Recently, I\'ve been playing with PowerShell, and I\'ve noticed some weird behavior when using pipes and foreach
loops that I couldn\'t understand.
This
The foreach
statement doesn't use the pipeline architecture, so its output cannot be passed to a pipeline directly (i.e. item by item). To be able to pass output from a foreach
loop to a pipeline you must run the loop in a subexpression:
$(foreach ($item in Get-ChildItem) { $item.Length }) | ...
or collect it in a variable first:
$len = foreach ($item in Get-ChildItem) { ... }
$len | ...
If you want to process data in a pipeline use the ForEach-Object
cmdlet instead:
Get-ChildItem | ForEach-Object { $_.Length } | ...
For further explanation of the differences between foreach
statement and ForEach-Object
cmdlet see the Scripting Guy blog and the chapter on loops from Master-PowerShell.
You need to evaluate the foreach
before piping the resulting Object like you did in the first test:
$(foreach ($i in gci){$i.length}) | measure -max
Alternatively, use the %
shorthand to which will evaluate it before piping it as well:
gci | % { $_.Length } | measure -max