powershellpowershell-core

How to pass a custom function inside a ForEach-Object -Parallel


I can't find a way to pass the function. Just variables.

Any ideas without putting the function inside the ForEach loop?

function CustomFunction {
    Param (
        $A
    )
    Write-Host $A
}

$List = "Apple", "Banana", "Grape" 
$List | ForEach-Object -Parallel {
    Write-Host $using:CustomFunction $_
}

enter image description here


Solution

  • The solution isn't quite as straightforward as one would hope:

    # Sample custom function.
    function Get-Custom {
      Param ($A)
      "[$A]"
    }
    
    # Get the function's definition *as a string*
    $funcDef = ${function:Get-Custom}.ToString()
    
    "Apple", "Banana", "Grape"  | ForEach-Object -Parallel {
      # Define the function inside this thread...
      ${function:Get-Custom} = $using:funcDef
      # ... and call it.
      Get-Custom $_
    }
    

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

    Note that redefining the function in each thread via a string is crucial, as an attempt to make do without the aux. $funcDef variable and trying to redefine the function with ${function:Get-Custom} = ${using:function:Get-Custom} fails, because ${function:Get-Custom} is a script block, and the use of script blocks with the $using: scope specifier is explicitly disallowed in order to avoid cross-thread (cross-runspace) issues.

    ${function:Get-Custom} is an instance of namespace variable notation, which allows you to both get a function (its body as a [scriptblock] instance) and to set (define) it, by assigning either a [scriptblock] or a string containing the function body.