What determines whether the Powershell pipeline will unroll a collection? What determines whether the Powershell pipeline will unroll a collection? powershell powershell

What determines whether the Powershell pipeline will unroll a collection?


$args is unrolled. Remember that function parameters are normally passed using space to separate them. When you pass in 1,2,3 you are passing in a single argument that is an array of three numbers that gets assigned to $args[0]:

PS> function UnrollMe { $args }PS> UnrollMe 1 2 3 | measureCount    : 3

Putting the results (an array) within a grouping expression (or subexpression e.g. $()) makes it eligible again for unrolling so the following unrolls the object[] containing 1,2,3 returned by UnrollMe:

PS> ((UnrollMe 1,2,3) | measure).Count3

which is equivalent to:

PS> ((1,2,3) | measure).Count3

BTW it doesn't just apply to an array with one element.

PS> ((1,2),3) | %{$_.GetType().Name}Object[]Int32

Using an array subexpression (@()) on something that is already an array has no effect no matter how many times you apply it. :-) If you want to prevent unrolling use the comma operator because it will always create another outer array which gets unrolled. Note that in this scenario you don't really prevent unrolling, you just work around the unrolling by introducing an outer "wrapper" array that gets unrolled instead of your original array e.g.:

PS> (,(1,2,3) | measure).Count1

Finally, when you execute this:

PS> (UnrollMe a,b,c d) | %{$_.GetType().Name}Object[]String

You can see that UnrollMe returns two items (a,b,c) as an array and d as a scalar. Those two items get sent down the pipeline separately which is the resulting count is 2.


It seem to have something to do with how Measure-Object works and how objects are passed along the pipeline.

When you say

1,2,3 | measure

you get 3 Int32 objects passed onto the pipeline, measure object then counts each object it sees on the pipeline.

When you "unroll it" using your function, you get a single array object passed onto the pipeline which measure object counts as 1, it makes no attempt to iterate through the objects in the array, as shown here:

PS C:\> (measure -input 1,2,3).count1

A possible work-around is to "re-roll" the array onto the pipeline using foreach:

PS C:\> (UnrollMe 1,2,3 | %{$_} | measure).count3