Search code examples
powershellpowershell-7

ConvertFrom-Json unpacks arrays with 1 item and behaves oddly with empty object


I am trying to figure out how to stop ConvertFrom-Json from unpacking array types if they have one or zero items.

I have read these related posts: ConvertTo-JSON an array with a single item How to prevent ConvertFrom-Json from collapsing nested arrays if there's 1 element

After reading these, I don't think I am experiencing the member access enumeration because I am not using the access operator.

I attempted to use ConvertFrom-Json without the use of pipelining but that didn't fix the issue as it did for someone using ConvertTo-Json

Here is a simple example with output:

$x = '[{"a": 1, "b": 2}]'
$y = ConvertFrom-Json -InputObject $x

$a = '[]'
$b = ConvertFrom-Json -InputObject $a

Write-Host $y -ForegroundColor Green
Write-Host $y.GetType() -ForegroundColor Green

Write-Host $b -ForegroundColor Green
Write-Host $b.GetType() -ForegroundColor Green
@{a=1; b=2} # first object in array, not array
System.Management.Automation.PSCustomObject # treats as object instead of array
# nothing was printed here because b is null
InvalidOperation: C:\Users\username\Test.ps1:11:1 # error from trying to print the type of b
Line |
  11 |  Write-Host $b.GetType() -ForegroundColor Green
     |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | You cannot call a method on a null-valued expression.

The kind of output I expected was the GetType() calls to return System.Object[]

Additional Context:

I am using the github cli to get lists of PRs for different repos and aggregate some data for some internal workflows. Obviously it is possible for a repo to have 0, 1 or more PRs and I am hoping to avoid any special logic for the 0 or 1 case, as an empty array or array with one item can follow the same code path as an array with many items.


Solution

  • The behavior you're seeing implies that you're using PowerShell (Core) 7+ rather than Windows PowerShell.

    While your command happens to work in Windows PowerShell, it relies on behavior that contravenes the usual pipeline behavior, i.e. enumerating arrays - see the (now closed) GitHub issue #3424 for background information.

    It is for this reason that in PowerShell 7+ ConvertFrom-Json now enumerates the elements of a parsed-from-JSON array by default, and requires opt-in in order to request that a such an array be output as a single object, using the -NoEnumerate switch:

    $x = '[{"a": 1, "b": 2}]'
    
    # Note the -NoEnumerate switch (v7+)
    $y = ConvertFrom-Json -NoEnumerate -InputObject $x
    
    $y.GetType().Name # -> 'Object[]', proving that the array was preserved.