How to use ForEach-Object Parallel cmdlet in PowerShell?


Foreach-Object -Parallel command was introduced in PowerShell version 7, preview 3, and it is used for the parallel execution of the pipeline input and more details on this have been explained in this article.

Please Note: Foreach-Object and Foreach commands are the same but we can’t write Foreach -Parallel command because there is no such command, we need to use the full command, Foreach-Object -Parallel.

A simple example of running a parallel object.

Example

1..10 | ForEach-Object -Parallel{
    $_ * 1000  
    Sleep 1
}

Output

1000
2000
3000
4000
5000
6000
7000
8000
9000
10000

Let's compare the timings with and without -Parallel parameter.

Parallel Execution

$time1 = Measure-Command {
    1..10 | ForEach-Object -Parallel{
        $_ * 1000  
        Sleep 1
    }

}
    
Write-Output "Parallel Time : Minutes : $($time1.Minutes) , Seconds : $($time1.Seconds) , Milliseconds : $($time1.TotalMilliseconds) "

Output

Parallel Time : Minutes : 0 , Seconds : 2 , Milliseconds : 2500.9792 

Sequential Execution

$time1 = Measure-Command {
    1..10 | ForEach-Object {
        $_ * 1000  
        Sleep 1
    }

}
    
Write-Output "Sequential Time : Minutes : $($time1.Minutes) , Seconds : $($time1.Seconds) , Milliseconds : $($time1.TotalMilliseconds) "

Output

Sequential Time : Minutes : 0 , Seconds : 10 , Milliseconds : 10062.0786

You can see the significant difference between the above two executions that the parallel run is much faster than the sequential.

There is one more parameter that supports the parallelism of the foreach-Object loop is -ThrottleLimit means the number of threads for the parallel execution. By default, the throttle limit is 5. See the time difference when we increase the throttle limit.

Example

$time1 = Measure-Command {
    1..10 | ForEach-Object -Parallel{
        $_ * 1000  
        Sleep 1
    } -ThrottleLimit 10

}
    
Write-Output "Sequential Time : Minutes : $($time1.Minutes) , Seconds : $($time1.Seconds) , Milliseconds : $($time1.TotalMilliseconds) "

Output

Parallel Time : Minutes : 0 , Seconds : 1 , Milliseconds : 1615.4921 

If you compare the first parallel time example, the second is quite faster because we have increased the throttle limit. When you increase the throttle limit make sure which command is used for the parallel execution and the number of throttle limit have passed as an input otherwise the system will overwhelm with the script execution because that many of the PowerShell threads generated.

You can also run this command as a background job because it supports -AsJob parameter.

$fjob = 1..10 | ForEach-Object -Parallel{
        $_ * 1000  
        Sleep 1
} -ThrottleLimit 10 -AsJob 

$fjob | Receive-Job

The difference between the other remote command and foreach-Object -Parallel is that this command runs the jobs parallelly in the same context that is called the namespace while the other remote commands run sequentially on the remote computer using -ComputerName parameter or Invoke-Command and that is the reason parallel execution is much faster for the remote computers.

When you use the Parallel foreach loop in PS version 7 the only variable visible inside the parallel loop is the pipeline variable others outside variable or objects can be accessed with Using: keyword. For example,

Example

$computers = "Test1-Win2k12", "test1-Win2k16"
$command = "Win32_OperatingSystem"

$computers | ForEach-Object -Parallel {
   Get-CimInstance $using:command -ComputerName $_
}

You can see in the above script that only $computers can be accessible inside the Foreach loop via $_ but to access the $command we need to use $using:Command because it is outside the scope of the loop but this is not the case with a simple foreach loop.

Updated on: 11-Nov-2020

2K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements