Powershell: ConvertFrom-Json and ConvertTo-Json eat the one object array

Created on 10 Oct 2016  路  6Comments  路  Source: PowerShell/PowerShell

OS info

Edition: Windows 10 Enterprise
Version: 1607
OS Build: 14393.187
Installed RAM: 16.0 GB
System Type: 64-bit operating system, x64-based processor

Steps to reproduce

  1. Create a .json file. Write in an array with only one valid json object:
[{
    "name": "Animals",
    "age": "1",
    "children": [{
        "name": "mimi",
        "age": "1",
        "lovely": true,
        "height": 20
    },
    {
        "name": "dog",
        "age": "2",
        "lovely": false,
        "height": 100
    }]
}]
  1. Convert this json file content to psobject and then convert it back to write it to another file
$o=(Get-Content -Raw D:\Test_Convert.json | ConvertFrom-Json)
Set-Content 'D:\result.json' ($o | ConvertTo-Json)
  1. View the result.json:
{
    "name":  "Animals",
    "age":  "1",
    "children":  [
                     {
                         "name":  "mimi",
                         "age":  "1",
                         "lovely":  true,
                         "height":  20
                     },
                     {
                         "name":  "dog",
                         "age":  "2",
                         "lovely":  false,
                         "height":  100
                     }
                 ]
}

Expected behavior

Get the right PSObject and write the same content back.

Actual behavior

The array turns into its only child.

Environment data

Included in the repro steps.

Powershell Version

PS C:\Users\qisun\Downloads\LatestPowerShell> $PSVersionTable.PSVersion

Major Minor Patch Label
----- ----- ----- -----
    6     0     0 alpha

Have to mention that the issue does not repro when there are multiple children in that array.

Area-Cmdlets Resolution-By Design

Most helpful comment

With the repro as is, it does look like it is by design - we enumerate objects written to the pipeline, so piping loses the fact that the object was an array. This is similar to the difference between:

$o = @(1)
$o | Get-Member
Get-Member -InputObject $o

I was going to suggest using:

Set-Content 'D:\result.json' (ConvertTo-Json -InputObject $o)

But this doesn't work either, and I would consider this a bug.

All 6 comments

@Francisco-Gamino I think you had brought this up before and this was "by design"?

With the repro as is, it does look like it is by design - we enumerate objects written to the pipeline, so piping loses the fact that the object was an array. This is similar to the difference between:

$o = @(1)
$o | Get-Member
Get-Member -InputObject $o

I was going to suggest using:

Set-Content 'D:\result.json' (ConvertTo-Json -InputObject $o)

But this doesn't work either, and I would consider this a bug.

Just ran into this the other day, the workaround I'm using is

Set-Content 'D:\result.json' (ConvertTo-Json -InputObject @($o))

The fact that it still won't work in pipeline is annoying. I have a restriction that I have to use pipeline, so I end up doing:

 .\Some-Script.ps1 -OutVariable List | Out-Null; ConvertTo-Json -InputObject @($List)

And that works. I'm restricted because in this context, the script reference must be first and all other arguments are appended afterwards. I almost want a -AsArray switch or something to ConvertTo-Json.

.\Some-Script.ps1 | ConvertTo-Json -AsArray

The pipleline issue is by design; however, this is not documented, so I've create an doc issue for this: https://github.com/PowerShell/PowerShell-Docs/issues/1219

For the ConvertTo-Json -InputObject $array, I cannot get it to repro. Here is what I am running:

# Generate a test file with Json content
'[{
    "name": "Animals",
    "age": "1",
    "children": [{
        "name": "mimi",
        "age": "1",
        "lovely": true,
        "height": 20
    },
    {
        "name": "dog",
        "age": "2",
        "lovely": false,
        "height": 100
    }]
}]'  | Out-File Test_Convert.json

# Create the test object from the Json file
$o=(Get-Content -Raw Test_Convert.json | ConvertFrom-Json)
$o

name    age children
----    --- --------
Animals 1   {@{name=mimi; age=1; lovely=True; height=20}, @{name=dog; age=2; lovely=False; height=100}}

# Serialize the object using  ConvertTo-Json -InputObject
Set-Content result.json (ConvertTo-Json -InputObject $o -Depth 3)

Get-Content .\result.json
[
  {
    "name": "Animals",
    "age": "1",
    "children": [
      {
        "name": "mimi",
        "age": "1",
        "lovely": true,
        "height": 20
      },
      {
        "name": "dog",
        "age": "2",
        "lovely": false,
        "height": 100
      }
    ]
  }
]

Since the pipleline issue is by design, I am closing this. Please reopen is ConvertTo-Json -InputObject $array does not work.

In my case this approach adds "value": at the beggining and "Count": 1 at the end:

{
"value": [
{
"name": "Animals",
"age": "1",
"children": [
{
"name": "mimi",
"age": "1",
"lovely": true,
"height": 20
},
{
"name": "dog",
"age": "2",
"lovely": false,
"height": 100
}
]
}
],
"Count": 1
}

Does this support complex json files .

Referring to the Azure ARM templates which are in the json format .

Does it support that too ?

Was this page helpful?
0 / 5 - 0 ratings