Discover the different types of loops in PowerShell

Brock Bingham candid headshot
Brock Bingham|February 16, 2023
PowerShell loops featured image.
PowerShell loops featured image.

Loops are an essential part of programming, and PowerShell is no exception. They allow you to iterate through collections and repeat tasks until a condition is met. Loops can drastically enhance your PowerShell scripts and take your automation to the next level.

Join me as I break down the different types of loops in PowerShell. If it helps, pour yourself an unhealthy-sized bowl of Froot Loops, and we’ll get started. And if you don’t like Froot Loops, just know that I’m silently judging you from across the internet.

What are the different types of loops in PowerShell?

PowerShell utilizes many of the same loop mechanisms you’ll find in other programming languages, with some variations unique to PowerShell. Here are the different types of loops in PowerShell:

  • For loop

  • Foreach loop

  • While loop

  • Do while loop

  • Do until loop

Let’s review them to see how they function, what makes them unique, and when you should use them.

PowerShell For loop

The for loop is very common in programming and functions much the same way in PowerShell as it does in other programming languages. For loops run as long as the specified condition evaluates to $true. When the condition evaluates to $false, the loop terminates. The for loop is excellent for iterating through a statement a fixed number of times.

Here is the basic structure of a for loop:

for (<Init>; <Condition>; <Repeat>) { <Statement list> }

Parentheses contain the for loop statement, and semicolons separate each component of the statement. The first component, represented by <Init>, represents one or more commands that run before the loop begins. Typically, <Init> is used to initialize a variable with a starting value that is utilized in the test condition.

The <Condition> placeholder represents a conditional expression that resolves to a $true or $false Boolean value and typically evaluates the initialized value at the beginning of the loop. The loop and its command block continue to run as long as the value of the condition returns $true. The loop terminates when the condition returns $false.

The <Repeat> placeholder represents one or more commands that execute each time the loop repeats. Typically, this portion of the statement is used to increment the value of the variable used in the conditional expression.

<Statement list> represents the set of commands that repeat as the loop iterates.

Here's an example of a for loop in its most basic form:

for ($i = 1; $i -lt 10; $i++){ Write-Host $i }

In this example, we’re initializing the variable $i with the value of 1. Next, we’re using the less than (-lt) comparison operator to check if the value of $i is less than 10. If the comparison returns $true, the commands in the statement list execute. In this case, we run the command Write-Host $i. Next, we increase the value of $i by one with the expression $i++. This process repeats until the value of $i is 10, at which point the condition $i -lt 10 returns false, and the loop terminates.

Now, let’s look at a more practical example. Let’s say I have a CSV file with six entries. However, due to a processing error, each entry has a duplicate entry resulting in a CSV file with 12 total entries. I can use a for loop to iterate through the CSV file and return only every other entry to weed out the duplicates. Here's my CSV file:

CSV file with duplicate entries.

And here is the PowerShell script to return every other line of the CSV file:

$users = Import-Csv -Path "C:\CSV\the_office_users.csv" for ($i = 0; $i -lt $users.count; $i+=2){ $users[$i] | Export-Csv -Path "C:\CSV\updated_office_users.csv" -Append }

Here is the resulting CSV file after running the script:

A CSV file that was exported using PowerShell to remove duplicate entries.

This example is a little trickier than the last one, so bear with me. In this example, we’re importing all the data from the CSV file and assigning it to the $users array. In the for loop, we’ve set $i to a value of 0 to correspond to the index value of the $user array. For the comparison, we’re comparing $i to $users.count, which goes to 11 since the CSV file contains 12 entries and the array starts at 0. The command statement $users[$i] then executes, which grabs the user data assigned to the current array index, then exports that information to a new CSV file. We add the -Append parameter to the Export-Csv command to ensure each value is added to the file as it loops through the statement. The value of the initialization variable then increases by two using the expression $i+=2. Increasing the initialization variable by two for each loop lets us return every other row of data.

