Powershell: Как получить код выхода, возвращенный из процесса, запускаемого внутри PsJob? - программирование
Подтвердить что ты не робот

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. Итак, я ищу решения, не требующие прав администратора.

Спасибо.

4b9b3361

Ответ 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 объекта заданий фона сообщит нам результат работы.