I just figured this out late last night. I was pulling my hair out. If you look at the following PowerShell code
($MyArray=1,2,3,4,5) | foreach-object { write-host $_ if ($_ -eq 3 ){return} }
You get a result of:
1
2
3
4
5
Next, if you look at this code (the only real difference being the lack of a pipe.)
foreach ($item in ($MyArray=1,2,3,4,5)) { write-host $item if ($item -eq 3 ){return} }
You get:
1
2
3
That stumped me. Why would they not produce the same thing? Then I ran across this thread. The replier said
I think because ForEach-Object processes each item in the pipeline, but the foreach statement processes the collection as a whole.
This led me to this page, and specifically this quote clears it up for me (kinda):
. . . [the object] it is sent into the pipeline and execution continues in the next section of the pipeline. . . . the foreach alias gets executed and the object is run through the process script block of ForEach-Object. Once the process script block completes, the object is discarded and the next object is [sent] . . .
In summary, last night I learned that when using a pipeline, the first item is passed to the script block, the script block is run, and then the next item is passed to the script block, and so on.
That sound correct? Can you come up with a better description?
This is called, “lazy evaluation.” By using foreach, you’re deferring processing of each building block until such a time as it’s required.
The type of operations that force the hand of execution are: sorting, counting, min/max, etc. These operations require knowledge of the entire set. That implies — with intention — that for a large part, piped processing doesn’t know what’s in the set until it hits a point where it needs to.