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
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).
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.
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
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