1

I am currently struggling with a relatively simple task.

Currently I want to replace an iteration via foreach with an ForEach-object, since I want to enable parallelization (since the majority of the function is purely waiting for a connection).

So

foreach ($vm in $vms)
{
   $output = Invoke-AzVMRunCommand -ResourceGroupName $vm.resourceGroup -VMName $vm.name -ScriptPath ".\script.sh" -CommandId RunShellScript -Verbose
...
   $result | Add-Member -MemberType NoteProperty "Joins" -Value "$($vm.name.tolower())$($vm.resourceGroup.tolower())$($sub.Id.tolower())"
}

will be turned into this:

$vms | ForEach-Object -ThrottleLimit 5 -Parallel {
{
   $vm = $_
   $output = Invoke-AzVMRunCommand -ResourceGroupName $vm.resourceGroup -VMName $vm.name -ScriptPath ".\script.sh" -CommandId RunShellScript -Verbose
...
   $result | Add-Member -MemberType NoteProperty "Joins" -Value "$($vm.name.tolower())$($vm.resourceGroup.tolower())$($sub.Id.tolower())"
}

The problem is inside the final result, since the nested derefencing to this property doesn't get parsed properly. I pressume its dereferencing the ForEach-object instead of the designated super-class. Does anybody have an idea how to correctly link them?

Best regards

€DIT: So since it was asked where the $sub is comming from, here some more detail:

foreach ($sub in $Subscriptions)
{
...
   foreach ($vm in $vms)
   {
      $output = Invoke-AzVMRunCommand -ResourceGroupName $vm.resourceGroup -VMName $vm.name -ScriptPath ".\script.sh" -CommandId RunShellScript -Verbose
   ...
      $result | Add-Member -MemberType NoteProperty "Joins" -Value "$($vm.name.tolower())$($vm.resourceGroup.tolower())$($sub.Id.tolower())"
   }
}
AtroCty
  • 85
  • 1
  • 6

1 Answers1

0

Mathias R. Jessen has provided the crucial pointer in a comment:

As in background / thread jobs and remoting calls in PowerShell, including variable values from the caller's scope requires use of the $using: scope in ForEach-Object -Parallel script blocks.

Since $sub in your code is a variable from the caller's scope (as opposed to the block-local $vm variable, which receives its value via the automatic $_ variable representing the pipeline input at hand), you need to refer to its value as $using:sub.

Therefore, $($sub.Id.tolower()) must be $($using:sub.Id.tolower())

See this answer for more information about when $using: is needed and what its limitations are.

mklement0
  • 382,024
  • 64
  • 607
  • 775