ConvertTo-JSON an array with a single item
Asked Answered
S

10

78

I'm trying to create a JSON-serialized array. When that array contains only one item I get a string, not an array of strings (in JSON).

Multiple Items (works as expected):

PS C:\> @("one", "two") | ConvertTo-JSON
[
    "one",
    "two"
]

Single Item Array (not as expected):

PS C:\> @("one") | ConvertTo-JSON
"one"

Am I missing something?

Subtorrid answered 6/9, 2013 at 17:5 Comment(1)
Place a , in front of @: ,@("one") | ConvertTo-Json: [ "one" ]Photojournalism
J
121

Try without the pipeline:

PS C:\> ConvertTo-Json @('one', 'two')
[
    "one",
    "two"
]
PS C:\> ConvertTo-Json @('one')
[
    "one"
]
Jagged answered 6/9, 2013 at 17:56 Comment(6)
Ahh yea. I see how using the pipeline would be ambiguous in this case. Thank you. You made me realize that it's not ConvertTo-JSON specific but a general powershell-array-pipline issue which lead me to: superuser.com/questions/414650/…Subtorrid
@Subtorrid If only there was sanity: @(@(1)) | ConvertTo-Json -- still "NOPE"Woodie
Actually the pipeline approach was wrong in the first place, arrays are always iterated when passed to the pipeline. Just luckily the behavior of ConvertTo-Json is to collect all pipeline input in an array and output a single object, otherwise the result would have been 2 JSON objects, both a single string.Kayser
@Kayser no that's just plain wrong, pipelines are a fantastic alternative to the reverse data-direction of the nested, arguments-based function-call paradigm. Bare lists are iterated in a pipeline, yes, but such a list can contain items of any object, including arrays. How else would this work to get the length of each strings' second word? 'hello there','it is i' | %{ ,@($_ -split ' ') } | %{ $_[1].Length }. We can likewise do this for ConvertTo like so; ,@(1) | ConvertTo-Json. ConvertTo craps itself, it's not operating correctly.Piecrust
@Piecrust My wording might have been unfortunate. Any collection type (e.g. an array) is iterated when passed to the start of the pipeline. Of course, that only applies to the first level, as the elements and sub elements can be collection types itself. That's exactly what you demonstrated in your example, you pass in an array of strings and the split is performed on each single element.Kayser
Yeah, so as you can see you can feed ConvertTo-Json an array, but it still wont serialise it properly. It outputs {values:1, count:1}, there's something wrong with it, not pipelining (its so much the wording, but the apparent response to user2864740)Piecrust
P
31

I hit this problem as well but it was because my structure was too deep and ConvertTo-Json flattens everything below a certain depth to a string.

For example:

PS C:\> $MyObject = @{ "a" = @{ "b" = @{ "c" = @("d") } } }
PS C:\> ConvertTo-Json $MyObject
{
    "a":  {
              "b":  {
                        "c":  "d"
                    }
          }
}

To fix this, you can pass a larger value to -Depth

PS C:\> ConvertTo-Json $MyObject -Depth 100
{
    "a":  {
              "b":  {
                        "c":  [
                                  "d"
                              ]
                    }
          }
}
Pelpel answered 20/4, 2017 at 23:26 Comment(0)
W
10

I just had the same issue and found out, that you can just append an -AsArray to the ConvertTo-Json command. Examples:

❯ @("one") | ConvertTo-Json -AsArray       
[
  "one"
]
❯ @("one", "two") | Convert-ToJson -AsArray
[
  "one",
  "two"
]
Waterfall answered 9/8, 2021 at 10:23 Comment(3)
That sounds like a useful switch but it doesn't exist for me. What version of PowerShell are you using? I'm on 5.1.19041.1320Clearwing
The -AsArray parameter is new in PowerShell 7.x, where this should be the recommended solution.Atomy
-AsArray outputs the root object as an array regardless of there being one or multiple objects. It does not do anything for nested arrays.Jaclin
P
9

Place a , in front of @:

,@("one") | ConvertTo-Json
[
  "one"
]
Photojournalism answered 10/2, 2022 at 18:13 Comment(2)
This works in many other situationsCayla
This should be considered as the right answer. The other ones are, at best, workarounds.Gardie
L
4

Faced the same issue today. Just to add, if you have an object like this

@{ op="replace"; path="clientName"; value="foo"}

then you have to specify it as

ConvertTo-Json @( @{ op="replace"; path="clientName"; value="foo"} )

The double @s can become confusing sometimes.

Latin answered 2/7, 2018 at 9:56 Comment(0)
T
4

I faced this issue with an array that was a child in an object. The array had one object in it, and ConvertTo-Json was removing the object in the array.

Two things to resolve this:

I had to set the -Depth parameter on ConvertTo-Json

$output = $body | ConvertTo-Json -Depth 10

I had to create the object in the array as a hashtable and then convert that to an object

$myArray.Add([pscustomobject]@{prop1 = ""; prop2 = "" })
Tipstaff answered 26/2, 2020 at 21:16 Comment(0)
W
1

Thats not a good idea to keep it 5.1 and 7.x aware: 7.x does as you say, but 5.1 does this:

    {
    "value":  [
    "one"
              ],
    "Count":  1
}
Wanitawanneeickel answered 10/2, 2023 at 17:47 Comment(0)
W
1

In my case, the prepared list was an array returned from a function. This was a simple array of strings. I had to re-wrap the array in @($ReturnedObject) before it would work.

ConvertTo-Json @($ReturnObject)

Weinstock answered 8/3, 2023 at 12:1 Comment(0)
G
0

This is an old question - but weirdly Powershell 7.x documentation has THIS tidbit. https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertfrom-json?view=powershell-7.3

-NoEnumerate Specifies that output isn't enumerated.

Setting this parameter causes arrays to be sent as a single object instead of sending every element separately. This guarantees that JSON can be round-tripped via ConvertTo-Json.

This causes ConvertFrom-Json to create an array regardless of content. Talk about mysterious...

Gayomart answered 26/8, 2023 at 17:52 Comment(0)
M
0

None of the solutions mentioned worked for me, because the issue is in the json file content in memory assignment operation;

I found these solutions not viable as they are not consistent, somehow the '-Depth 100' worked in some instances. The '-AsArray' parameter converts the entire memory loaded json file into an json array object.

I have many json files with single element arrays that continue to be converted from array objects to just objects.

I rewrote the json array object assignment to fix this issue. Snippet of my code below

hidden [bool] RunSort( [string] $redacted_data_key)
{
    $jsonNodes = $redacted_data_key -split '\.'
    if($this.content.$($jsonNodes[0]).$($jsonNodes[1]).$($jsonNodes[2]).Redacteds)
    {
        $this.content.$($jsonNodes[0]).$($jsonNodes[1]).$($jsonNodes[2]).Redacteds = @($($this.RedactedData[$redacted_data_key]) | Sort-Object);
        $this.SortData["RedactedsSorted"].Add($redacted_data_key)
        return $true
    }
    else
    {
        return $false
    }
}

...

 $this.content | ConvertTo-Json -depth 100 | Format-Json | Out-File  $this.SortData["FilePath"] -NoNewline -Encoding $this.jsonFileEncodingType

So in conclusion check your assignment operations. The problem is occurring there and is not caused by the powershell command 'ConvertTo-Json'. i rewrote my assignment operation within the @() powershell standard array variable brackets. This solved the issue for me

Montane answered 17/6 at 13:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.