Create a Single-Element Json Array Object Using PowerShell

I have a powershell 5.1 script that I've created that imports a csv file, manipulates some of the data, then converts the object of data to json format using the ConvertTo-Json cmdlet at the end of the script. The problem that I'm running into; in one of my fields I need to create a single array for the object property with brackets. So I need the object to be like:

"PersonGroups":[
              {
                "Name":"test Name",
                "Id": 3433
              }
            ]

Here is the call to the function:

 $_.PersonGroups = Set-DataHash -InputObject $_

Below is my code that I have:

function Set-DataHash{
param(
    [psobject] $InputObject
)

$customObject = [psobject]@{
   Name = "Test"
   Id = 78888
}

$customArray = @($customObject)

return $customArray

}

Of course if I have more than one object in the array it works fine; but since it's only one object ConvertTo-Json makes it a single object. Any suggestions on what to do?


How about:

 $_.PersonGroups = @(Set-DataHash -InputObject $_)

You don't need the "return".


js2010's helpful answer shows how to solve the problem on the caller's side, using @(), the array-subexpression operator, around your Set-DataHash function call to ensure that the return value is an array.

If you want to solve the problem from within your function, you must ensure that the array being output (returned) is output as a whole, as a single object, which can be achieved with an auxiliary single-element wrapper array created with (the unary form of) ,, the array constructor operator:

function Set-DataHash {
  param(
    [psobject] $InputObject
  )
  
  $customObject = [psobject] @{
    Name = "Test"
    Id   = 78888
  }
  
  # Wrap $customObject in an array with @(...), 
  # then *additionally* wrap this array in an *auxiliary* single-element array,
  # via `,` (array-construction operator).
  # Outputting this aux. array causes *it* to be enumerated, which therefore
  # outputs its only element as-is: the *original* array - see explanation below.
  # Note: I've omitted `return`, which is always optional.
  , @($customObject)
  
}

Explanation:

By default - irrespective of whether you use return or implicit output in a function or script - outputting a collection (including arrays) causes its elements to be enumerated (aka streamed, unwrapped or unrolled); that is, the elements are output one by one to the (invisible, in this case) pipeline through which the caller receives the output.

  • In the case of a single-element collection, the nature of the pipeline is such that the caller receives just that single element itself - the collection wrapper is lost.

  • In the case of a multi-element collection, the specific original collection is lost too, and the enumerated elements are automatically collected in an [object[]] array).

Therefore, wrapping a collection that you want to output as a whole, as a single object requires the aux. single-element wrapper array technique shown above; a less efficient alternative is to use Write-Output with the -NoEnumerate switch, which too prevents enumeration of a collection passed to it as an argument (not via the pipeline).


Note:

  • In general, in functions/scripts intended to be called directly by others, it is better not to output collections as a whole, so as not to confound the general expectation of streaming (enumerating) behavior in the pipeline; in the streaming case, it is the caller that must ensure that the collected output is an array, via @(...), as shown in js2010's answer; see this answer for background information.

  • Conversely, however, outputting collections as a whole is faster and allows you to output a specific collection type.