PowerShell For Loop (With Examples)

A PowerShell for loop runs a block of code a set number of times. You give it a starting value, a condition and a step, and PowerShell repeats the block while the condition is true:

for (<init>; <condition>; <repeat>) {
    <statement list>
}

Here’s the simplest real example, counting from 1 to 5:

for ($i = 1; $i -le 5; $i++) {
    "Pass number $i"
}

Output:

Pass number 1
Pass number 2
Pass number 3
Pass number 4
Pass number 5

Below, you’ll see how each part works, how to loop from 1 to 10, step by 2, count backwards and walk an array by index. I’ll also cover break, continue, the mistakes I see most, and when foreach is the better choice.

I ran every example in PowerShell 7.6 and Windows PowerShell 5.1. The for loop behaves the same in both.

How the three parts of a for loop work

PartExampleWhen it runs
Init$i = 1Once, before the first pass
Condition$i -le 5Before every pass. The loop stops as soon as it’s $false
Repeat$i++After every pass, before the condition is checked again

Because the condition is checked first, the body may never run. for ($i = 10; $i -le 5; $i++) does nothing at all.

Microsoft’s about_For documentation describes the full syntax.

PowerShell for loop from 1 to 10

To loop from 1 to 10, start at 1 and keep going while the counter is less than or equal to 10:

for ($i = 1; $i -le 10; $i++) {
    Write-Output $i
}

Output:

1
2
3
4
5
6
7
8
9
10

When you just need the numbers and don’t care about the counter logic, the range operator 1..10 with foreach is shorter. This one builds server names with a two-digit number:

foreach ($i in 1..10) {
    "Server{0:D2}" -f $i
}

Output:

Server01
Server02
Server03
Server04
Server05
Server06
Server07
Server08
Server09
Server10

Count by 2 or count backwards

The repeat part doesn’t have to be $i++. Use $i += 2 to step by two, or $i-- with -ge to count down:

# count by 2
for ($i = 0; $i -le 10; $i += 2) { $i }

'---'

# count down from 5 to 1
for ($i = 5; $i -ge 1; $i--) { $i }

Output:

0
2
4
6
8
10
---
5
4
3
2
1
PowerShell for loop counting by 2 and counting down from 5 to 1 in Windows PowerShell 5.1
Stepping by 2 and counting down in Windows PowerShell 5.1

Loop through an array by index

This is where the for loop really earns its place. You get the position of each item, not just the item:

$states = 'California', 'Texas', 'Florida', 'New York', 'Ohio'

for ($i = 0; $i -lt $states.Count; $i++) {
    "{0}. {1}" -f ($i + 1), $states[$i]
}

Output:

1. California
2. Texas
3. Florida
4. New York
5. Ohio
PowerShell for loop printing each array item with its position
Looping through an array by index in PowerShell 7

Arrays start at 0, so the condition is $i -lt $states.Count, not -le. I add 1 only when I print the number for humans.

Change array items in place

A foreach loop gives you a copy of each value, so assigning to it doesn’t change the array. With the index, you can update the array directly:

$prices = 19.99, 5.25, 42.00

for ($i = 0; $i -lt $prices.Count; $i++) {
    $prices[$i] = [math]::Round($prices[$i] * 1.08, 2)    # add 8% sales tax
}

$prices

Output:

21.59
5.67
45.36

Loop through an array in reverse

Start at the last index and count down to 0. It’s handy for undo steps or when you remove items while looping:

$steps = 'Download', 'Extract', 'Install', 'Configure'

for ($i = $steps.Count - 1; $i -ge 0; $i--) {
    "Undo: $($steps[$i])"
}

Output:

Undo: Configure
Undo: Install
Undo: Extract
Undo: Download

Use two counters in one for loop

You can move two variables at once. Wrap each assignment in parentheses and separate them with a comma, then do the same in the repeat part:

for (($i = 0), ($j = 10); $i -lt 3; $i++, $j--) {
    "i = $i, j = $j"
}

Output:

i = 0, j = 10
i = 1, j = 9
i = 2, j = 8

Break and continue in a for loop

