Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the Foreach-Object cmdlet in Part 2 of the Looping Week series.
Microsoft Scripting Guy, Ed Wilson, is here. Today I want to address a major point of confusion for newbie Windows PowerShell scripters. That point is the Foreach-Object cmdlet. Part of the confusion comes with the alias, Foreach, which is the same as the command name, Foreach.
But that is only part of the confusion. For people trying to come to grips with looping through a collection, adding the Foreach-Object cmdlet into the mixture is just asking for trouble. Or asking for help. And that is what I am going to provide today; I'll attempt to demystify part of the equation.
Note This is Part 2 of a four-part series about looping. In Part 1, Basics of PowerShell Looping: Foreach, I looked at the Foreach statement and talked about the problem of collections, arrays, and accessing specific items. Today, I am going to talk about using the Foreach-Object cmdlet to work with individual items from a collection.
I want to go back to the array that I created yesterday. I store three values in three different variables. I then stored those three variables into the $d variable as shown here:
PS C:\> $a = 5
PS C:\> $b = 6
PS C:\> $c = 7
PS C:\> $d = $a, $b, $c
PS C:\> $d
5
6
7
PS C:\>
Yesterday, I used the Foreach command to add five to each of the items stored in the array. I can do the same thing by using the pipeline. In fact, it will be easier to write and work with. The key point is that the $_ variable represents the current item in the pipeline. I can then work with $_ in the same way that I worked with the $i variable yesterday in the Foreach statement.
It might be a bit easier to show the script. I take the $d variable (which contains the three values), and I send it down the pipeline to the Foreach-Object cmdlet. Inside the script block (curly braces), I use the $_ automatic variable, and I add the number 5 to each item that comes across. This script is shown here:
PS C:\> $d | ForEach-Object { $_ + 5 }
10
11
12
PS C:\>
The command and the Windows PowerShell console are shown in the following image.
There are a number of advantages to using the Foreach-Object cmdlet as opposed to the Foreach statement. The first is that I do not have to create an enumerator variable, and I can leave out the parenthesis portion of the code block.
The second advantage is that I have a number of aliases for the Foreach-Object cmdlet. The shortest one is the % symbol. If I look at this symbol just right, I can see an o, and a |, and another o. This illustrates a value crossing the pipeline—at least this is the way I remember it. So my previous script becomes:
PS C:\> $d | % { $_ + 5 }
10
11
12
Another thing that is cool is that I do not need the $d variable at all. I can pipe my array of variables directly to the Foreach-Object cmdlet. This technique is shown here:
PS C:\> $a,$b,$c | ForEach-Object { $_ + 5 }
10
11
12
PS C:\>
In addition, tab expansion works with the Foreach-Object cmdlet, so I do not have to type out Foreach-Object each time I want to use it. I just type a few letters, hit the Tab key, and the cmdlet name expands. Or I can use the % symbol (which is what I use when I work interactively from the Windows PowerShell console).
One of the things that I like to do when using the Foreach-Object cmdlet with the pipeline, is to send the results to another Windows PowerShell cmdlet, such as the Sort-Object cmdlet. This makes for some really powerful script, and it is easy to work out.
For example, I have three values stored in three variables: $e, $f, and $g. This is shown here:
PS C:\> $e = 15
PS C:\> $f = 9
PS C:\> $g = 17
Notice that the values are not in order—not in any sort of order at all. I want to add two to each of the values, and then I want to sort the list. To do this, I pipe the array of three variables to the Foreach-Object cmdlet. Inside the script block, I add two, and then I pipe the results to the Sort-Object cmdlet. I sort on the same $_ automatic variable, and then I choose the –Descending switch. This script is shown here:
PS C:\> $e, $f, $g | % { $_ + 2 } | sort $_ -Descending
19
17
11
The command and the output are shown in the following image:
The neat thing is that by using the Foreach-Object cmdlet, it is so easy to work with collections that I do not have to write any script. Notice that today I did not bother to open the Windows PowerShell ISE. With the Foreach language statement, I generally feel compelled to open the Windows PowerShell ISE…it just seems like the thing to do. But with the Foreach-Object statement, I don’t need to do so at all.
That is all there is to using the Foreach-Object cmdlet. Looping Week will continue tomorrow when I will talk about using the While statement.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy