1

I created a ForEach-Object which works, but as soon as I add the -Parallel flag the loop fails with "you cannot call a method on a null-valued expression". I'm using Powershell 7.2

$outputArray = [System.Collections.ArrayList]@()
$outputArrayP = [System.Collections.ArrayList]@()
$testArray =[System.Collections.ArrayList]@()
$testArrayP =[System.Collections.ArrayList]@()

for ($i=0; $i -le 1000;$i++){
    $testArray.Add("Hello $i")>$null
    $testArrayP.Add("Hello $i")>$null
}

$testArray | ForEach-Object { 
    $outputArray.Add("Hello $_")>$null
}

$testArrayP | ForEach-Object -Parallel{ 
    $outputArrayP.Add("Hello $_")>$null
} -ThrottleLimit 5

The actual code stores database queries in an array that I want to run in parallel instead of this sample code.

Related question Making Requests in Parallel with Powershell results in "You cannot call a method on a null-valued expression" where the answer code works also in parallel, but does not answer why my code would fail.

OrigamiEye
  • 864
  • 1
  • 12
  • 31
  • 1
    It's like invoke-command. You would have to use the using: scope to refer to a variable outside of it. – js2010 Mar 08 '23 at 13:45

1 Answers1

2

ForEach-Object -Parallel works by forking work off to separate background runspaces.

Runspaces are the components that host your execution context, including all the variables defined in the current scope, so code that executes in a different runspace than the one you're calling the code from will not be able to "see" the variables you've defined.

You can instruct PowerShell to copy a reference to a variable from the calling runspace into the background runspace by using the using: scope modifier when referring to the variable inside the ForEach-Object block:

$testArrayP | ForEach-Object -Parallel{ 
    ($using:outputArrayP).Add("Hello $_")>$null
} -ThrottleLimit 5
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206