PowerShell by default enumerates (unrolls) collections[1] when outputting them to the pipeline: that is, instead of outputting the collection itself, its elements are output, one by one.
PowerShell collects all output objects from a pipeline in a flat array (of type [object[]]
, i.e. an array whose elements can be of any type (System.Object
)), if two or more objects are output (a single object is collected as itself).
Therefore, even outputting multiple arrays creates a single, flat output array by default, which is the concatenation of these arrays.
A simpler example:
# Output 2 2-element arrays.
PS> 1..2 | % { @(1, 2) } | Measure-Object | % Count
4 # i.e., @(1, 2, 1, 2).Count
In order to produce nested arrays, you must suppress enumeration, which can be achieved in two ways:
- Simplest option: Wrap the output array in an auxiliary, transient single-element array so that when PowerShell enumerates the aux. array its one and only element - the original array - is output as a whole, as a single object. This can be achieved with the unary form of
,
the array-constructor ("comma") operator:
# Use unary , to wrap the RHS in a transient single-element array,
# which ensures that @(1, 2) is output *as a whole*.
PS> 1..2 | % { , @(1, 2) } | Measure-Object | % Count
2 # i.e., @(@(1, 2), @(1, 2)).Count
- Alternative, using
Write-Output -NoEnumerate
(PSv4+; this is slower, but conceptually more explicit):
PS> 1..2 | % { Write-Output -NoEnumerate @(1, 2) } | Measure-Object | % Count
2 # i.e., @(@(1, 2), @(1, 2)).Count
Note:
- While use of
@(...)
is not strictly necessary to create array literals (as used above) - for literals, separating elements with ,
is sufficient[2] - you still need @(...)
to ensure that output from enclosed expressions or commands is treated as an array, in case only a single object happens to be output.
[1] Specifically, types that implement the System.Collections.IEnumerable
interface or its generic counterpart are enumerated, but there are a few exceptions, notably strings and dictionaries. See the bottom section of this answer for details.
[2] E.g., 1, 2
creates a two-element array. In the case of nesting such an array via unary ,
, you do need an enclosure, however, to clarify precedence, for which the general-purpose (...)
(grouping operator) would suffice: , (1, 2)
- though you may prefer , @(1, 2)
for conceptual clarity.