I am trying to construct a complex powershell object containing nested hashtables and arrays, and then using the ConvertTo-Json function to convert the whole lot into Json.
I am experiencing a problem where - if an array object has only a single element, the Json that is returned is not returned as an array but as a single object. That is to say, it is missing the enclosing square brackets in the json.
Here is some sample code that demonstrates the problem:
function GetMyArrayData
{
param($myData)
$myArrayOfInfo = $myData -split '\s*[,;]\s*'
$myReturnArray = @()
foreach($infoItem in $myArrayOfInfo)
{
$hashObj = @{
field1 = "standard-value"
field2 = $infoItem
}
$myReturnArray = $hashObj
}
return $myReturnArray
}
$myFirstArray = GetMyArrayData -myData "abc;def"
$mySecondArray = GetMyArrayData -myData "xyz"
$myBigObject = @{
item1 = "my-first-item"
item2 = "my-second-item"
myArray1 = $myFirstArray
myArray2 = $mySecondArray
}
$myJsonVersion = ConvertTo-Json $myBigObject -Depth 5
Write-Output $myJsonVersion
This code then outputs the following JSON:
{
"item2": "my-second-item",
"myArray1": [
{
"field1": "standard-value",
"field2": "abc"
},
{
"field1": "standard-value",
"field2": "def"
}
],
"myArray2": {
"field1": "standard-value",
"field2": "xyz"
},
"item1": "my-first-item"
}
Notice that "myArray2" is converted to a single object, rather than an array containing a single object.
It should be rendered thus:
{
"item2": "my-second-item",
"myArray1": [
{
"field1": "standard-value",
"field2": "abc"
},
{
"field1": "standard-value",
"field2": "def"
}
],
"myArray2": [
{
"field1": "standard-value",
"field2": "xyz"
}
],
"item1": "my-first-item"
}
Can anyone advise what is wrong with this code that prevents it from outputting myArray2 as an array containing a single object?
Thanks heaps,
David :-)
CodePudding user response:
When you return arrays and collections from a function PwerShell will “unroll” them. If the array contains a single object, it will return that object rather than an array.
You can work around this in a couple of ways - inside your function you can do this:
return @(, $myReturnArray )
which wraps your return value in an outer array - Powershell will then unroll that rather than your inner array, so your single item array is returned intact, or you can do this:
$myFirstArray = @( GetMyArrayData -myData "abc;def" )
which wraps the return value in a new array. If the return value is already an array it basically creates a shallow copy, but if it’s a single object it will be bundled onto an array.
CodePudding user response:
In this case, you can use the @() array subexpression operator or the unary comma operator to force the variable into an array:
myArray1 = @($myFirstArray)
myArray2 = @($mySecondArray)
or
myArray1 = ,$myFirstArray
myArray2 = ,$mySecondArray
Note that you still will lose the []
if you pipe the $MyBigObject
through to the ConvertTo-Json cmdlet. Using -InputObject
(as you implicitely do) is the correct way here.