MCPMag.com

Sign up for our newsletter.

I agree to this site's Privacy Policy.

Prof. Powershell

Extending the Reach of ForEach in PowerShell

Here's how to make the ForEach command work for you.

Most of the time we rely on the PowerShell pipeline and the fact that cmdlets can often accept pipelined input.

Get-Service w* | where {$_.status –eq 'running'} | restart-service

You probably are also aware of ForEach-Object when you need to handle objects in an individual basis, such as invoking a method or running multiple commands on the same object.

PS C:\> get-content C:\work\testnames.txt | foreach { get-service wuauserv -computer $_ | Select Machinename,Status,Name} | format-table -autosize
MachineName  Status Name
-----------  ------ ----
chi-dc04    Running wuauserv
chi-dc01    Running wuauserv
chi-dc02    Running wuauserv

I realize there are other ways to use PowerShell to get the same result that might be more efficient to stick with me. I just wanted a simple example to demonstrate ForEach-Object. In this example I'm getting a list of computer names from the text file. For each name (or object) I want to run Get-Service for the Windows Update service on the specified computer. In this context, the $_ indicates the current object in the pipeline, or each name from the list. I then grab a few properties and format the result as a nice table. In PowerShell 3.0 you can also use $psitem instead of $_.

But there's more to ForEach-Object than what you might expect. ForEach-Object actually has 3 scriptblocks, referenced by parameters. The one we are used to seeing is the –Process scriptblock. ForEach-Object gives you a way from the command prompt to process objects the way a cmdlet or an advanced function would. The other parameters you can use are –Begin and –End.

The –Begin scriptblock is a chunk of PowerShell code that runs once before anything is processed from the pipeline. Then there's the –Process scriptblock you are familiar with. The parameter name is positional which is why you may not have known what it is called. The code in this scriptblock is run once on every piped in object. Finally there is the –End scriptblock which runs once after everything has been processed.

Here's a revised version of my command using all the scriptblocks:

get-content C:\work\testnames.txt |
foreach -Begin {
#initialize some variables before processing any names
$offline=@()
$found=@()
$myErr=@()
} -Process {
<#
run this code for each name in the list. I'll define a variable
for the computername to keep things clear and also so that I
can reference it in the Catch scriptblock in the event of an error.
#>
$computer = $_
#test if the computer is running
Write-Host "Processing $computer" -ForegroundColor Cyan
if (Test-Connection -computername $computer -quiet -Count 1) {
#get the service and add it to the results
Try {
$found+=Get-Service -Name wuauserv -ComputerName $computer -ErrorAction Stop
}
Catch {
#add the exception message and name to the error variable
$myErr+="Error querying $computer. $($_.exception.message)."

}
}
else {
#computer is offline so add it $offline
$offline+=$psitem
}
} -end {
#display results after all names have been processed
$found | Select Machinename,Status,Name

#display problems and errors if detected
if ($offline) {
Write-Warning "Failed to query $($offline -join ",")"
}
if ($myErr) {
Write-Warning ($myErr | Out-String)
}
}

The code has a number of comments so I won't repeat myself. In figure 1 you can see the end result:

[Click on image for larger view.] Figure 1.

The –Begin scriptblock executes once defining some variables. Then each name is processed and finally the –End scriptblock runs displaying the results and problems. Again, use my sample here as a learning aid, not as indication of how to get services from a remote computer. ForEach-Object has a lot to offer beyond what you may be used to so take some time to tinker.

 

About the Author

Jeffery Hicks is a Microsoft MVP in Windows PowerShell, Microsoft Certified Trainer and an IT veteran with over 20 years of experience, much of it spent as an IT consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He works today as an independent author, trainer and consultant. Jeff writes the popular Prof. PowerShell column for MPCMag.com and is a regular contributor to the Petri IT Knowledgebase and 4SysOps. If he isn't writing, then he's most likely recording training videos for companies like TrainSignal or hanging out in the forums at PowerShell.org. Jeff's latest books are Learn PowerShell 3 in a Month of Lunches, Learn PowerShell Toolmaking in a Month of Lunches and PowerShell in Depth: An Administrators Guide. You can keep up with Jeff at his blog http://jdhitsolutions.com/blog, on Twitter at twitter.com/jeffhicks and on Google Plus (http:/gplus.to/JeffHicks)

comments powered by Disqus

Reader Comments:

Add Your Comment Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above