The PowerShell foreach loop runs a block of code once for every item in a collection, such as an array, a list of files or the output of a command. The current item is stored in the variable you name before in:
foreach ($item in $collection) {
# do something with $item
}
Here’s a real one that walks through an array of office names:
$cities = 'Seattle', 'Denver', 'Austin', 'Boston'
foreach ($city in $cities) {
"Checking the $city office"
}
Output:
Checking the Seattle office
Checking the Denver office
Checking the Austin office
Checking the Boston office

In this guide, I’ll loop through arrays, files and hashtables, show how break and continue work, and explain the difference between foreach, ForEach-Object and the .ForEach() method.
I tested everything in PowerShell 7.6 and Windows PowerShell 5.1. The two traps near the end caught me more than once, so don’t skip them.
Loop through an array with foreach
Arrays are the most common use. You don’t need an index or a counter, and the loop stops on its own after the last item.
This one adds up a list of order amounts:
$orders = 120.50, 89.99, 240.00, 15.25
$total = 0
foreach ($amount in $orders) {
$total += $amount
}
"Orders: $($orders.Count) Total: {0:C}" -f $total
Output:
Orders: 4 Total: $465.74
The {0:C} format shows the total as currency. On a US system, that’s dollars with two decimals.
To loop over pipeline output instead of an array, use ForEach-Object.
Loop through files in a folder
Anything that returns objects can go after in, including a command. Here’s every log file in a folder with its size:
foreach ($file in Get-ChildItem -Path C:\psfaqs\Logs -Filter *.log) {
'{0,-8} {1,8:N1} KB' -f $file.Name, ($file.Length / 1KB)
}
Output:
app.log 2.3 KB
sql.log 93.8 KB
web.log 17.6 KB

For more file examples, see how to loop through files in a folder with PowerShell.
Loop through a hashtable
A hashtable isn’t enumerated item by item on its own. Call GetEnumerator() so each pass gets one key/value pair:
$offices = [ordered]@{ Seattle = 'WA'; Austin = 'TX'; Boston = 'MA' }
foreach ($entry in $offices.GetEnumerator()) {
"$($entry.Key) is in $($entry.Value)"
}
Output:
Seattle is in WA
Austin is in TX
Boston is in MA
I used [ordered] so the output keeps the order I typed. A plain hashtable doesn’t guarantee any order.
How do I get the index in a foreach loop?
The foreach statement doesn’t track the position for you. Keep your own counter:
$tasks = 'Back up the database', 'Patch the servers', 'Rotate the logs'
$i = 0
foreach ($task in $tasks) {
$i++
"Step ${i}: $task"
}
Output:
Step 1: Back up the database
Step 2: Patch the servers
Step 3: Rotate the logs
Note the ${i} braces. Without them, PowerShell reads $i: as a drive-qualified variable and the line breaks. If you need the index a lot, a for loop is usually cleaner.