PowerShell's for loop conforms to the standard established by ANSI C, that is:

for ( <INITIALISATION>; <CONDITION>; <MODIFIER> ) { <STATEMENTS> }

...where:

Some examples:

# # Use $i as the loop iteration value and iterate from 0 through to 10. # for ( $i = 0; $i -le 10; $i++ ) { Write-Host -Object ( '$i is {0}' -f $i ); } #for # # Do the same again, but only display even numbers (i.e.: increment by 2 for each loop iteration). # for ( $i = 0; $i -le 10; $i+=2 ) { Write-Host -Object ( '$i is {0}' -f $i ); } #for # # Use a decrement operation to count backwards from 5 to -5. # for ( $i = 5; $i -ge -5; $i-- ) { Write-Host -Object ( '$i is {0}' -f $i ); } #for # # As a nod to Brian Kernighan and Dennis Ritchie, display a fahrenheit to celcius conversion table. # for ( $fahr = 0; $fahr -le 300; $fahr += 20 ) { Write-Host -Object ( '{0,3}°F {1,8:F1}°C' -f $fahr, ((5/9)*($fahr-32)) ); } #for # # The initialisation, condition and modifier are all optional. So, you *could* loop # forever with the following: # for ( ; ; ) { Write-Host -Object 'Hello World!'; } #for # # However, a more practical use of this optionality is to omit the initialisation. That is, # assume a value from a previous step. # for ( ; $intScore -le 21; $intScore++ ) { Write-Host -Object ( 'The score is {0}.' -f $intScore ); } #for

You can exit a for loop using a statement (see section ).  For example, the loop below will never reach values beyond 5:

# # Use a break statement to exit the loop when we reach 5. # for ( $i = 0; $i -le 10; $i++ ) { $i; if ($i -eq 5) { break; } } #for

This is obviously a contrived example, as you would never use the loop iteration value to exit a for loop (that is, you would set the loop condition properly instead).  Typically, a break statement will be used to react to an external condition, for example, human input or a calculation based on the loop iteration value and another external value, Etc.

You can also cause the for loop to jump to the next loop iteration using a statement.   For example, the loop below will skip values 3 and 7:

# # Use a continue statement to skip to the next loop iteration. # for ( $i = 0; $i -le 10; $i++ ) { if ( ($i -eq 3) -or ($i -eq 7) ) { continue; } $i; } #for

PowerShell's foreach loop provides a way to step through an array (or "collection") of objects in a controlled manner and is, in some respects, the antithesis of PowerShell's , in that it breaks away from the "flow" of the pipeline, reverting to object manipulation techniques used in other 3GLs, such as C#, PHP, Python and Visual Basic .NET.  However, this divergence is well justified when performing state affecting changes (see ).   The format of the foreach loop is as follows:

foreach ( <ITEM> in <COLLECTION> ) { <STATEMENTS> }

...where:

The item data type will match that of the objects being stored in the collection, for example, if we wished to process each rule defined in the Windows firewall, we could quickly identify the data type of a firewall rule:

PS C:\Users\JohnDoe> (Get-NetFirewallRule)[0].GetType().FullName; Microsoft.Management.Infrastructure.CimInstance PS C:\Users\JohnDoe>

We could then define the following:

[Microsoft.Management.Infrastructure.CimInstance[]] $Local:arrFirewallRules = @(); # Collection. [Microsoft.Management.Infrastructure.CimInstance] $Local:objFirewallRule = $null; # Item.

Finally, we can retrieve the firewall rules and process each one in turn:

# # Enumerate firewall rules. # $arrFirewallRules = Get-NetFirewallRule; # # Process firewall rules. # foreach ( $objFirewallRule in $arrFirewallRules ) { # # Do something useful... # $objFirewallRule.Name; } #foreach

The foreach loop can also be used to step through more simple arrays, for example:

# # Step through an array of string values. # foreach ( $s in @('fly', 'spider', 'bird', 'cat', 'dog', 'horse') ) { $s; } # # Step through an array of integers built using the operator (..). # foreach ( $i in @(10..20; 30..40) ) { '192.168.0.{0}' -f $i; }

PowerShell's while loop continues to execute the loop statements while the given condition holds true.  The format of the while loop is as follows:

while ( <CONDITION> ) { <STATEMENTS> }

