DevOps | Scripts | Automation

Powershell

How to use the foreach -Parallel loop in PowerShell 7?

Unlike the normal foreach loop which runs sequentially in PowerShell, we can leverage the foreach-object -parallel loop to run the script parallelly. If you have worked with PowerShell 5 workflow then both approaches are almost the same and easier to understand.

Consider the below example which runs the 1 to 10 values randomly. Here the number of values is very little so in this example, you may not see if that runs actually in parallel but they do.

1..10 | foreach-Object -Parallel {
    $_
}

Output:

Please note: we have used the $_ to “capture the current iteration variable value“. You can store it in another variable and use it. The output will be the same as above.

$arr = 1..10

$arr | foreach-Object -Parallel {
    $val = $_
    $val
}
With multiple statements

You can add multiple statements inside the parallel block and they execute sequentially. For example, if you have the 5 processes, the processes will run parallel but content inside the foreach parallel block would run sequentially.

For example,

$computers = @("Computer1","Computer2","Computer3")

$computers | foreach-object -Parallel {
  Write-Output "Running Commands on $_"
   Gwmi win32_Service -ComputerName $_
   Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $_
}

In the above example, foreach -parallel loop will be executed 3 times parallel on the remote computers but 3 commands inside the foreach loop will be executed sequentially.

Use outside variable inside foreach parallel loop.

Using the variables declared outside foreach -parallel loop isn’t that straight. let’s consider the below example and see if that works.

$arr = 1..10
$printvar = "Value"

$arr | foreach-Object -Parallel {
    $val = $_
    "$($printvar) : $val"
}

Output:

You see the value is not printed. So to use the variable declared outside the foreach -parallel loop use the inbuilt $using variable.

$arr = 1..10
$printvar = "Value"

$arr | foreach-Object -Parallel {
    $val = $_
    "$($using:printvar) : $val"
}

Make sure $using a variable is only for assignment not for the other operations like addition or subtraction. For example,

$arr = 1..10
$output = 0
$arr | foreach-Object -Parallel {
    $val = $_
    $using:output += $val
}
Error message
Save Output of the foreach -parallel loop.

Like we can’t use the outside foreach variable inside the loop directly (we need to use $using), variable scope inside the foreach -parallel loop is restricted. For example,

$arr = 1..10
$newarray = @()
$arr | foreach-Object -Parallel {
    $newarray = $using:newArray

    $newarray += $arr

}

"New Array: $newarray"

You won’t see the values in $newarray because the scope is restricted. To store the loop output, save the entire loop to the array.

$arr = 1..10
$newarray = @()
$newarray += $arr | foreach-Object -Parallel { $_ }

"New Array: $newarray"
Output
Control parallel threads using -ThrottleLimit

You can also leverage the foreach parallel loop to configure a number of parallel threads execution using the -ThrottleLimit parameter. By default, this limit is set to 5. You can increase as numbers based on the cores (CPU) present in the system and their availability. Make sure that increasing the throttle limit should not choke your system.

$arr = 1..10
$arr | foreach-Object -Parallel { 
  $_ 
  sleep 1
} -ThrottleLimit 10

Loading