Now, I know what you’re thinking: This sure seems like a lot of work for just a CSV file with 12 rows of data. You’re not wrong. But if this CSV file had 1,200 rows of data, this would be a lifesaver.

PowerShell foreach loops

The foreach loop in PowerShell is used to iterate through a collection of items and is gloriously powerful. But it can also be a bit... weird. When we’re talking about the foreach loop, we could be talking about one of four things:

  • foreach

  • foreach

  • ForEach-Object

  • Foreach

Confused yet? Glad we’re on the same page. Let’s try to make sense of this mess Microsoft has got us in.

There are (kind of) four versions of the foreach loop in PowerShell. There’s the foreach statement, the foreach method, the ForEach-Object cmdlet, and the Foreach alias. Clear as mud? Perfect. Let’s quickly go over each one.

Foreach: The statement

Foreach, the statement, is my personal favorite of the foreach loop varieties. It’s also the one people use the vast majority of the time. Here’s the basic syntax of the foreach statement:

foreach ($<item> in $<collection>{ <statement list> }

Let’s dive right into a simple example to examine how the foreach statement works.

$darths = “Plageuis”, “Bane”, “Sidious”, “Nihilus”, “Revan”, “Vader” foreach ($darth in $darths){ Write-Host “Darth $darth” -ForegroundColor Red }

In this example, we assign several Sith Lord names to the $darths variable. Then, we start the foreach statement and assign the $darth (no “s”) variable as a placeholder to contain the current item being iterated on from the $darths collection. Lastly, we’re using Write-Host (because we don’t care what the internet thinks of us) and displaying the list of darths in red, which seems suitable. Here’s the result.

Results of a foreach statement.

While there are instances when the other foreach loops would be more efficient, the foreach statement will likely be your go-to foreach loop most of the time because of readability and performance.

Foreach: The method

The foreach method is the newest of the foreach loops added to PowerShell. Being a method means it’s quick and easy to call this type of foreach loop, and it can often be a single line of code. The foreach method can also be considerably faster depending on the use case but can suffer with its readability. Here’s an example of the foreach method:

(Get-Process).ForEach({$_.Id})

In this example, we’re using the foreach method to iterate through each returned object from the Get-Process cmdlet, then return the Id of each item. Here's a truncated version of the returned results.

Results of a PowerShell command using the foreach method.

As I mentioned, the foreach method can be considerably faster depending on the use case. For example, invoking a method on each loop iteration can be noticeably faster using the foreach method. For example:

(Get-Process -Name notepad).ForEach(‘Kill’)

In this example, I’m invoking the ‘Kill’ method on each returned process with the name notepad. This command processes much faster than using a foreach statement. However, the best way to determine the efficiency of a command is to use the Measure-Command cmdlet, which can tell you exactly how long it takes for a command to run.

ForEach-Object: The cmdlet

The ForEach-Object cmdlet is a great way to integrate a foreach loop into a pipeline. The ForEach-Object cmdlet also offers advanced functionality, such as supporting the begin, process, and end function blocks. However, because ForEach-Object accepts input from the pipeline, it can be considerably slower than the other options we’ve covered.

Here’s an example of a command using the ForEach-Object cmdlet.

$Grades = 23,22,21,20,19,18,17,16,15,14,13,12 $Grades | ForEach-Object {[Math]::Round($_/23*100)}

In this example, we want to determine the possible scores for an assignment with 23 questions depending on the number of correct answers. This script provides the score for anything above 50%. We’ve assigned the possible correct answers to the $Grades variable and piped that to the ForEach-Object cmdlet. Then, we utilized the Math class’s Round method, which rounds the results of our equation ($_/23*100) to the nearest whole number. Here's the result:

The results of a PowerShell command using the ForEach-Object cmdlet.

Foreach: The alias

Last and definitely least is the Foreach alias. The Foreach alias is the alias for the ForEach-Object cmdlet. I’m pretty sure its sole reason to exist is to confuse people about which foreach loop is being used.

When should you use the Foreach alias? Never. Okay, fine. If you want to use the alias in your one-off command because you’re too lazy to type “-Object” and can’t be bothered with tab completion, then fine. But please don’t ever use this in a script that other people may read one day. You’re just going to cause confusion, and the world is a confusing enough place as it is.

Whew, that felt good to get off my chest. Now that I’ve ranted, let’s move on to while loops.

PowerShell while loops

While loops in PowerShell are the perfect combination of simplicity and power. They’re readable, easy to understand, and can be used to great effect.

While loops run while a condition evaluates to true. They’re similar to for loops, but their syntax is much less complicated. Here is the basic structure of a while loop:

while(<condition>){ <statement list> }

When the while statement runs, PowerShell evaluates the condition before running anything in the <statement list> block, which means the loop never runs if the condition never evaluates to true. As long as the condition evaluates to true, the loop continues to run until the condition returns false or the loop is stopped by another means, such as a break statement.

Here’s an example of a while loop:

$Computer = "thor.whiskeytime.club" $Proc = Invoke-Command -ComputerName $Computer {Get-Process -Name notepad -ErrorAction SilentlyContinue} while($Proc){ $Proc = Invoke-Command -ComputerName $Computer {Get-Process -Name notepad -ErrorAction SilentlyContinue} Write-Host “Notepad is currently running on $Computer” Start-Sleep -Seconds 10 } Write-Host “Notepad is not running on $Computer”

In this example, we’re checking to see if the Notepad process is running on a remote computer. If it is, we enter the while loop, which checks to see if the process is still running. It then writes the status of the remote process to the console. The script then sleeps for 10 seconds. After 10 seconds, the loop reevaluates the condition, repeating until the condition is false, meaning the process is no longer running on the remote computer. Once the loop exits, we indicate that the Notepad process is no longer running on the remote computer.

The results of a PowerShell command using a while loop.

PowerShell do while loop

The do while loop in PowerShell is similar to the while loop but is a bottom-evaluated version. A bottom-evaluated loop just means that the condition is not evaluated until after the statement block has run at least once.

Here’s the syntax of a do while loop:

do { <statement list> } while(<condition>)

And here’s a simple example of a do while loop where the user has to guess the correct number between 1 and 50. If they guess the correct answer, the loop terminates.

$num = 42 do{ $guess = Read-Host -Prompt “Guess a number between 1 and 50:” } while($guess -ne $num) Write-Host “Congratulations, you know the meaning of life.”

And here's the result:

Results of a do while PowerShell command.

PowerShell do until loop

Do until loops are basically the opposite of do while loops. Do until loops iterate until a condition is true. A do until loop iterates as long as the condition evaluates to false. If we were to use the previous example and switch it for a do until loop, the first time a user guessed the wrong answer, the loop would terminate.

Results of a do until PowerShell command.

PowerShell has a loop for every occasion

I don’t know about you, but that was enough loops to get my head spinning.

PowerShell loops are handy, especially when dealing with repetitive tasks and extensive collections. If you want to get really advanced, you can play around with embedded loops and combine them with if statements.

Once you get the hang of PowerShell loops, you can use that knowledge to build your own custom PowerShell scanners in PDQ Inventory. With PowerShell scanners, you can query your managed computers and return loads of valuable information. Try it out for yourself with a 14-day free trial.

Oh, and if you want to spruce up your Visual Studio code like the screenshots in this article, we’ve got you covered with a complete guide on customizing Visual Studio code.

Brock Bingham candid headshot
Brock Bingham

Born in the '80s and raised by his NES, Brock quickly fell in love with everything tech. With over 15 years of IT experience, Brock now enjoys the life of luxury as a renowned tech blogger and receiver of many Dundie Awards. In his free time, Brock enjoys adventuring with his wife, kids, and dogs, while dreaming of retirement.

Related articles