Enumerate objects in parallel with ForEach-Object
PowerShell 7.0 introduced a third parameter set for ForEach-Object: the -Parallel parameter. This parameter lets you process multiple pipeline objects concurrently, rather than one at a time. The -Parallel parameter requires PowerShell 7.0 or later—it isn't available in Windows PowerShell 5.1.
Basic parallel syntax
The basic syntax uses the -Parallel parameter with a script block:
1..5 | ForEach-Object -Parallel { "Processing $_" }
By default, ForEach-Object -Parallel runs up to five iterations simultaneously. Use the -ThrottleLimit parameter to control the maximum number of concurrent script blocks:
Get-Content servers.txt | ForEach-Object -Parallel {
Test-Connection -ComputerName $_ -Count 1
} -ThrottleLimit 10
Passing variables into parallel script blocks
Parallel script blocks run in separate runspaces and can't directly access variables from the caller's scope. Use the $using: scope modifier to pass outer variables in:
$logPath = "C:\Logs"
Get-ChildItem $logPath -File | ForEach-Object -Parallel {
$path = $using:logPath
Move-Item $_.FullName -Destination "$path\Archive\$($_.Name)"
}
Note
Variables referenced without $using: inside a -Parallel script block are $null because the script block runs in an isolated runspace.
When to use parallel enumeration
Parallel execution is best suited for tasks where the work per object is time-consuming and independent, such as:
- Network operations (Test-Connection, Invoke-RestMethod)
- File I/O operations on separate files
- Queries to multiple servers
For trivial tasks, the overhead of creating new runspaces can make parallel execution slower than sequential processing. Use -Parallel when each operation takes at least several seconds.
Other parameters
-TimeoutSecondslimits how long the parallel operation runs before stopping remaining items.-AsJobreturns the operation as a background job object instead of waiting for results.
1..20 | ForEach-Object -Parallel { Start-Sleep 1; $_ } -ThrottleLimit 5 -TimeoutSeconds 10