To add an explanation to Bill Stewart's effective solution:
Outputting a collection such as an array[1] either implicitly or using return
sends its elements individually through the pipeline; that is, the collection is enumerated (unrolled):
# Count objects received.
PS> (1..3 | Measure-Object).Count
3 # Array elements were sent *individually* through the pipeline.
Using the unary form of ,
(comma; the array-construction operator) to prevent enumeration is a conveniently concise, though somewhat obscure workaround:
PS> (, (1..3) | Measure-Object).Count
1 # By wrapping the array in a helper array, the original array was preserved.
That is, , <collection>
creates a transient single-element helper array around the original collection so that the enumeration is only applied to the helper array, outputting the enclosed original collection as-is, as a single object.
A conceptually clearer, but more verbose and slower approach is to use Write-Output -NoEnumerate
, which clearly signals the intent to output a collection as a single object.
PS> (Write-Output -NoEnumerate (1..3) | Measure-Object).Count
1 # Write-Output -NoEnumerate prevented enumeration.
Pitfall with respect to visual inspection:
On outputting for display, the boundaries between multiple arrays are seemingly erased again:
PS> (1..2), (3..4) # Output two arrays without enumeration
1
2
3
4
That is, even though two 2-element arrays were each sent as a single object each, the output, through showing elements each on their own line, makes it look like a flat 4-element array was received.
A simple way around that is to stringify each array, which turns each array into a string containing a space-separated list of its elements.
PS> (1..2), (3..4) | ForEach-Object { "$_" }
1 2
3 4
Now it is obvious that two separate arrays were received.
[1] What data types are enumerated:
Instances of data types that implement the IEnumerable
interface are automatically enumerated, but there are exceptions:
Types that also implement IDictionary
, such as hashtables, are not enumerated, and neither are XmlNode
instances.
Conversely, instances of DataTable
(which doesn't implement IEnumerable
) are enumerated (as the elements of their .Rows
collection) - see this answer and the source code.
Additionally, note that stdout output from external program is enumerated line by line.