Powershell: Как получить код выхода, возвращенный из процесса, запускаемого внутри PsJob?
У меня есть следующая работа в powershell:
$job = start-job {
...
c:\utils\MyToolReturningSomeExitCode.cmd
} -ArgumentList $JobFile
Как мне получить доступ к коду выхода, возвращенному c:\utils\MyToolReturningSomeExitCode.cmd
? Я попробовал несколько вариантов, но единственное, что я мог найти, это то, что работает:
$job = start-job {
...
c:\utils\MyToolReturningSomeExitCode.cmd
$LASTEXITCODE
} -ArgumentList $JobFile
...
# collect the output
$exitCode = $job | Wait-Job | Receive-Job -ErrorAction SilentlyContinue
# output all, except the last line
$exitCode[0..($exitCode.Length - 2)]
# the last line is the exit code
exit $exitCode[-1]
Я нахожу этот подход слишком кривым для моего тонкого вкуса. Может ли кто-нибудь предложить более приятное решение?
Важно. Я прочитал в документации, что powershell должен запускаться как администратор, чтобы работа, связанная с работой, работала. Я не могу запустить его как администратора, следовательно -ErrorAction SilentlyContinue
. Итак, я ищу решения, не требующие прав администратора.
Спасибо.
Ответы
Ответ 1
Если вам нужно сделать что-то в фоновом режиме, а главное script делает что-то еще, то PowerShell класс достаточно (и это обычно быстрее). Кроме того, он позволяет передавать в живой объект, чтобы вернуть что-то в дополнение к выходу через параметры.
$code = @{}
$job = [PowerShell]::Create().AddScript({
param($JobFile, $Result)
cmd /c exit 42
$Result.Value = $LASTEXITCODE
'some output'
}).AddArgument($JobFile).AddArgument($code)
# start thee job
$async = $job.BeginInvoke()
# do some other work while $job is working
#.....
# end the job, get results
$job.EndInvoke($async)
# the exit code is $code.Value
"Code = $($code.Value)"
UPDATE
Исходный код был с объектом [ref]
. Он работает в PS V3 CTP2, но не работает в V2. Поэтому я исправил его, вместо этого мы можем использовать другие объекты, например хэш-таблицу, чтобы возвращать некоторые данные через параметры.
Ответ 2
Один из способов определить, сбой фонового задания или нет на основе кода выхода, - это оценить код выхода внутри самого фонового задания и выбросить исключение, если код выхода указывает на возникшую ошибку. Например, рассмотрим следующий пример:
$job = start-job {
# ...
$output = & C:\utils\MyToolReturningSomeExitCode.cmd 2>&1
if ($LASTEXITCODE -ne 0) {
throw "Job failed. The error was: {0}." -f ([string] $output)
}
} -ArgumentList $JobFile
$myJob = Start-Job -ScriptBlock $job | Wait-Job
if ($myJob.State -eq 'Failed') {
Receive-Job -Job $myJob
}
В этом примере можно отметить пару замечаний. Я перенаправляю стандартный поток вывода ошибок в стандартный выходной поток, чтобы захватить весь текстовый вывод из пакета script и вернуть его, если код выхода не равен нулю, указывая, что он не запускался. Таким образом, создавая исключение, свойство State объекта заданий фона сообщит нам результат работы.