I'd like to formally request that people stop referring to the ForEach-Object cmdlet as a foreach loop, and that they explicitly use ForEach-Object by name and stop using the foreach alias in published examples. There are a lot of users searching for help on foreach, and this is easily one of the most confusing cmdlets/statements in PowerShell due to the name overlap. Blurring the line between ForEach-Object and foreach is contributing to increasing the learning curve required when working with PowerShell. I see this in searches that lead to my blog on a regular basis. The two articles I have written about foreach are the most popular articles by far.
ForEach-Object is not a loop statement. You cannot use the break statement to get out of it (it will actually break out of the loop that contains the ForEach-Object statement, or the entire script will terminate if there is no external loop statement), nor can you use the continue statement to stop processing the current iteration and continue to the next (continue will also continue the loop that contains the ForEach-Object statement, or the entire script will terminate if there is no external loop statement). The documentation in about_foreach is wrong! You cannot use the foreach statement inside of a pipeline (*unless it is used within a script that is a parameter of a cmdlet like Where-Object or ForEach-Object), despite what the section titled "The Foreach Statement Inside of a Command Pipeline" implies. You can use the ForEach-Object cmdlet inside of the command pipeline, which is not the foreach statement, and while it functions in a similar manner (only in that it processes a set of objects iteratively) the two are not equivalent nor should they be treated as equivalent.
You can read more about the differences between these the ForEach-Object cmdlet and the foreach statement on my blog. The first article, Essential PowerShell: Understanding foreach, can be found here:
http://poshoholic.com/2007/08/21/essential-powershell-understanding-foreach/">http://poshoholic.com/2007/08/21/essential-powershell-understanding-foreach/
The follow-up article to that post, Essential PowerShell: Understanding foreach (Addendum), can be found here:
http://poshoholic.com/2007/08/31/essential-powershell-understanding-foreach-addendum/">http://poshoholic.com/2007/08/31/essential-powershell-understanding-foreach-addendum/
If you're working with foreach and ForEach-Object, please make sure you understand the differences between these the cmdlet and the statement.
Also, as Dmitry Sotnikov points out (http://dmitrysotnikov.wordpress.com/2007/10/02/bug-in-exchange-cmdlets/), something funny is going on here if what is written above is actually true. I agree with Dmitry on this. If pipelining the results of the first cmdlet into the ForEach-Object cmdlet (not the foreach loop statement!) results in the objects coming through the pipeline one at a time while not using the ForEach-Object results in the entire set being collected before anything is passed down the pipeline then something is definitely wrong here. At least according to PowerShell documentation. If you look at section 2.3.1 of "PowerShell in Action" by Bruce Payette, one of the creators of PowerShell (if you love PowerShell, buy this book!) in the last paragraph on page 46 he describes how pipelining cmdlets results in objects being passed from one cmdlet to another as soon as those objects are emitted from a given stage in the pipeline. Since that is the case, you shouldn't actually need to use the ForEach-Object cmdlet here to make the entire one-liner execute more quickly. ForEach-Object allows you to execute multiple lines of PowerShell script in the middle of a pipeline. It also allows you to pass the results from one stage in a pipeline to parameters of a cmdlet in another stage even if those parameters were not configured to accept input from the pipeline. It does a whole bunch of other things as well, but my point is, according to the description of PowerShell's streaming behaviour in pipeline execution, what this article states is actually incorrect. That is, unless the Exchange cmdlets that are described here don't function the way other cmdlets do in a pipeline.
Please respond to this. There is a lot of confusion generated by this blog entry!
Thanks for listening!
Kirk out.
http://poshoholic.com