Powershell ISE неправильно интерпретирует нормальный вывод openssl.exe как ошибку

Я пытаюсь отладить сценарий в PowerShell ISE, но я столкнулся с проблемой, когда нормальный вывод строки интерпретируется ISE как ошибка

Мне удалось упростить воспроизведение этой проблемы: я получаю любую версию openssl по адресу https://www.openssl.org/related/binaries.html (я тестировал это с 1.0.2d x86 из связанного репозитория http://slproweb.com/products/Win32OpenSSL.html)

Я открываю Powershell ISE, перехожу туда, где находится exe, и запускаю следующее:

$ErrorActionPreference = "Stop"
$env:OPENSSL_CONF = ((Resolve-Path "openssl.cfg").Path)
&openssl.exe genrsa

Результат красный и начинается так:

openssl.exe : Loading 'screen' into random state - done
At line:1 char:1
+ &C:\Trayport\OpenSsl\openssl.exe genrsa
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (Loading 'screen...om state - done:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError

Generating RSA private key, 2048 bit long modulus

Если я запустил это в обычном командном окне PowerShell, результат будет таким же, но будет белым и не будет считаться ошибкой.

Loading 'screen' into random state - done
Generating RSA private key, 2048 bit long modulus

Я пробовал использовать 2> & 1 или заключить вызов с помощью параметра ErrorPreference (как предлагается в PowerShell ISE выдает ошибку при проверке git), но все равно не работает

try / catching all exception действительно работает, но я бы предпочел этого не делать, если я могу этого избежать.

Я пробовал использовать PowerShell версии 3.0 и 4.0

Изменить: если вы используете $ErrorActionPreference = "SilentlyContinue", он заглушает ошибку, но затем вы теряете доступ к выходу, плюс законные проблемы также исчезают


person Evren Kuzucuoglu    schedule 16.07.2015    source источник
comment
возможный дубликат Сообщите PowerShell ISE не отправлять stderr для записи -Ошибка   -  person Vesper    schedule 16.07.2015
comment
Там нет ответа на мой вопрос. 2 ›& 1 мне не подходят.   -  person Evren Kuzucuoglu    schedule 16.07.2015


Ответы (3)


Powershell интерпретирует любой дамп в канал ошибки как ошибку, произошедшую на стороне приложения, поэтому останавливает скрипт после этой точки. Вы должны добавить 2>&1 в строку, которая вызывает openssl.exe, чтобы стандартная ошибка приложения не была зафиксирована и интерпретирована Powershell как фактическая ошибка.

$ErrorActionPreference = "Stop"
$env:OPENSSL_CONF = ((Resolve-Path "openssl.cfg").Path)
& openssl.exe genrsa 2>&1

ОБНОВЛЕНИЕ: это неизлечимо, Powershell ISE перехватывает стандартный канал ошибок в Write-Error, и триггеры останавливаются. здесь есть обходной путь, который включает упаковку внешнее приложение, которое генерирует вывод канала ошибки в блок скрипта с локальным переопределением $ErrorActionPreference, например:

& { 
  $ErrorActionPreference='silentlycontinue'
  openssl.exe genrsa 2>&1 
}
person Vesper    schedule 16.07.2015
comment
Пробовал, но ничего не меняет. Вывод сообщений openssl.exe вообще не относится к каналу ошибок. Это просто нормальные сообщения. - person Evren Kuzucuoglu; 16.07.2015
comment
Ага, есть проблема. openssl.exe действительно генерирует данные stderr, и ISE действительно захватывает их перед перенаправлением ... размышляя дальше. - person Vesper; 16.07.2015
comment
Это обычное дело. Например, psexec использует std err для баннера, который появляется при запуске программы. - person Matt; 16.07.2015
comment
$ ErrorActionPreference = 'silentlycontinue' НЕ предотвратит проглатывание сообщений stderr. - person Raúl Salinas-Monteagudo; 02.05.2019

Нашел рабочее решение.

Как указано в редактировании вопроса, установка $ErrorActionPreference = "SilentlyContinue" - это немного неправильное решение, потому что в этом случае PowerShell является эквивалентом поглощения всех ошибок, а также удаляет доступ к фактическому выходу процесса. Но во время тестирования с параметрами для команды, которая фактически вернула бы допустимую ошибку, я заметил, что в этом случае я получу не-0 $ LASTEXITCODE (обратите внимание на тех, у кого есть похожая проблема: это действительно характерно для openssl.exe, это может быть не так для любого приложения, которое вы вызываете).

Поэтому я решил полагаться на код выхода процесса, чтобы решить, следует ли рассматривать stderr как действительную ошибку.

Захват стандартных выходов и ошибок с помощью Start-Process дает решение, чтобы поддерживать вывод процесса живым, поэтому:

$processStartInfo = New-Object System.Diagnostics.ProcessStartInfo
$processStartInfo.FileName = "openssl.exe"
$processStartInfo.RedirectStandardError = $true
$processStartInfo.RedirectStandardOutput = $true
$processStartInfo.UseShellExecute = $false
$processStartInfo.Arguments = "genrsa"
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $processStartInfo
$process.Start() | Out-Null
$process.WaitForExit()
$standardError = $process.StandardError.ReadToEnd()
if ($process.ExitCode) {
   Write-Error $standardError
} else {
   Write-Host $standardError
}
person Evren Kuzucuoglu    schedule 16.07.2015

Invoke-Expression ".\openssl.exe req -new -nodes -out c:\test\certs\rui.csr -keyout c:\test\certs\rui.key -config c:\test\certs\esxi.cfg" 2>&1

Отсюда

person Colin    schedule 03.10.2017