Patrick Stalder
Patrick Stalder

Reputation: 415

Save to array/list in parallel in powershell

I want to parallelize information gathering in my PS scripts.

My scripts usually do something along the lines of

foreach ($system in $systemlist) {
    $system = Add-InformationToServerObj $system 
}

and thus the $systemlist gets populated with more information which later gets used.

How can such a task which requires saving output to one shared list/array be parallelized?

Upvotes: 0

Views: 513

Answers (2)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174515

Start-Job is an option, but it's quite high overhead in processing time since each job kicks of a new process and data will have to be serialized between the parent process and the job process.

Use Runspaces instead:

# Create initial sessionstate object for the runspaces
$InitialSessionState = [initialsessionstate]::Create()
# Import module that contains Add-InformationToServerObj
$InitialSessionState.ImportPSModule("InformationModule")

# Create and open the runspacepool
$RunspacePool = [runspacefactory]::CreateRunspacePool($InitialSessionState)
$RunspacePool.Open()

# Create a new PowerShell instance per "job", collect these along with the IAsyncResult handle (we'll need it later)
$Jobs = foreach($system in $systemlist)
{
    $PSInstance = [powershell]::Create()
    [void]$PSInstance.AddCommand('Add-InformationToServerObj').AddArgument($system)

    New-Object psobject -Property @{
        Instance = $PSInstance
        IAResult = $PSInstance.BeginInvoke()
    }
}

# Wait for runspaces to complete
while($InProgress = @($Jobs |Where-Object {-not $_.IAResult.IsCompleted})){
    # Here you could also use Write-Progress
    Write-Host "$($InProgress.Count) jobs still in progress..."
    Start-Sleep -Milliseconds 500
}

# Collect the output
$systemlist = foreach($Job in $Jobs)
{
    $Job.Instance.EndInvoke($Job.IAResult)
}

# Dispose of the runspacepool
$RunspacePool.Dispose()

The above is a very basic example and has zero error handling - consider using something like Invoke-Parallel or PoshRSJobs instead (PoshRSJobs can also be found on the gallery)

Upvotes: 1

saftargholi
saftargholi

Reputation: 980

use this :

foreach ($system in $systemlist) {
    start-job -scriptblock{$system = Add-InformationToServerObj $system }
}

Upvotes: 1

Related Questions