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
| Feature | foreach Statement | ForEach-Object Cmdlet |
|---|---|---|
| Syntax | foreach ($x in $list) | $list | ForEach-Object { ... } |
| Current item | $x (named variable) | $_ (pipeline variable) |
| Works with pipeline | No (uses variable) | Yes (receives piped input) |
| Parallel support | No | Yes (-Parallel in PS7) |
| Performance | Slightly faster | Slightly slower (overhead) |
| Best use case | Pre-loaded collections | Pipeline 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.