Note that the condition is evaluated at the beginning of each loop operation; the condition must therefore hold true in order for the loop to be entered in the first place (this differs from PowerShell's loop, which will be discussed below).   We must therefore perform some kind of initialisation prior to entering the loop, for example:

# # This example uses a while loop to ensure that a valid numeric value is supplied by the user. # The loop will only exit once a valid response has been provided. Validation is achieved using # a data type assignment, an condition and an . A more robust # approach would involve using a (discussed in section ). # # Establish an initial condition that will cause our loop to be entered. # [Int32] $Local:intSelection = 0; # # Loop while we have an invalid selection. # while ( ($intSelection -lt 1) -or ($intSelection -gt 5) ) { # # Use an to deal with non-numeric input. # try { # # Get user input and display an error if it's out of range. # $intSelection = Read-Host -Prompt 'Enter a number between 1 and 5'; if ( ($intSelection -lt 1) -or ($intSelection -gt 5) ) { Write-Host -Object 'ERROR : Number out of range.'; } #if } #try catch [System.Management.Automation.MetadataException] { Write-Host -Object 'ERROR : Please enter a number.'; } #catch } #while

PowerShell's do...while loop is similar to the loop, with the exception that the condition is tested at the end of the loop iteration:

do { <STATEMENTS> } until ( <CONDITION> )

This behaviour is useful when you always want the loop operation to execute at lease once.  For example:

# # This example attempts to delete a given file. If the deletion fails, the user # is asked whether they wish to retry. A do...while loop is used to repeat the # operation until the user selects "N" for "no". # # We also use a , and to # ensure that only "Y" or "N" is entered. # [ValidateSet('Y', 'N')] [String] $Local:strRetry = 'N'; [String] $Local:strFile = 'd:\test.txt'; do { Remove-Item -LiteralPath $strFile -ErrorAction silentlyContinue; if ( ! $? ) { while ( $true ) { try { $strRetry = Read-Host -Prompt 'Unable to delete file; retry (Y/N)?'; break; } #try catch [System.Management.Automation.ValidationMetadataException] { Write-Host -Object 'Invalid input.'; } #catch } #while } #if } while ( $strRetry -eq 'Y' ); #do...while

PowerShell's do...until loop operates in the same way as the loop, with the exception that the loop terminating condition is reversed, that is, the loop exits when the condition evaluates to .

# # Loop until a remote host comes online. # do { Write-Host -Object 'Waiting for host to come online...'; Start-Sleep -Seconds 1; } until ( Test-Connection -ComputerName '192.168.0.1' -ErrorAction silentlyContinue )

PowerShell's break command causes processing of the immediate loop to be aborted, with execution passing directly to the command following the loop construct.  The break command is useful for dealing with external factors, such as errors or user interaction, for example:

# # Attempt an HTTP connection with local hosts... # [String] $Local:strIP = ''; [Int32] $Local:intOctet = 0; foreach ( $intOctet in 1..254 ) { $strIP = '192.168.0.{0}' -f $intOctet; Write-Host -Object ( 'Checking for HTTP listener on {0}...' -f $strIP ); Test-NetConnection -CommonTCPPort HTTP -ComputerName $strIP; if ( (Read-Host -Prompt 'Continue (Y/N)') -ne 'Y' ) { break; } } #foreach # # Execution continues here... #

As already mentioned, the break command aborts the immediate loop.  However, it is possible to break out of a parent loop (see , below).

PowerShell's continue command causes execution of the immediate loop iteration to be halted with execution continuing with the next iteration of the loop.

# # Enumerate all established TCP connections. # [Microsoft.Management.Infrastructure.CimInstance[]] $Local:arrTCPConnections = Get-NetTCPConnection | Where State -eq 'Established'; [Microsoft.Management.Infrastructure.CimInstance] $Local:objConnection = $null; foreach ( $objConnection in $arrTCPConnections ) { # # Ignore System process (process ID 4). # if ( $objConnection.OwningProcess -eq 4 ) { Write-Host -Object 'Ignoring system process...'; continue; } #if # # Do something... # Write-Host -Object ( 'Local address/port {0}:{1}; Remote address/port {2}:{3}' -f $objConnection.LocalAddress, $objConnection.LocalPort, $objConnection.RemoteAddress, $objConnection.RemotePort ); } #foreach

As with the command, the continue command can also continue to the next iteration of a parent loop (again, see , below).

Both the and commands support an advanced mode of operation, whereby the developer can specify which loop will be aborted or continued.  This is very useful when dealing with nested loops.  Without this capability, the developer would have to maintain a flag of some kind that would be set when aborting an inner loop; the flag would then be used as a condition to abort the outer loop.

The example below attempts to demonstrate this.  In this example, we have a list of fruit that gets eaten on various days of the week.  The rules of this day/fruit relationship are as follows:

Clear-Host; [String[]] $arrDays = @( 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ); [String] $strDay = ''; [String[]] $arrFruit = @( 'apple', 'banana', 'cherry', 'damson', 'elderberry', 'fig' ); [String] $strFruit = ''; # # Step through days of the week (outer loop). # :DAY_LOOP foreach ( $strDay in $arrDays ) { Write-Host -Object ( 'Today is {0}.' -f $strDay ) -BackgroundColor Red -ForegroundColor White; # # We don't eat fruit on weekends. # if ( ($strDay -eq 'Saturday') -or ($strDay -eq 'Sunday') ) { Write-Host -Object ( "`t{0} is a non-fruit day!" -f $strDay ); continue; # Skip to next day. } #if # # Step through our fruit collection (inner loop). # Write-Host -Object "`tLet's eat some fruit..." -BackgroundColor Yellow -ForegroundColor Black; foreach ( $strFruit in $arrFruit ) { # # We never eat cherries... # if ( $strFruit -eq 'cherry' ) { Write-Host -Object "`t`tYuk, don't like cherries!" -BackgroundColor DarkGray -ForegroundColor White; continue; # Continue to next fruit. } #if # # Eating bananas on a Wednesday sends us to sleep until the next day. # if ( ($strDay -eq 'Wednesday') -and ($strFruit -eq 'banana') ) { Write-Host -Object "`t`tFeeling sleepy... snor!" -BackgroundColor DarkYellow -ForegroundColor Black; continue DAY_LOOP; # Skip to the next iteration of the outer (day) loop. } #if # # Eating damsons on a Friday kills us! # if ( ($strDay -eq 'Friday') -and ($strFruit -eq 'damson') ) { Write-Host -Object "`t`tDamsons on a Friday .... no!!!!! Errrrrrk! " -BackgroundColor Black -ForegroundColor White; break DAY_LOOP; # Break out of the outer (day) loop. } #if Write-Host -Object ( "`t`t{0} - yum!" -f $strFruit ); } #foreach-fruit } #foreach-day