PowerShell tutorial 8 part 2

As I mentioned last time, today’s post is in regards to using pipelines with foreach loops. Whenever you define a collection in a foreach statement, you are more or less setting up a pipeline. Take a look at this example;

foreach ($svc in Get-Service |
where {$_.status -eq 'running'})
{
$svc.name + ": " +
$svc.canstop.tostring().toupper()
}

In this example, the output from get-service is piped to the where-object cmdlet (shown as it’s alias where), which serves to limit the values returned by get-service to only those service objects whose status property value is running.

Another way of writing your pipeline statements is to assign the service objects to a variable, and then call that variable in a foreach statement. Take this example;

$svcs = get-service |
where {$_.status -eq 'running'}
foreach ($svc in $svcs)
{
$svc.name + ": " +
$svc.canstop.tostring().
toupper()
}

here the foreach statement uses $svcs to call the collection. This command returns the same results as those returned by the previous command.

PowerShell also includes the foreach-object cmdlet and foreach is the name of the built-in alias used to reference that cmdlet. The foreach-object cmdlet receives a collection from the pipeline and loops through that collection just like a foreach statement.

get-service |
where {$_.status -eq 'running'} |
foreach {
$_.name + ": " +
$_.canstop.tostring().toupper()
}

This statement begins by piping get-service’s output to the where-object cmdlet. The collection returned by where-object is then piped to the foreach-object cmdlet (referenced by the foreach alias). Notice that the foreach alias is followed only by a script block without any code in parentheses. The implication of this difference between the foreach statement and the foreach-object cmdlet is that, instead of defining an element variable, you use the $_ built in variable. Be aware that you mucst place the opening brace on the same line as the foreach alias, otherwise powershell treats the first line as a complete statement.

if foreach appears at the biginning of a statement, powershell interprets it as the keyword and processes the code that follows as a foreach statement. If it appears anywhere else, powershell interprets it as the foreach-object cmdlet alias.

Powershell supports another alias to reference the foreach-object cmdlet: the percent sign.

get-service |
where {$_.status -eq
'running'} |
% {
$_.name + ": " +
$_.canstop.tostring()
toupper()
}

this will return the same results as the preceding example, except that it uses % rather than foreach.

Although you can use the foreach statement or foreach-object cmdlet to return the same results, there are several differences. The cmdlet is a little simpler because you don’t have to create a special element variable. Instead you use the $_ built in variable.

Another difference is the way powershell processes the two statements. When powershell processes a foreach statement, it generates the entire collection before processing individual values. When Powershell processes a foreachobject cmdlet, it processes each value as it passes through the pipeline, so it uses less memory at any given time. If memory usage is an important consideration, you’ll want to use the cmdlet. A third difference is that you can pass the foreach-object cmdlet’s output down the pipeline, but you can’t do this with the foreach statement’s output.

Get-service |
where {$_.status -eq 'running'} |
foreach {
$_.name + ": " +
$_.canstop.tostring().toupper()
} | sort -decending

the sort-object cmdlet sorts the output in the pipeline in descending order. Another advantage of the foreach-object cmdlet over the foreach statement is that the cmdlet supports three types of script blocks as shown below.

get-service |
where {$_.status -eq 'running'} |
foreach {
$count=0 } {
$_.name + ": " +
$_.canstop.tostring().toupper()
$count ++ } {
write-host
"$count services are running."
write-host
}

The first script block assigns 0 to the $count variable. This variable tracks the number of elements in the collection. The second script block retrieves the Name and CanStop property values for each service and increases the $count value by 1. The third script block prints a message that includes the total number of services, based on the last value in $count. When you include the script blocks in this way, powershell runs the first block before the first loop, runs the second block one time for each loop, and runs the third block after the last loop.

Leave a Reply