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