У меня есть сценарий PowerShell, который запускает множество msdeploy одновременно на нескольких удаленных серверах с использованием рабочего процесса Powershell.
Все работает нормально, за исключением того, что в конце каждого цикла «Foreach -Parallel» я получаю следующее исключение:
Microsoft.PowerShell.Utility\Write-Error : The workflow was terminated by a Terminate activity.
At Execute-Bootstrapper:28 char:28
+
+ CategoryInfo : NotSpecified: (:) [Write-Error], WorkflowReturnException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Workflow.WorkflowReturnException,Microsoft.PowerShell.Commands.Writ
eErrorCommand
+ PSComputerName : [localhost]
Как я могу это исправить ? Есть ли особый способ завершить рабочий процесс?
Вот часть, относящаяся к параллельному выполнению:
foreach -Parallel ($remoteHost in $selectedHosts) {
if($Env:FULL -eq "true") {
$process = Start-Process -PassThru -Wait -NoNewWindow "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" "xxx --full"
} else {
$process = Start-Process -PassThru -Wait -NoNewWindow "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" "xxx"
}
if($process.ExitCode -ne 0) {
Exit $process.ExitCode
}
}
Спасибо.
Рабочие процессы отличаются от Windows PowerShell… рабочий процесс может выглядеть как функция с другим ключевым словом, но ... не дайте себя обмануть - самое важное, что нужно знать о рабочих процессах, - это то, что они выглядят как Windows PowerShell, но на самом деле таковыми не являются.
Источник: Рабочие процессы: основы (под Работа и рабочие процессы основная статья на Привет, сценарист! Блог).
Следующий частично прокомментированный сценарий может помочь. Протестировано с использованием очень простых параметров, переданных в MSDeploy.exe
такой, что
-help -verb
действителен, код выхода = 0, а другие -help -brew
и -help -bubu
нет, код выхода = -1.-NoNewWindow
без -RedirectStandardOutput
и -RedirectStandardError
вызовет следующую ошибку (рассмотрите возможность пропуска -NoNewWindow
параметр вообще):
Microsoft.PowerShell.Utility\Write-Error
: Ошибка обработки данных фонового процесса. Сообщается об ошибке: Невозможно обработать элемент с типом узла «Текст». Поддерживаются только типы узлов Element и EndElement.
workflow procWorkflow {
## workflow parameter
param( $selectedHosts )
## $using: prefix allows us to call items that are in the workflow scope
## but not in the function / inlinescript scope.
Function myStartProcess {
param( [string] $lineargs )
$process = Start-Process `
-FilePath "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" `
-PassThru -Wait -NoNewWindow `
-RedirectStandardOutput "$env:TEMP\$using:remoteHost`Out.txt" `
-RedirectStandardError "$env:TEMP\$using:remoteHost`Err.txt" `
-ArgumentList $lineargs
$process.ExitCode # function return value
}
## parallel foreach loop on workflow parameter
foreach -Parallel ($remoteHost in $selectedHosts) {
if($Env:FULL -eq "true") {
# omitted as I know that there is no $Env:FULL variable defined on my comp
} else {
$processEx = myStartProcess "-help -$remoteHost"
### tried instead above function call:
### $lineargs = "-help -$remoteHost"
### $process = Start-Process -FilePath "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" -PassThru -Wait -NoNewWindow -RedirectStandardOutput "$env:TEMP\$remoteHost`Out.txt" -RedirectStandardError "$env:TEMP\$remoteHost`Err.txt" -ArgumentList $lineargs
### and then tried following output alternatives:
### $processEx = $process.ExitCode # null !!!
### $processEx = $process.HasExited # false !!!
### $processEx = $process.GetType().FullName # System.Management.Automation.PSObject
### $processEx = $process # System.Diagnostics.Process (msdeploy)
}
Write-Output @{ $remoteHost = $processEx } # workflow return value
}
}
Вышеуказанный рабочий процесс возвращает массив хэш-таблиц (примерно hostname: exitcode
пары), потому что простого кода выхода будет недостаточно, так как порядок вывода случайный, поскольку он выполнялся параллельно.
## example call to above workflow would look like
$procWorkflow = procWorkflow 'verb','brev','bubu'
## example output processing
"`n=== procWorkflow raw:"
$procWorkflow
"`n=== procWorkflow processed:`n"
for ($i=0; $i -lt $procWorkflow.Count; $i++) {
$procWorkflow[$i].Keys | ForEach-Object {
$procExitcode = $procWorkflow[$i][$_]
if ( $procExitcode -eq 0 ) {
$procOutFile = Get-Item "$env:TEMP\$_`Out.txt"
} else {
$procOutFile = Get-Item "$env:TEMP\$_`Err.txt"
}
'{0,-6} {1,6} {2,12} {3}' -f
$_, $procExitcode, $procOutFile.Length, $procOutFile.Name
}
}
Вывод:
PS D:\PShell> D:\PShell\SF\805314_workflow.ps1
=== procWorkflow raw:
Name Value
---- -----
bubu -1
brev -1
verb 0
=== procWorkflow processed:
bubu -1 56 bubuErr.txt
brev -1 56 brevErr.txt
verb 0 537 verbOut.txt