Windows PowerShell also includes two cmdlets that rely on scriptblocks : ForEach-Object and Where-Object.
A ScriptBlock is a chunk of PowerShell code enclosed in braces. Note
that scriptblocks are also used in functions, filters, and variables.
In fact, anything that you can type in a Windows PowerShell prompt can
be placed in a scriptblock.
The ForEach-Object Cmdlet
ForEach-Object is a flow-control cmdlet
that is used to perform an operation on each object in a pipeline. It
uses the automatic variable $_ to represent the current object and
processes one object at a time. The operation to perform is described
within a script block.
The ForEach-Object cmdlet has the alias foreach, so you can use that instead of typing the full cmdlet name. When you use foreach in a pipeline, Windows PowerShell interprets the command as the ForEach-Object cmdlet. However, when you use foreach at the beginning of a command, the foreach construct is used instead of the ForEach-Object cmdlet. The foreach construct is used to iterate through a series of values in a collection of items, and basically works in the same way as the ForEach-Object
cmdlet. The difference lies in how the objects are processed, the
foreach statement stores the whole collection in memory before
processing while the ForEach-Object cmdlet reads one object at the
time. Another difference is that the foreach statement does not use the $_ variable. Instead the loop variable is specified in the construct.
Here is a simple example of how to use the ForEach-Object cmdlet:
PS > $num = 1,2,3,4,5
PS > $num | ForEach-Object { $_ }
1
2
3
4
5
Notice how we use $_ to work with the current object being processed by the ForEach-Object cmdlet.
Here is an example of using the foreach alias:
PS > $num | foreach { $_ }
1
2
3
4
5
Since we are sending an array through a pipeline, Windows PowerShell interprets the foreach command as the ForEach-Object cmdlet.
You can access specific properties and methods on each object passed to the ForEach-Object cmdlet. Here is an example where we take an array of two string values as input and use the ToUpper() method on each object.
PS > $strings = "windows","powershell"
PS > $strings | ForEach-Object { $_.ToUpper() }
WINDOWS
POWERSHELL
You can also use the ForEach-Object cmdlet to perform operations on multiple sites in a site collection, as demonstrated in this example:
PS > $url = "http://SPServer01"
PS > Get-SPSite -Identity $url | Get-SPWeb | ForEach-Object {
>> "$($_.url) has $($_.Lists.Count) lists"
>> }
http://spserver01 has 24 lists
http://spserver01/Web1 has 9 lists
http://spserver01/Web2 has 1 lists
http://spserver01/Web3 has 7 lists
http://spserver01/Web4 has 2 lists
http://spserver01/Web5 has 1 lists
http://spserver01/Web6 has 7 lists
http://spserver01/Web7 has 2 lists
http://spserver01/Web8 has 6 lists
In this example, we pipe the sites retrieved with Get-SPWeb to the ForEach-Object
cmdlet. We then return the URL and the number of lists in each site.
Notice how we place the $_ variable in a subexpression to access the
properties of the current object being processed by the cmdlet.
In the previous examples, we used a single scriptblock to describe the operation performed on each object passed to the ForEach-Object
cmdlet. It is possible to add two additional scriptblocks: one that
runs before the first object is processed and one that runs when all
objects have been processed. You can add the additional scriptblocks
using the Begin, Process, and End parameters supported by the ForEach-Object cmdlet as demonstrated in this example:
PS > Get-SPSite -Identity http://SPServer01 | Get-SPWeb |
>> ForEach-Object -Begin {Get-Date}
>> -Process {"$($_.url) has $($_.Lists.Count) lists"} '
>> -End {Get-Date}
>>
Sunday, June 27, 2010 1:59:03 PM
http://spserver01 has 24 lists
http://spserver01/Site1 has 9 lists
http://spserver01/Site2 has 1 lists
http://spserver01/Site3 has 7 lists
http://spserver01/Site4 has 2 lists
http://spserver01/Site5 has 1 lists
http://spserver01/Site6 has 7 lists
http://spserver01/Site7 has 2 lists
http://spserver01/Site8 has 6 lists
Sunday, June 27, 2010 1:59:03 PM
Here, we pipe the sites retrieved with Get-SPWeb to the ForEach-Object cmdlet. We then use the Begin parameter to display the current date and time. The Process
parameter uses the current object being processed and displays the URL,
followed by the number of lists in the current site. Finally, the End parameter is used to display the date and time after all of the objects have been processed.
The Where-Object Cmdlet
The Where-Object cmdlet is used to select
objects from a collection based on the conditions specified in its
scriptblock. Each element coming in through the pipeline is evaluated,
and if the result evaluates to true, the element is passed through. If
the result evaluates to false, the element is ignored. Like the ForEach-Object cmdlet, Where-Object uses the $_ automatic variable to host the current pipeline element.
Here is an example of using the Where-Object cmdlet:
PS > $num = 1,2,3,4,5
PS > $num | Where-Object {-not ( $_ % 2 )}
2
4
In this example, we send an array of numeric characters through a pipeline and use the Where-Object cmdlet to check if any of the elements in the array are even.
You can also use logical operators to test different values.
PS > $num | Where-Object {-not ( $_ % 2 ) -or $_ -eq 5 }
2
4
5
In this example, we check if any of the elements in the array are even or equal to 5.
You can pass cmdlets through a pipeline and perform evaluations on the objects returned by a cmdlet.
PS > Get-SPSite -Identity http://SPServer01 | Get-SPWeb |
>> Where-Object { $_.LastItemModifiedDate -lt $(Get-Date 5/5/2010) }
Url
---
http://spserver01
http://spserver01/Site1
http://spserver01/Site2
Here, we pipe the sites retrieved with Get-SPWeb to the Where-Object cmdlet. We then check if the LastItemModifiedDate is less than May 5, 2010. Three sites meet the criteria in the example.
You can go one step further and send the objects to the ForEach-Object cmdlet and perform additional operations on the objects that meet the criteria.
PS > Get-SPSite -Identity http://SPServer01 | Get-SPWeb |
>> Where-Object { $_.LastItemModifiedDate -lt $(Get-Date 5/5/2010) } |
>> ForEach-Object { $_.Author }
UserLogin DisplayName
--------- -----------
POWERSHELL\sezel Sergey Zelenov
POWERSHELL\maka Mattias Karlsson
POWERSHELL\nigo Niklas Goude
In this example, we use the ForEach-Object cmdlet to return the author of the sites that meet the criteria.