Powershell получает вывод от rabbitmqctl и анализирует исключение - PullRequest
0 голосов
/ 14 июля 2020

Я вызываю rabbitmqctl из Powrshell:

$out = (& $path ($arguments -split " ") )
Write-Host $out

При правильном пути на выходе появляется сообщение об успешном завершении:

Clearing policy "<policyname>" on vhost "<vhost>" ...

При неправильном пути возникает исключение :

....
    + CategoryInfo          : NotSpecified: (Error::String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
 
Parameter does not exist

Сообщение Clearing policy отсутствует. При остановке выполнения сообщение $ _. Exception.Message пустое.

try {
   $ErrorActionPreference = 'Stop'
   ...
}
catch {
    Write-Warning $_.Exception.Message
}

Есть ли способ получить как сообщение Clearing policy, так и последнюю строку Parameter does not exist?

1 Ответ

2 голосов
/ 14 июля 2020

tl; dr : перенаправить поток ошибок на stdout и преобразовать каждый элемент в строку:

$out = (& $path ($arguments -split " ") 2>&1) | % ToString

При выполнении внешних программ (например, rabbitmqctl) вы не получите никаких исключений. Вы можете получить вывод в разных потоках (в основном stdout и stderr), и ваша внешняя программа вернет код ошибки, но, конечно, не исключение, которое может обработать PowerShell.

Я думаю, вы используете PowerShell ISE. Зачем? Поскольку, в отличие от PowerShell, PowerShell ISE имеет странное поведение, вызывая исключение, если он вынужден печатать текст, который был получен из потока ошибок внешней программы.

Вы можете воспроизвести это с помощью следующего command:

where.exe nonExistentExecutable.bla

В PowerShell он выведет текст, говорящий, что не удалось найти файл с этим шаблоном. В PowerShell ISE вы получите исключение NativeCommandError, которое содержит текст из потока ошибок.

Ключевым моментом здесь является то, что большинство исполняемых файлов записывают в поток ошибок, если им нужно сообщить об ошибках. Так же и where.exe, и rabbitmqctl в вашем случае. Вы не можете захватить поток ошибок следующим образом:

$out = (& $path ($arguments -split " ") )

Это захватит только поток успеха (он же stdout). Поток ошибок будет перенаправлен на консоль, и ISE выдаст исключение. Вот что происходит в вашем случае. Чтобы также захватить поток ошибок, перенаправьте его на stdout:

$out = (& $path ($arguments -split " ") 2>&1)

Теперь $out определенно зафиксирует результат, либо сообщение об успешном выполнении, либо сообщение об ошибке. В случае потока ошибок каждая строка будет заключена в [System.Management.Automation.ErrorRecord], и даже PowerShell (например, ISE) выведет это в виде исключения. Чтобы этого не произошло, преобразуйте каждый элемент в строку:

$out = (& $path ($arguments -split " ") 2>&1) | % ToString

Это не повлияет отрицательно на сообщения об успешном завершении и, таким образом, может использоваться в любом случае.

...