powershellparallel-processingswitch-statementscriptblockforeach-object

Powershell implement Switch Statement


I would like to implement a -parallel Switch to one of my skripts

Non Parallel Version:

  $tmpArray | ForEach-Object {
          #region ... local Variables
          $stepWidthLocal = $stepWidth
<#
my code
#>

Parallel Funktion:

  $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel {
          #region ... local Variables
          $stepWidthLocal = $using:stepWidth
<#
my code
#>

What I dont want is:

$myParallel = $true
if ($myParallel) {
  $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel {
    #region ... local Variables
    $stepWidthLocal = $using:stepWidth
    <#
    my code
    #>
  } #end $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel
} #end if($myParallel) 
else {
  $tmpArray | ForEach-Object {
    #region ... local Variables
    $stepWidthLocal = $stepWidth
    <#
my code
#>
  } #end $tmpArray | ForEach-Object {
} #end else {

I want something like this:


$myCode = <#
define my Codeblock
#>
$myParallel = $true
if ($myParallel) {
  $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel {
    #region ... local Variables
    $stepWidthLocal = $using:stepWidth
    $myCode
  } #end $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel
} #end if($myParallel) 
else {
  $tmpArray | ForEach-Object {
    #region ... local Variables
    $stepWidthLocal = $stepWidth
    $myCode
  } #end $tmpArray | ForEach-Object {
} #end else {

Now I want to create some kind of switch statement without duplicating the entire code (block <# my code#>).

is this possible?


Solution

  • You can define the reusable code as a script block, but note that you won't be able to use it directly in your ForEach-Object -Parallel script block and instead have to recreate it there, via its string representation passed to the static [scriptblock]::Create() method; using a simplified example:

    # Your reusable code block.
    # Note the .ToString() call to obtain its string representation.
    $myCodeSource = {
      "hi from thread $([System.Threading.Thread]::CurrentThread.ManagedThreadId)"
    }.ToString()
    
    
    1, 2 | ForEach-Object -Parallel { 
      # ...
      # Note: You can pass arguments, if the script block is prepared to handle them.
      & ([scriptblock]::Create($using:myCodeSource)) 
    }
    

    Note: This answer contains an analogous solution for using a function from the caller's scope in a ForEach-Object -Parallel script block.

    The above output something like the following:

    hi from thread 35
    hi from thread 36
    

    Note (as of PowerShell 7.2):