continue skips the rest of the current pass. break leaves the loop completely:

for ($i = 1; $i -le 10; $i++) {
    if ($i % 2 -eq 0) { continue }    # skip even numbers
    if ($i -gt 7)     { break }       # stop after 7
    $i
}

Output:

1
3
5
7

You can also leave out all three parts to get an endless loop. Just make sure something inside calls break:

$attempt = 0
for (;;) {
    $attempt++
    "Attempt $attempt"
    if ($attempt -eq 3) { "Done"; break }
}

Output:

Attempt 1
Attempt 2
Attempt 3
Done

For more ways to stop a loop early, see how to break out of a foreach loop in PowerShell.

Nested for loops

Put one for loop inside another to work through rows and columns. This prints a small multiplication table:

for ($row = 1; $row -le 3; $row++) {
    $line = for ($col = 1; $col -le 5; $col++) { '{0,4}' -f ($row * $col) }
    -join $line
}

Output:

   1   2   3   4   5
   2   4   6   8  10
   3   6   9  12  15

Common for loop mistakes in PowerShell

Using < instead of -lt

PowerShell uses -lt, -le, -gt and -ge for comparisons. The < sign is reserved, so this won’t even start:

for ($i = 0; $i < 3; $i++) { $i }

Output:

ParserError: C:\psfaqs\lt.ps1:1
Line |
   1 |  for ($i = 0; $i < 3; $i++) { $i }
     |                  ~
     | The '<' operator is reserved for future use.

Going one step past the end of the array

This one is sneakier, because PowerShell doesn’t throw an error. Reading past the end of an array just returns $null:

$letters = 'a', 'b', 'c'

for ($i = 0; $i -le $letters.Count; $i++) {
    "[$i] = '$($letters[$i])'"
}

Output:

[0] = 'a'
[1] = 'b'
[2] = 'c'
[3] = ''

That extra empty pass can write a blank line to a report or call a cmdlet with an empty value. Use -lt $array.Count for arrays.

for vs. foreach vs. ForEach-Object: which is faster?

I timed 100,000 iterations of the same simple calculation on my PC. Your numbers will differ, but the order is the same every time I run it:

$n = 100000

"for:            {0,5:N0} ms" -f (Measure-Command { for ($i = 0; $i -lt $n; $i++) { $null = $i * 2 } }).TotalMilliseconds
"foreach:        {0,5:N0} ms" -f (Measure-Command { foreach ($i in 1..$n) { $null = $i * 2 } }).TotalMilliseconds
"ForEach-Object: {0,5:N0} ms" -f (Measure-Command { 1..$n | ForEach-Object { $null = $_ * 2 } }).TotalMilliseconds

Output:

for:              115 ms
foreach:           38 ms
ForEach-Object:   433 ms
Speed comparison of for, foreach and ForEach-Object loops in PowerShell 7
A second run in PowerShell 7: the times change, the order doesn’t

In the run above, foreach finished in about 38 ms, for in 115 ms, and ForEach-Object took 433 ms because every item goes through the pipeline.

My rule of thumb: use foreach to process every item, for when you need the index or a custom step, and ForEach-Object when you’re already in a pipeline.

Read more in the PowerShell foreach loop and ForEach-Object in PowerShell.

Frequently Asked Questions

What is the syntax of a for loop in PowerShell?

for (<init>; <condition>; <repeat>) { <statements> }, for example for ($i = 1; $i -le 10; $i++) { $i }.

How do I loop from 1 to 10 in PowerShell?

Use for ($i = 1; $i -le 10; $i++) { $i }, or the shorter foreach ($i in 1..10) { $i }.

How do I get the index in a PowerShell loop?

Use a for loop and read the item with $array[$i]. If you prefer foreach, keep your own counter variable and increment it inside the loop.

How do I exit a for loop early in PowerShell?

Call break to leave the loop, or continue to skip to the next pass.

Why doesn’t my for loop run at all?

The condition is checked before the first pass. If it’s already false, for example $i = 10; $i -le 5, the body never runs.

Keep going with these PowerShell loop tutorials: