I am trying to write data to external array while running a powershell job-
This is my code sample that I' m trying-
$datafromJob = @()
$wmijobs = @()
foreach ($c in $computers) {
$wmijobs += Start-Job -Name WMIInventory -ScriptBlock {
$jobdata = get-wmiobject -ComputerName $args[0] -Class win32_computersystem -Credential $Cred -ErrorVariable Err -ErrorAction SilentlyContinue
if ($Err.length) {
Add-content -Path D:\InventoryError.log -Force -Value $Err
$details = @{
Domain = "Error"
Manufacturer = "Error"
Computer = $args[0]
Name = "Error"
}
$args[3] += New-Object PSObject -Property $details
}
if ($jobdata.length) {
$details = @{
Domain = $jobdata.Domain
Manufacturer = $jobdata.Manufacturer
Computer = $args[2]
Name = $jobdata.Name
}
$args[3] += New-Object PSObject -Property $details
}
-ArgumentList $c, $Cred, "Test", $datafromJob
}
}
Expecting Output in $datafromJob Variable, but the end of job and loop variable is empty, M not getting how it will work, anyhelp,
Do let me know if any queries on this question
Background jobs run in a separate (child) process, so you fundamentally cannot directly update values in the caller's scope from them.[1]
Instead, make your job script block produce output that the caller can capture with
Receive-Job
.A simple example:
Note: If what you output from a background job are complex objects, they will typically not retain their original type and instead be custom-object emulations, due to the limitations of PowerShell's XML-based cross-process serialization infrastructure; only a limited set of well-known types deserialize with type fidelity, including primitive .NET types, hashtables and
[pscustomobject]
instances (with the type-fidelity limitations again applying to their properties and entries). - see this answer for background information.A few asides:
There is no need to call
Start-Job
/Get-WmiObject
in a loop, because the latter's-ComputerName
parameter can accept an array of target computers to connect to in a single call.Start-Job
) at all.The CIM cmdlets (e.g.,
Get-CimInstance
) superseded the WMI cmdlets (e.g.,Get-WmiObject
) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell [Core] (version 6 and above), where all future effort will go, doesn't even have them anymore.Applying the above to your case:
Caveat re targeting a large number of computers at once:
As of this writing, neither the
Get-CimInstance
help topic nor the conceptual about_CimSession topic discuss connection throttling (limiting the number of concurrent connections to remote computers to prevent overwhelming the system).PowerShell's general-purpose
Invoke-Command
remoting command, by contrast, has a-ThrottleLimit
parameter that defaults to32
. Note that PowerShell remoting must first be enabled on the target computers in order to be able to useInvoke-Command
on them remotely - see about_Remote_Requirements.Therefore, to have more control over how the computers are targeted in parallel, consider combining
Invoke-Command
with local invocation ofGet-CimInstance
on each remote machine; for instance:Also passing a sessions-options object to
Invoke-Command
's-SessionOption
parameter, created withNew-PSSessionOption
, additionally gives you control over various timeouts.[1] In a script block executed in a background job, the automatic
$args
variable contains deserialized copies of the values passed by the caller - see this answer for background information.Note that the usually preferable, thread-based
Start-ThreadJob
cmdlet - see this answer - can receive live references to reference-type instances in the caller's scope, though modifying such objects then requires explicit synchronization, if multiple thread jobs access them in parallel; the same applies to the PowerShell 7+ForEach-Object -Parallel
feature.