Bryan Oakley Bryan Oakley - 8 months ago 35
JSON Question

why does powershell give different result in one-liner than two-liner when converting JSON?

Overview



From a powershell 3 prompt,, I want to call a RESTful service, get some JSON, and pretty-print it. I discovered that if I convert the data to a powershell object, and then convert the powershell object back to json, I get back a nice pretty-printed string. However, if I combine the two conversions into a one-liner with a pipe I will get a different result.

TL;DR: this:

PS> $psobj = $orig | ConvertFrom-JSON
PS> $psobj | ConvertTo-JSON


... gives me different result than this:

PS> $orig | ConvertFrom-JSON | ConvertTo-JSON


Original data



[
{
"Type": "1",
"Name": "QA"
},
{
"Type": "2",
"Name": "whatver"
}
]


Doing the conversion in two steps



I'm going to remove the whitespace (so it fits on one line...), convert it to a powershell object, and then convert it back to JSON. This works well, and gives me back the correct data:

PS> $orig = '[{"Type": "1","Name": "QA"},{"Type": "2","Name": "DEV"}]'
PS> $psobj = $orig | ConvertFrom-JSON
PS> $psobj | ConvertTo-JSON
[
{
"Type": "1",
"Name": "QA"
},
{
"Type": "2",
"Name": "DEV"
}
]


Combining the two steps with a pipe



However, if I combine those last two statements into a one-liner, I get a different result:

PS> $orig | ConvertFrom-JSON | ConvertTo-JSON
{
"value": [
{
"Type": "1",
"Name": "QA"
},
{
"Type": "2",
"Name": "DEV"
}
],
"Count": 2
}


Notice the addition of the keys "value" and "Count". Why is there a difference? I'm sure it has something to do with the desire to return JSON object rather than a JSON array, but I don't understand why the way I do the conversion affects the end result.

Answer

The solution is to wrap the first two operations with parenthesis:

PS C:\> ($orig | ConvertFrom-JSON) | ConvertTo-JSON
[
    {
        "Type":  "1",
        "Name":  "QA"
    },
    {
        "Type":  "2",
        "Name":  "DEV"
    }
]

The parenthesis allow you to grab the output of the first two operations all at once. Without them, powershell will attempt to parse any objects its gets separately. The collection of PSCustomObject resulting from $orig | ConvertFrom-JSON contains two PSCustomObjects for the 1/QA and 2/DEV pairs, so by piping the output of that collection powershell attempts to handle the key/value pairs one-at-a-time.

Using parenthesis is a shorter way of "grouping" that output and allows you to operate on it without making a variable.