PowerShell ForEach Loop

The foreach loop iterates over each item in a collection — an array, a list, a set of files, or pipeline output — and runs a block of code for each item. It is the most natural loop for processing collections in PowerShell because it reads exactly like English: "for each item in this list, do this."

Basic Syntax


foreach ($item in $collection) {
    # Code runs for each item
}
  $fruits = @("Apple", "Banana", "Mango")
  
  Iteration 1: $item = "Apple"  → runs body
  Iteration 2: $item = "Banana" → runs body
  Iteration 3: $item = "Mango"  → runs body
  Loop ends.

Simple foreach Loop


$cities = @("Delhi", "Mumbai", "Chennai", "Kolkata", "Bangalore")

foreach ($city in $cities) {
    Write-Host "City: $city"
}

Output:


City: Delhi
City: Mumbai
City: Chennai
City: Kolkata
City: Bangalore

foreach with Numbers


$scores = @(85, 92, 67, 75, 98)

foreach ($score in $scores) {
    if ($score -ge 80) {
        Write-Host "$score → Pass with Distinction"
    } elseif ($score -ge 60) {
        Write-Host "$score → Pass"
    } else {
        Write-Host "$score → Fail"
    }
}

Output:


85 → Pass with Distinction
92 → Pass with Distinction
67 → Pass
75 → Pass
98 → Pass with Distinction

foreach with a Range


# Iterate through numbers 1 to 10
foreach ($n in 1..10) {
    Write-Host "Square of $n = $($n * $n)"
}

Output:


Square of 1 = 1
Square of 2 = 4
Square of 3 = 9
...
Square of 10 = 100

foreach with String Operations


$emails = @("alice@company.com", "BOB@COMPANY.COM", "Charlie@Company.com")

foreach ($email in $emails) {
    $normalized = $email.ToLower()
    Write-Host $normalized
}

Output:


alice@company.com
bob@company.com
charlie@company.com

foreach with Objects

When cmdlets return objects, foreach processes each object in the collection.


# List all running services
$runningServices = Get-Service | Where-Object { $_.Status -eq "Running" }

foreach ($service in $runningServices) {
    Write-Host "$($service.DisplayName) is running"
}

foreach with Files


# List all .log files in a folder
$logFiles = Get-ChildItem -Path "C:\Logs" -Filter "*.log"

foreach ($file in $logFiles) {
    $sizeMB = [math]::Round($file.Length / 1MB, 2)
    Write-Host "File: $($file.Name)  Size: $sizeMB MB"
}

break and continue Inside foreach


$numbers = @(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

# Skip multiples of 3
foreach ($n in $numbers) {
    if ($n % 3 -eq 0) {
        continue    # Skip this iteration
    }
    Write-Host $n
}

Output:


1
2
4
5
7
8
10

# Stop loop when value exceeds 6
foreach ($n in $numbers) {
    if ($n -gt 6) {
        break
    }
    Write-Host $n
}

Output:


1
2
3
4
5
6

ForEach-Object – Pipeline Version

ForEach-Object is the pipeline-compatible version of foreach. It processes each object that arrives through the pipeline. Inside the script block, $_ refers to the current pipeline object.


# foreach statement version
$names = @("Alice", "Bob", "Carol")
foreach ($name in $names) {
    Write-Host "Hello, $name"
}

# ForEach-Object pipeline version (same result)
@("Alice", "Bob", "Carol") | ForEach-Object {
    Write-Host "Hello, $_"
}

ForEach-Object with Cmdlet Output


# Get processes and show only name and CPU for each
Get-Process | ForEach-Object {
    Write-Host "Process: $($_.Name)  CPU: $($_.CPU)"
}

ForEach-Object Short Alias: %


1..5 | % { Write-Host "Number: $_" }

Output:


Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

Parallel ForEach – PowerShell 7 Feature

PowerShell 7 supports parallel processing in ForEach-Object with the -Parallel parameter. This runs iterations simultaneously instead of one by one — a major performance gain for tasks like querying multiple servers.


# Sequential (one at a time)
1..5 | ForEach-Object {
    Start-Sleep -Seconds 1
    Write-Host "Done: $_"
}
# Takes 5 seconds total

# Parallel (all at the same time)
1..5 | ForEach-Object -Parallel {
    Start-Sleep -Seconds 1
    Write-Host "Done: $_"
} -ThrottleLimit 5
# Takes about 1 second total

Real-world parallel example – check multiple server statuses:


$servers = @("Server01", "Server02", "Server03", "Server04")

$servers | ForEach-Object -Parallel {
    $ping = Test-Connection -ComputerName $_ -Count 1 -Quiet
    [PSCustomObject]@{
        Server  = $_
        Online  = $ping
    }
} -ThrottleLimit 4

foreach Statement vs ForEach-Object

Featureforeach StatementForEach-Object Cmdlet
Syntaxforeach ($x in $list)$list | ForEach-Object { ... }
Current item$x (named variable)$_ (pipeline variable)
Works with pipelineNo (uses variable)Yes (receives piped input)
Parallel supportNoYes (-Parallel in PS7)
PerformanceSlightly fasterSlightly slower (overhead)
Best use casePre-loaded collectionsPipeline processing, parallel tasks

Real-World Example – Bulk User Report


$users = @(
    [PSCustomObject]@{ Name = "Alice"; Department = "IT";   Salary = 80000 },
    [PSCustomObject]@{ Name = "Bob";   Department = "HR";   Salary = 55000 },
    [PSCustomObject]@{ Name = "Carol"; Department = "IT";   Salary = 95000 },
    [PSCustomObject]@{ Name = "Dave";  Department = "Finance"; Salary = 72000 }
)

$totalSalary = 0

foreach ($user in $users) {
    Write-Host "$($user.Name) | $($user.Department) | ₹$($user.Salary)"
    $totalSalary += $user.Salary
}

Write-Host "------------------------------"
Write-Host "Total Salary Budget: ₹$totalSalary"

Output:


Alice | IT | ₹80000
Bob | HR | ₹55000
Carol | IT | ₹95000
Dave | Finance | ₹72000
------------------------------
Total Salary Budget: ₹302000

Summary

The foreach loop processes each item in a collection cleanly without managing index counters. It works with arrays, ranges, file lists, and objects returned by cmdlets. The pipeline version ForEach-Object (with alias %) integrates directly into the PowerShell pipeline. PowerShell 7's -Parallel parameter transforms serial processing into concurrent execution, significantly reducing time for bulk operations like server health checks or file processing across hundreds of items.

Leave a Comment