3

The file minimal.json contains:

{
    "data":  {
                 "labels":  [
                                "GERMAN AMERICAN BANK",
                                "JOHNSON BANK",
                                "WASHINGTON TRUST BANK"
                            ],
                 "datasets":  [
                                  {
                                      "data":  [
                                                   {
                                                       "y":  43.84,
                                                       "x":  51
                                                   },
                                                   {
                                                       "y":  47.02,
                                                       "x":  12
                                                   },
                                                   {
                                                       "y":  58.21,
                                                       "x":  53
                                                   }
                                               ],
                                      "label":  "data"
                                  }
                              ]
             },
    "options":  {
                    "title":  {
                                  "text":  "Banks",
                                  "display":  true
                              },
                    "scales":  {

                               },
                    "plugins":  {
                                    "datalabels":  {
                                                       "formatter": function(value, context) { var idx = context.dataIndex; return context.chart.data.labels[idx]; },
                                                       "display":  true
                                                   }
                                }
                },
    "type":  "scatter"
}

If I execute the following at a console:

@{ chart = Get-Content C:\temp\minimal.json -Raw } | ConvertTo-Json -Depth 100

The console appears to hang. It is unresponsive to C-c.

Is this a bug in ConvertTo-Json?

Any suggestions on how to get this example to work?

dharmatech
  • 8,979
  • 8
  • 42
  • 88

2 Answers2

3

tl;dr

  • Your problem is specific to Windows PowerShell (it no longer affects PowerShell (Core) 7+).

  • A solution that works in both editions is to cast the Get-Content -Raw … call to [string]:

@{ chart = [string] (Get-Content C:\temp\minimal.json -Raw) } | 
  ConvertTo-Json -Depth 100

Note: -Depth 100 is not required in this case, because the default depth, 2, is sufficient to serialize your input hashtable (the content of the chart entry value, due to being a string, is irrelevant with respect to the recursion depth - leaving the undesired Windows PowerShell behavior discussed below aside).
However, in general it's worth paying attention to whether a -Depth argument is needed - see this post.


Background information:
  • Get-Content, in both PowerShell editions, decorates its [string] output objects with ETS (Extended Type System) properties.

    • These properties are: PSChildName, PSDrive, PSParentPath, PSPath, PSProvider, and ReadCount, and you can discover them with Get-Content C:\temp\minimal.json -Raw | Get-Member -Type NoteProperty).
  • In Windows PowerShell only, these properties are included when these output objects are serialized via ConvertTo-Json.[1]

    • Serializing arbitrary .NET objects with -Depth 100 can result in excessive amounts of data getting serialized and even potentially infinite loops, depending on the nature of the object - this is what you saw, due to the ETS properties being included in the serialization.

    • Casting the Get-Content -Raw … call to [string] implicitly discards the ETS properties, resulting in an undecorated [string] instance that serializes as just its text, and thereby bypasses the problem.


[1] PR #15665, which took effect in PowerShell (Core) 7.2., now intentionally excludes ETS properties of types [string] and [datetime], specifically.

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

This appears to be a workaround:

$minimal = Get-Content c:\temp\minimal.json -raw

$literal = @"
$minimal
"@


$json = @{ 
    
    chart = $literal

} | ConvertTo-Json -Depth 100
dharmatech
  • 8,979
  • 8
  • 42
  • 88
  • 1
    This works, because in effect it creates a new, _undecorated_ `[string]` instance. However, a simple `[string]` cast is sufficient. – mklement0 Mar 29 '23 at 02:08