Looping through items
Loop processing is a concept that you will need to master in order to write scripts and one-liners with efficiency. You'll need to use loops to iterate over each item in an array or a collection of items, and then run one or more commands within a script block against each of those objects. In this recipe, we'll take a look at how you can use foreach
loops and the ForEach-Object
cmdlet to process items in a collection.
How to do it...
The foreach
statement is a language construct used to iterate through values in a collection of items. The following example shows the syntax used to loop through a collection of mailboxes, returning only the name of each mailbox:
foreach($mailbox in Get-Mailbox) {$mailbox.Name}
In addition, you can take advantage of the PowerShell pipeline and perform loop processing using the ForEach-Object
cmdlet. This example produces the same result as the one shown previously:
Get-Mailbox | ForEach-Object {$_.Name}
You will often see the given command written using an alias of the ForEach-Object
cmdlet, such as the percent sign (%
):
Get-Mailbox | %{$_.Name}
How it works...
The first part of a foreach
statement is enclosed in parentheses and represents a variable and a collection. In the previous example, the collection is the list of mailboxes returned from the Get-Mailbox
cmdlet. The script block contains the commands that will be run for every item in the collection of mailboxes. Inside the script block, the $mailbox
object is assigned the value of the current item being processed in the loop. This allows you to access each mailbox one at a time using the $mailbox
variable.
When you need to perform loop processing within a pipeline, you can use the ForEach-Object
cmdlet. The concept is similar, but the syntax is different because objects in the collection come across the pipeline.
The ForEach-Object
cmdlet allows you to process each item in a collection using the $_
automatic variable, which represents the current object in the pipeline. The ForEach-Object
cmdlet is probably one of the most commonly used cmdlets in PowerShell, and we'll rely heavily on it in many examples throughout the book.
The code inside the script block used with both the looping methods can be more complex than just a simple expression. The script block can contain a series of commands or an entire script. Consider the following code:
Get-MailboxDatabase -Status | %{ $DBName = $_.Name $whiteSpace = $_.AvailableNewMailboxSpace.ToMb() "The $DBName database has $whiteSpace MB of total white space" }
In this example, we're looping through each mailbox database in the organization using the ForEach-Object
cmdlet. Inside the script block, we created multiple variables, calculated the total megabytes of whitespace in each database, and returned a custom message that includes the database name and corresponding whitespace value. This is a simple example, but keep in mind that inside the script block, you can run other cmdlets, work with variables, create custom objects, and many more.
PowerShell also supports other language constructs for processing items, such as the for
, while
, and do
loops. Although these can be useful in some cases, in the next recipe, we will use the while
and do
loops as examples. You can read more about them and view examples using the get-help about_for
, get-help about_while
, and get-help about_do
commands in the shell.
There's more…
There are some key differences between the foreach
statement and the ForEach-Object
cmdlet that you'll want to be aware of when you need to work with loops. First, the ForEach-Object
cmdlet can process one object at a time as it comes across the pipeline. When you process a collection using the foreach
statement, this is the exact opposite. The foreach
statement requires that all of the objects that need to be processed within a loop are collected and stored in memory before processing begins. We would want to take advantage of the PowerShell pipeline and its streaming behavior whenever possible, since it is much more efficient.
The other thing to take note of is that, in PowerShell, foreach
is not only a keyword, but also an alias. This can be a little counterintuitive, especially when you are new to PowerShell and you run into a code sample that uses the following syntax:
Get-Mailbox | foreach {$_.Name}
At first glance, this might seem like we're using the foreach
keyword, but we're actually using an alias for the ForEach-Object
cmdlet. The easiest way to remember this distinction is that the foreach
language construct is always used before a pipeline. If you use foreach
after a pipeline, PowerShell will use the foreach
alias, which corresponds to the ForEach-Object
cmdlet.
Another common loop is the for
loop, and it's ideal to use this loop when the same sequence of statements needs to be repeated a specific number of times. To explain the for
loop, we illustrate this using the following example:
for (initialize; condition; increment) { code block }
The following are the various sections of PowerShell:
- Initialize section: In this section, you can set a variable to a starting value. You can also set one or more variables by separating them with commas.
- Condition section: This condition is tested each time by PowerShell before it executes the code. If the condition is found to be
true
, your body of code will be executed. If the condition is found to befalse
, PowerShell stops executing the code. - Increment section: In this section, you can specify how you want a variable to be updated after each run of the loop. This can be an increment, a decrement, or any other change that you need. After the code has been executed once, PowerShell will update your variable.
The for
loop keeps on looping until your condition turns false
, which is similar to the following example.
for ($i = 1; $i –lt 11; $i++) { Write-Host $i }
In the preceding example, initially, $i
is set to a value of 1
. The loop will run until $i
is less than 11
. Our example will write the value for $i
on the screen.
Other common loops are the do while
and while
loops. These loops executes until the condition value is true
. These kinds of loop can be helpful when moving mailboxes and can then be used to verify that the move is proceeding as expected and has finished successfully. In this case, the move status would be the condition that the loop is using:
do { code block } while (condition)
The preceding two sections shown are almost self-explanatory. Under the do
section, the code is written, as our following example shows that we are using Write-Host
.
Under the while
section, the condition is set; in our example, the condition is that $i
is less than 10
:
do { Write-Host $i $i++ } while ($i –le 10)
See also
- Working with arrays and hash tables
- Understanding the pipeline
- Creating custom objects