The solution isn't quite as straightforward as one would hope:
function CustomFunction {
Param ($A)
"[$A]"
}
# Get the function's definition *as a string*
$funcDef = $function:CustomFunction.ToString()
"Apple", "Banana", "Grape" | ForEach-Object -Parallel {
# Define the function inside this thread...
$function:CustomFunction = $using:funcDef
# ... and call it.
CustomFunction $_
}
Note: This answer contains an analogous solution for using a script block from the caller's scope in a ForEach-Object -Parallel
script block.
This approach is necessary, because - aside from the current location (working directory) and environment variables (which apply process-wide) - the threads that ForEach-Object -Parallel
creates do not see the caller's state, notably neither with respect to variables nor functions (and also not custom PS drives and imported modules).
- Update: js2010's helpful answer shows a more straightforward solution that passes a
System.Management.Automation.FunctionInfo
, obtained via Get-Command
, which can be invoked directly with &
. The only caveat is that the original function should be side-effect-free, i.e. should operate solely based on parameter or pipeline inputs, without relying on the caller's state, notably its variables, as that could lead to thread-safety issues. The stringification technique above implicitly prevents any problematic references to the caller's state, because the function body is rebuilt in each thread's context.
As of PowerShell 7.1, an enhancement is being discussed on GitHub to support copying the caller's state to the threads on demand, which would make the caller's functions available.
Note that making do without the aux. $funcDef
variable and trying to redefine the function with $function:CustomFunction = $using:function:CustomFunction
is tempting, but $function:CustomFunction
is a script block, and the use of script blocks with the $using:
scope specifier is explicitly disallowed.
$function:CustomFunction
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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…