Comment exécuter une fonction PowerShell plusieurs fois en parallèle?

Je ne suis pas sûr d'appeler cela un besoin de multi-threading, basé sur le travail ou asynchrone, mais fondamentalement, j'ai une fonction de script Powershell qui prend plusieurs paramètres et je dois l'appeler plusieurs fois avec des paramètres différents et les faire fonctionner en parallèle.

Actuellement, j'appelle la fonction comme ceci:

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

Comment puis-je appeler cela plusieurs fois sans attendre que chaque appel S'exécute return to the caller?

Actuellement, je cours v2. 0 mais je peux mettre à jour si nécessaire

EDIT: Voici ce que j'ai jusqu'à présent, qui ne fonctionne pas:

$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

Je reçois une erreur:

Impossible de convertir ' système.objet [] 'au type' système.gestion.automatisation.scriptblock " requis par le paramètre 'initializationscript'. la méthode spécifiée n'est pas prise en charge

EDIT2: j'ai modifié mon script mais je reçois toujours l'erreur mentionnée ci-dessus. Voici mon 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
21
demandé sur Ansgar Wiechers 2012-10-07 08:39:55

4 réponses

Aucune mise à jour nécessaire pour cela. Définir un bloc de script et utiliser Start-Job pour exécuter le bloc de script autant de fois que nécessaire. Exemple:

$cmd = {
  param($a, $b)
  Write-Host $a $b
}

$foo = "foo"

1..5 | ForEach-Object {
  Start-Job -ScriptBlock $cmd -ArgumentList $_, $foo
}

Le bloc de script prend 2 paramètres $a et $b, qui sont passés par la -ArgumentList option. Dans l'exemple ci-dessus, les travaux sont $_$a et $foo$b. $foo est juste un exemple pour un paramètre configurable, mais statique.

Exécutez Get-Job | Remove-Job à un moment donné pour supprimer les travaux finis de la file d'attente (ou Get-Job | % { Receive-Job $_.Id; Remove-Job $_.Id } Si vous voulez récupérer la sortie).

37
répondu Ansgar Wiechers 2012-10-07 14:35:45

Voici un script faux rapide dans le but de tester:

$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)."
}

Cette scriptblock peut alors être transmis à Start-Job, avec par exemple 3 paramètres (10, 15, 35)

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

Wait-Job -Job $jobs | Out-Null
Receive-Job -Job $jobs

Cela crée 3 tâches, les affecte à la variable $jobs, Les exécute en parallèle, puis attend la fin de ces 3 tâches et récupère les résultats:

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.

Cela n'a pas pris 90 secondes pour exécuter, seulement 30.

L'Une des parties difficiles est de fournir -Argumentlist à Start-Job, et d'inclure un param() bloquer à l'intérieur du ScriptBlock. Sinon, vos valeurs ne sont jamais vues par le scriptblock.

24
répondu Joost 2016-12-05 14:56:11

Je suis désolé que tout le monde a manqué votre problème-je sais qu'il est beaucoup trop tard maintenant, mais...

Cette erreur est due au fait qu'il vous manque une virgule entre $username et $password dans votre liste.

Vous pouvez le tester avec cet extrait, que j'ai modélisé à partir des réponses précédentes:

$cmd = {
  param($a, $b, $c, $d)
}
$foo = "foo"
$bar = "bar"
start-job -scriptblock $cmd -ArgumentList "a", $foo, $bar, "gold" #added missing comma for this to work
3
répondu Aland 2015-09-10 20:45:55

Vous pouvez utiliser une alternative qui peut être plus rapide que d'invoquer des tâches si la fonction n'est pas longue. Le thread maximum est de 25 et j'invoque seulement cette fonction 10 fois, donc je m'attends à ce que mon temps d'exécution total soit de 5 secondes. Vous pouvez envelopper Mesure-Commande autour de l'=' instruction pour afficher les statistiques.

Exemple:

$ScriptBlock = {
    Param ( [int]$RunNumber )
    Start-Sleep -Seconds 5   
    Return $RunNumber
}
$runNumbers = @(1..10)
$MaxThreads = 25
$runspacePool = [RunspaceFactory ]::CreateRunspacePool(1, $MaxThreads)
$runspacePool.Open()
$pipeLines = foreach($num in $runNumbers){
    $pipeline = [powershell]::Create()
    $pipeline.RunspacePool = $runspacePool
    $pipeline.AddScript($ScriptBlock)    | Out-Null   
    $pipeline.AddArgument($num)  | Out-Null
    $pipeline | Add-Member -MemberType NoteProperty -Name 'AsyncResult' -Value $pipeline.BeginInvoke() -PassThru 
}
#obtain results as they come.
$results =  foreach($pipeline in $pipeLines){
    $pipeline.EndInvoke($pipeline.AsyncResult )
}
#cleanup code.
$pipeLines | % { $_.Dispose()}
$pipeLines = $null
if ( $runspacePool ) { $runspacePool.Close()}
#your results
$results
2
répondu binarySalt 2018-06-27 12:12:49