foreach

I was asked about foreach today and responded with a description of who foreach-object works. Thinking about it I should have realised that part of the issue with foreach is the confusion that arises between foreach and foreach – –  that is the difference between the foreach PowerShell statement and the foreach alias of the foreach-object cmdlet.

 

To unravel the confusion there are two different things referred to as foreach. The confusion is that they do very similar things but are used in different ways.

 

The first is the PowerShell statement which is used to step through each value in a collection of values:

 

$procs = Get-Process

foreach ($proc in $procs) {

New-Object -TypeName PSObject -Property @{
   Name = $proc.Name
   SysMen =  $proc.NonpagedSystemMemorySize + $proc.PagedSystemMemorySize64
}

}

 

You create your collection of objects and then use foreach to step through them. It is convention to make the collection plural and the individual member of the collection its singular.  Within the script block you can define what happens to the object.

 

I know I could have a performed this action is a simpler way but I wanted to demonstrate how foreach works. The simpler way would be:

Get-Process |
select Name,
@{Name = ‘SysMen’;
Expression = {$_.NonpagedSystemMemorySize + $_.PagedSystemMemorySize64}}

 

Now we’ve got that out of the way what about the other foreach which is the alias of foreach-object.  This can be use to iterate over a collection of objects. The main difference is that the objects are usually piped into foreach:

 

Get-Process |
foreach {

New-Object -TypeName PSObject -Property @{
   Name = $_.Name
   SysMen =  $_.NonpagedSystemMemorySize + $_.PagedSystemMemorySize64
}

}

 

If you don’t like using $_ to represent the object on the pipeline try

Get-Process |
foreach {

New-Object -TypeName PSObject -Property @{
   Name = $psitem.Name
   SysMen =  $psitem.NonpagedSystemMemorySize + $psitem.PagedSystemMemorySize64
}

}

 

which is exactly equivalent to

Get-Process |
ForEach-Object {

New-Object -TypeName PSObject -Property @{
   Name = $psitem.Name
   SysMen =  $psitem.NonpagedSystemMemorySize + $psitem.PagedSystemMemorySize64
}

}

 

Using the cmdlet or its alias you can set up script blocks to process once when the first object reaches foreach (BEGIN), once per object on the pipeline (PROCESS) and once when the last object has been processed (END)

Get-Process |
ForEach-Object `
-BEGIN {
  Write-Host “First object about to be processed”
} `
-PROCESS {
New-Object -TypeName PSObject -Property @{
   Name = $psitem.Name
   SysMen =  $psitem.NonpagedSystemMemorySize + $psitem.PagedSystemMemorySize64
}
}`
-END {
Write-Host “Last object processed”
}

 

Your ouput looks like this

 

First object about to be processed

Name                                                                      SysMen
—-                                                                      ——
armsvc                                                                    164096
concentr                                                                  200400
conhost                                                                   119104
csrss                                                                     153664
csrss                                                                     407760
           <truncated>

WUDFHost                                                                  103696
WWAHost                                                                   778816
WWAHost                                                                   785120
Yammer.Notifier                                                           566304
Last object processed

 

More info is available in the help files for foreach-object and about_foreach

This entry was posted in Powershell Basics. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s