Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execute a PowerShell function several times in parallel?

I'm not sure whether to call this a need for multi-threading, job-based, or async, but basically I have a Powershell script function that takes several parameters and I need to call it several times with different parameters and have these run in parallel.

Currently, I call the function like this:

Execute "param1" "param2" "param3" "param4" 

How can I call this multiple times without waiting for each call to Execute return to the caller?

Currently I'm running v2.0 but I can update if necessary

EDIT: here's what I have so far, which doesn't work:

$cmd = {     param($vmxFilePath,$machineName,$username,$password,$scriptTpath,$scriptFile,$uacDismissScript,$snapshotName)     Execute $vmxFilePath $machineName $username $password $scriptTpath $scriptFile $uacDismissScript $snapshotName }  Start-Job -ScriptBlock $cmd -ArgumentList $vmxFilePath, $machineName, $username $password, $scriptTpath, $scriptFile, $uacDismissScript, $snapshotName 

I get an error:

cannot convert 'system.object[]' to the type 'system.management.automation.scriptblock' required by parameter 'initializationscript'. specified method is not supported

EDIT2: I've modified my script but I still get the error mentioned above. Here's my mod:

$cmd = {     param($vmxFilePath,$machineName,$username,$password,$scriptTpath,$scriptFile,$uacDismissScript,$snapshotName)     Execute $vmxFilePath $machineName $username $password $scriptTpath $scriptFile $uacDismissScript $snapshotName }  Start-Job -ScriptBlock $cmd -ArgumentList $vmxFilePath, $machineName, $username $password, $scriptTpath, $scriptFile, $uacDismissScript, $snapshotName 
like image 803
JohnZaj Avatar asked Oct 07 '12 04:10

JohnZaj


People also ask

Can you run 2 PowerShell scripts in parallel?

You can execute parallel jobs in Powershell 2 using Background Jobs. Check out Start-Job and the other job cmdlets.

Which cmdlet can you use to run a PowerShell command on multiple systems in parallel?

Normally, when you use the ForEach-Object cmdlet, each object piped to the cmdlet is processed sequentially. But with the new ForEach-Object -Parallel parameter set, you can run all script in parallel for each piped input object.

Does PowerShell run asynchronously?

PowerShell does not provide an async or await keyword. The PowerShell engine itself has a tendency to very single-threaded unless you take steps to use Start-Job or Start-ThreadJob . Because of this, you'll need to take care when calling async methods in .

How do I pass multiple command line arguments in PowerShell?

To pass multiple parameters you must use the command line syntax that includes the names of the parameters. For example, here is a sample PowerShell script that runs the Get-Service function with two parameters. The parameters are the name of the service(s) and the name of the Computer.


2 Answers

No update necessary for this. Define a script block and use Start-Job to run the script block as many times as necessary. Example:

$cmd = {   param($a, $b)   Write-Host $a $b }  $foo = "foo"  1..5 | ForEach-Object {   Start-Job -ScriptBlock $cmd -ArgumentList $_, $foo } 

The script block takes 2 parameters $a and $b which are passed by the -ArgumentList option. In the example above, the assignments are $_$a and $foo$b. $foo is just an example for a configurable, but static parameter.

Run Get-Job | Remove-Job at some point to remove the finished jobs from the queue (or Get-Job | % { Receive-Job $_.Id; Remove-Job $_.Id } if you want to retrieve the output).

like image 67
Ansgar Wiechers Avatar answered Sep 20 '22 08:09

Ansgar Wiechers


Here's a quick bogus scriptblock for the purpose of testing:

$Code = {     param ($init)     $start = Get-Date     (1..30) | % { Start-Sleep -Seconds 1; $init +=1 }     $stop = Get-Date     Write-Output "Counted from $($init - 30) until $init in $($stop - $start)." } 

This scriptblock can then be passed on to Start-Job, with for example 3 parameters (10, 15, 35)

$jobs = @() (10,15,35) | % { $jobs += Start-Job -ArgumentList $_ -ScriptBlock $Code }  Wait-Job -Job $jobs | Out-Null Receive-Job -Job $jobs 

This creates 3 jobs, assign them to the $jobs variable, runs them in parallel and then waits for these 3 jobs to finish, and retrieves the results:

Counted from 10 until 40 in 00:00:30.0147167. Counted from 15 until 45 in 00:00:30.0057163. Counted from 35 until 65 in 00:00:30.0067163. 

This did not take 90 seconds to execute, only 30.

One of the tricky parts is to provide -Argumentlist to Start-Job, and include a param() block inside the ScriptBlock. Otherwise, your values are never seen by the scriptblock.

like image 27
Joost Avatar answered Sep 21 '22 08:09

Joost