PowerShell: ForEach and Loops
Loops are essential for automating repetitive tasks. PowerShell provides multiple ways to iterate through collections: ForEach-Object, foreach statement, for, while, and do loops. This lesson covers all loop types with practical pentesting examples.
What You'll Learn
- ForEach-Object cmdlet (pipeline)
- foreach statement
- for loop
- while and do-while loops
- Where-Object for filtering
- Breaking and continuing loops
- Practical automation scenarios
ForEach-Object Cmdlet
Pipeline Processing
# Syntax
Collection | ForEach-Object { Process each item }
# Aliases
ForEach-Object
foreach
%
Basic Usage
# Process each number
1..5 | ForEach-Object { $_ * 2 }
# Output: 2, 4, 6, 8, 10
# $_ represents current item in pipeline
Get-Process | ForEach-Object { $_.Name }
# Multiple commands
Get-ChildItem *.txt | ForEach-Object {
Write-Host "Processing: $($_.Name)"
$content = Get-Content $_.FullName
Write-Host "Lines: $($content.Count)"
}
-Begin, -Process, -End
1..5 | ForEach-Object -Begin {
Write-Host "Starting..."
$sum = 0
} -Process {
$sum += $_
} -End {
Write-Host "Sum: $sum"
}
foreach Statement
Syntax
foreach ($item in $collection) {
# Process $item
}
Basic Usage
# Iterate through array
$numbers = 1..5
foreach ($num in $numbers) {
Write-Host ($num * 2)
}
# Iterate through files
$files = Get-ChildItem *.txt
foreach ($file in $files) {
Write-Host $file.Name
}
# Process services
$services = Get-Service
foreach ($service in $services) {
if ($service.Status -eq "Running") {
Write-Host "$($service.Name) is running"
}
}
for Loop
Syntax
for ($i = 0; $i -lt 10; $i++) {
# Process
}
Examples
# Count 0 to 9
for ($i = 0; $i -lt 10; $i++) {
Write-Host $i
}
# Count backwards
for ($i = 10; $i -gt 0; $i--) {
Write-Host $i
}
# Step by 2
for ($i = 0; $i -lt 10; $i += 2) {
Write-Host $i
}
# Iterate with index
$array = @("a", "b", "c")
for ($i = 0; $i -lt $array.Length; $i++) {
Write-Host "$i: $($array[$i])"
}
while Loop
Syntax
while (condition) {
# Code
}
Examples
# Count to 5
$i = 1
while ($i -le 5) {
Write-Host $i
$i++
}
# Read until empty line
while ($true) {
$input = Read-Host "Enter text (empty to quit)"
if ($input -eq "") { break }
Write-Host "You entered: $input"
}
# Wait for service
while ((Get-Service -Name wuauserv).Status -ne "Running") {
Write-Host "Waiting for service..."
Start-Sleep -Seconds 2
}
do-while and do-until Loops
do-while
# Execute at least once, then check condition
$i = 1
do {
Write-Host $i
$i++
} while ($i -le 5)
do-until
# Execute until condition is true
$i = 1
do {
Write-Host $i
$i++
} until ($i -gt 5)
Where-Object (Filtering)
Syntax
Collection | Where-Object { Condition }
# Aliases
Where-Object
where
?
Examples
# Filter processes
Get-Process | Where-Object { $_.CPU -gt 10 }
# Multiple conditions
Get-Process | Where-Object {
$_.CPU -gt 10 -and $_.WorkingSet -gt 100MB
}
# Filter files
Get-ChildItem | Where-Object { $_.Length -gt 1MB }
# Simplified syntax (PowerShell 3.0+)
Get-Process | Where-Object CPU -gt 10
Get-ChildItem | Where-Object Length -gt 1MB
Break and Continue
break Statement
# Exit loop entirely
foreach ($i in 1..10) {
if ($i -eq 5) { break }
Write-Host $i
}
# Output: 1, 2, 3, 4
continue Statement
# Skip to next iteration
foreach ($i in 1..10) {
if ($i -eq 5) { continue }
Write-Host $i
}
# Output: 1, 2, 3, 4, 6, 7, 8, 9, 10
Nested Loops
# Multiplication table
for ($i = 1; $i -le 5; $i++) {
for ($j = 1; $j -le 5; $j++) {
Write-Host -NoNewline "$($i * $j)`t"
}
Write-Host ""
}
ForEach-Object vs foreach Statement
Performance Comparison
# ForEach-Object (pipeline) - Slower but flexible
1..10000 | ForEach-Object { $_ * 2 }
# foreach statement - Faster
$numbers = 1..10000
foreach ($num in $numbers) { $num * 2 }
When to Use Each
Use ForEach-Object when:
- Working with pipeline
- Don't want to store entire collection in memory
- Need -Begin/-Process/-End blocks
Use foreach statement when:
- Have collection already in memory
- Need maximum performance
- Want simpler syntax
Practical Examples
Example 1: Process Multiple Files
# Rename all .txt files
Get-ChildItem *.txt | ForEach-Object {
$newName = "backup_" + $_.Name
Rename-Item $_.FullName $newName
}
Example 2: Check Multiple Servers
$servers = @("server1", "server2", "server3")
foreach ($server in $servers) {
if (Test-Connection -ComputerName $server -Count 1 -Quiet) {
Write-Host "$server is online" -ForegroundColor Green
} else {
Write-Host "$server is offline" -ForegroundColor Red
}
}
Example 3: Generate Report
$processes = Get-Process | Where-Object { $_.CPU -gt 10 }
$report = @()
foreach ($proc in $processes) {
$report += [PSCustomObject]@{
Name = $proc.Name
CPU = [math]::Round($proc.CPU, 2)
Memory = [math]::Round($proc.WorkingSet / 1MB, 2)
}
}
$report | Export-Csv high_cpu_processes.csv -NoTypeInformation
Example 4: Count Down Timer
for ($i = 10; $i -gt 0; $i--) {
Write-Host "$i..."
Start-Sleep -Seconds 1
}
Write-Host "Go!"
Example 5: Clean Old Files
$files = Get-ChildItem -Path C:\Logs -Recurse -File
foreach ($file in $files) {
if ($file.LastWriteTime -lt (Get-Date).AddDays(-30)) {
Write-Host "Deleting: $($file.FullName)"
Remove-Item $file.FullName -Force
}
}
Practical Pentesting Scenarios
Scenario 1: Port Scan
$target = "192.168.1.1"
$ports = 1..1000
foreach ($port in $ports) {
$connection = Test-NetConnection -ComputerName $target -Port $port -WarningAction SilentlyContinue
if ($connection.TcpTestSucceeded) {
Write-Host "Port $port is OPEN" -ForegroundColor Green
}
}
Scenario 2: Ping Sweep
$network = "192.168.1"
1..254 | ForEach-Object -Parallel {
$ip = "$using:network.$_"
if (Test-Connection -ComputerName $ip -Count 1 -Quiet) {
"$ip is alive"
}
} -ThrottleLimit 50
Scenario 3: Brute Force Username Enumeration
$usernames = Get-Content usernames.txt
$domain = "domain.com"
foreach ($user in $usernames) {
try {
$result = net user $user /domain 2>$null
if ($result) {
Write-Host "[+] Valid user: $user" -ForegroundColor Green
}
} catch {
Write-Host "[-] Invalid user: $user" -ForegroundColor Red
}
}
Scenario 4: Search for Credentials
$keywords = @("password", "pwd", "pass", "credential", "secret")
$files = Get-ChildItem -Recurse -Include *.txt, *.config, *.ini -ErrorAction SilentlyContinue
foreach ($file in $files) {
$content = Get-Content $file.FullName -ErrorAction SilentlyContinue
foreach ($keyword in $keywords) {
$matches = $content | Select-String -Pattern $keyword -CaseSensitive:$false
if ($matches) {
Write-Host "[+] Found '$keyword' in: $($file.FullName)" -ForegroundColor Yellow
}
}
}
Scenario 5: Enumerate Shares
$computers = Get-Content computers.txt
foreach ($computer in $computers) {
Write-Host "`n[*] Checking: $computer"
try {
$shares = Get-WmiObject -Class Win32_Share -ComputerName $computer -ErrorAction Stop
foreach ($share in $shares) {
Write-Host " [+] Share: \\$computer\$($share.Name)" -ForegroundColor Green
}
} catch {
Write-Host " [-] Cannot access $computer" -ForegroundColor Red
}
}
Scenario 6: Hash Cracking Progress
$hashes = Get-Content hashes.txt
$wordlist = Get-Content rockyou.txt
$cracked = @()
foreach ($hash in $hashes) {
foreach ($password in $wordlist) {
$testHash = (Get-FileHash -InputStream ([System.IO.MemoryStream]::new([System.Text.Encoding]::UTF8.GetBytes($password))) -Algorithm MD5).Hash
if ($testHash -eq $hash) {
Write-Host "[+] Cracked: $hash = $password" -ForegroundColor Green
$cracked += [PSCustomObject]@{
Hash = $hash
Password = $password
}
break
}
}
}
$cracked | Export-Csv cracked.csv -NoTypeInformation
Scenario 7: Process Multiple Targets
$targets = Import-Csv targets.csv
foreach ($target in $targets) {
Write-Host "`n[*] Scanning: $($target.IP)"
# Check if alive
if (Test-Connection -ComputerName $target.IP -Count 1 -Quiet) {
Write-Host " [+] Host is up"
# Check common ports
$commonPorts = @(21, 22, 23, 80, 443, 445, 3389)
foreach ($port in $commonPorts) {
$connection = Test-NetConnection -ComputerName $target.IP -Port $port -WarningAction SilentlyContinue
if ($connection.TcpTestSucceeded) {
Write-Host " [+] Port $port is open" -ForegroundColor Green
}
}
} else {
Write-Host " [-] Host is down" -ForegroundColor Red
}
}
Parallel Processing (PowerShell 7+)
ForEach-Object -Parallel
# Process items in parallel
1..10 | ForEach-Object -Parallel {
Start-Sleep -Seconds 2
"Processed $_"
} -ThrottleLimit 5
# Ping sweep (parallel)
1..254 | ForEach-Object -Parallel {
$ip = "192.168.1.$_"
if (Test-Connection -ComputerName $ip -Count 1 -Quiet) {
"$ip is alive"
}
} -ThrottleLimit 50
Quick Reference
ForEach-Object (Pipeline):
Collection | ForEach-Object { $_ }
Collection | % { $_ }
foreach Statement:
foreach ($item in $collection) { }
for Loop:
for ($i = 0; $i -lt 10; $i++) { }
while Loop:
while (condition) { }
do-while Loop:
do { } while (condition)
do-until Loop:
do { } until (condition)
Where-Object (Filter):
Collection | Where-Object { condition }
Collection | ? { condition }
Control:
break # Exit loop
continue # Skip to next iteration
Parallel (PS 7+):
Collection | ForEach-Object -Parallel { } -ThrottleLimit N
Performance Tips
1. Use foreach Statement for Speed
# Faster
$data = 1..10000
foreach ($item in $data) { $item * 2 }
# Slower
1..10000 | ForEach-Object { $_ * 2 }
2. Filter Early
# Good - filter first
Get-ChildItem | Where-Object { $_.Length -gt 1MB } | ForEach-Object { /* process */ }
# Bad - process all, then filter
Get-ChildItem | ForEach-Object { /* process */ } | Where-Object { $_.Length -gt 1MB }
3. Use -Parallel When Possible (PS 7+)
# Much faster for I/O operations
$servers | ForEach-Object -Parallel {
Test-Connection $_ -Count 1
} -ThrottleLimit 10
Resources
Help
Get-Help ForEach-Object -Examples
Get-Help about_ForEach
Get-Help about_While
Get-Help about_Break
Online
- Microsoft Learn PowerShell docs: https://learn.microsoft.com/powershell/
Next Steps
- Practice loops daily - automate everything!
- Learn ForEach-Object -Parallel (PowerShell 7+)
- Combine with Where-Object for powerful filtering
- Master break/continue for flow control
- Benchmark performance - choose right loop type
Loops are the heart of automation. Master them and you'll process thousands of items effortlessly!
"ForEach-Object: Because doing things once is never enough."