Reputation: 63
Please advise, any insight as to what i need to do to have the variable passed successfully would be much appreciated.
This works successfully, but works on each FQDN in the piped list one at a time. i have 100+ servers, so this can take longer than one would think. like 1-6 seconds per server
Write-Host "Confirm correct OS is installed" -ForegroundColor Yellow -BackgroundColor Black
$FQDNs | ForEach-Object {
Invoke-Command -ComputerName $_ -Credential $Credentials -ScriptBlock {
$OS = (Get-CimInstance -ClassName CIM_OperatingSystem).Caption
Write-Host "$Using:_`: $OS" -ForegroundColor Green -BackgroundColor Black
Write-Output "$Using:_`: $OS"
}
}
}
if i add the -Parallel parameter, it fails immediately with the error below. How else am i supposed to give the variable if an automatic variable is the only way I'm seeing that foreach-object pipes them? (I'm hoping that's wrong)
ForEach-Object: C:\Scripts\Checklist.ps1:53
Line |
53 | $FQDNs | ForEach-Object -Parallel {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
| The value of the using variable '$using:_' cannot be retrieved because
| it has not been set in the local session.
Here's the script with the Parallel parameter inserted to show exactly where i'm doing that
Write-Host "Confirm correct OS is installed" -ForegroundColor Yellow -BackgroundColor Black
$FQDNs | ForEach-Object -Parallel {
Invoke-Command -ComputerName $_ -Credential $Credentials -ScriptBlock {
$OS = (Get-CimInstance -ClassName CIM_OperatingSystem).Caption
Write-Host "$Using:_`: $OS" -ForegroundColor Green -BackgroundColor Black
Write-Output "$Using:_`: $OS"
}
}
}
Upvotes: 1
Views: 2007
Reputation: 387
The problem is apparently that PowerShell doesn't always handle nested contexts properly, and in this case, because adding the -Parallel
parameter creates an independent runspace for each script block instance running in parallel, the $Using:
now evaluates for that runspace context rather than the remoting session context in which it was previously executed without the parameter.
You'll actually run into the same problem if you alternately use Invoke-Command
with -ThrottleLimit
and an array of computer names passed into -ComputerName
to take advantage of parallelism rather than ForEach-Object
with -Parallel
.
To address this, try using [scriptblock]::Create()
to build your script block so that the correct context is honored, as described in this answer.
Upvotes: 2
Reputation: 27423
Invoke-command computername comp1,comp2,comp3 already runs in parallel.
# elevated prompt
start-service winrm
invoke-command localhost,localhost,localhost { sleep 10 }
(get-history)[-1] | fl
Id : 3
CommandLine : invoke-command localhost,localhost,localhost { sleep 10 }
ExecutionStatus : Completed
StartExecutionTime : 6/19/2020 10:05:02 AM
EndExecutionTime : 6/19/2020 10:05:13 AM # 11 seconds for all three
Upvotes: 1