Change JSON property to an array if not an array powershell

359 views Asked by At

I have a JSON that I want to check if it is an array, if not, I want to update the JSON and change it to an array

{
    "Customer": [{
        "id": "123"
    }],
 "address": {
    "type": "home",
    "name": "what",
    "description": "",
    "adi:water": {
      "type": "comp",
      "location": "grass"
    },
    "att": [
      {
        "name": "cat",
        "type": "int"
      },
      {
        "name": "ds",
        "type": "string"
      }
    ]
  }
}

#For example address is not an array, I want to change so address is an array of one single object

Code so far

$File = ((Get-Content -Encoding UTF8 -path Test.json -Raw)

$File = $File| ConvertFrom-Json
$File.address = $File.address | Select-Object * -ExcludeProperty streets #This line changes it to an object instead of an array

I want the address to be an array. Can I do that in powershell?

1

There are 1 answers

0
mklement0 On BEST ANSWER

Use ForEach-Object and reassign the address property value by enclosing it in @(...), the array-subexpression operator, to ensure that it is an array (if it already is an array, nothing changes[1]):

@'
{
  "Customer": [
      {
          "id": "123"
      }
  ],
  "address": {
      "type": "home",
      "name": "what",
      "description": "",
      "adi:water": {
          "type": "comp",
          "location": "grass"
      },
      "att": [
          {
              "name": "cat",
              "type": "int"
          },
          {
              "name": "ds",
              "type": "string"
          }
      ]
  }
}
'@ | ConvertFrom-Json | 
  ForEach-Object { 
    $_.address = @($_.address | Select-Object * -ExcludeProperty streets)
    $_ 
  } |
    ConvertTo-Json -Depth 4

Note the stand-alone $_ statement after the assignment: it ensures that (modified) input object is also output (to the next pipeline segment), using PowerShell's implicit output feature - see this answer.

Note: ConvertTo-Json limits the serialization depth to 2 by default, hence -Depth 4 was used above to prevent data loss. In general, keep in mind that you may have to pass a -Depth argument to ConvertTo-Json prevent data loss - see this post.[2]

The above yields the following, showing that the address property is now an array:

{
  "Customer": [
    {
      "id": "123"
    }
  ],
  "address": [
    {
      "type": "home",
      "name": "what",
      "description": "",
      "adi:water": {
        "type": "comp",
        "location": "grass"
      },
      "att": [
        {
          "name": "cat",
          "type": "int"
        },
        {
          "name": "ds",
          "type": "string"
        }
      ]
    }
  ]
}

[1] Technically, a (shallow) copy of an existing array is created, but that doesn't make any difference here.
To learn more about the @() operator, see this answer.

[2] This requirement is cumbersome and easy to miss, but hasn't been changed for the sake of backward compatibility. However, PowerShell version 7.1 will at least emit a warning when the (possibly default) -Depth value is insufficient: see this PR and the associated discussion in GitHub issue #8393.
Also, the issue may be revisited in the context of moving the implementation of the JSON cmdlets from the Newtonsoft.Json library to the new(ish) built-in System.Text.Json API, at some point after v7.1, which will inevitably entail breaking changes - see this PR.