Powershell ISE错误地将openssl.exe正常输出解释为错误

时间:2015-07-16 08:36:28

标签: powershell openssl powershell-v3.0 powershell-ise powershell-v4.0

我正在尝试调试PowerShell ISE中的脚本,但我正在运行一个问题,其中一行的正常输出被ISE解释为错误

我已经能够简化这个问题的复制: 我在https://www.openssl.org/related/binaries.html获得了openssl的任何版本(我使用链接存储库http://slproweb.com/products/Win32OpenSSL.html中的1.0.2d x86对其进行了测试)

我打开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 throws an error on git checkout中所述),但仍然失败

尝试/捕捉所有异常确实有效,但我不愿意,如果我可以避免它。

我尝试使用PowerShell版本3.0和4.0

编辑:如果您使用$ErrorActionPreference = "SilentlyContinue",它确实会使错误无效,但您会失去对输出的访问权限,而且合法问题也会消失

3 个答案:

答案 0 :(得分: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并触发停止。解决方法here包括将生成错误通道输出的外部应用程序包装到具有$ErrorActionPreference的本地覆盖的脚本块中,如下所示:

& { 
  $ErrorActionPreference='silentlycontinue'
  openssl.exe genrsa 2>&1 
}

答案 1 :(得分:3)

我找到了一个有效的解决方案。

正如问题编辑中指定的那样,设置$ErrorActionPreference = "SilentlyContinue"是一个错误的解决方案,因为在这种情况下,PowerShell相当于吞下所有错误,并且它还删除了对实际输出的访问权限这个过程。 但是,在使用实际返回合法错误的命令参数进行测试时,我注意到在这种情况下我会得到一个非0 $ LASTEXITCODE(注意任何有类似问题的人:这实际上是特定于openssl.exe,对于你打电话的任何一个应用程序,情况可能并非如此。

所以我决定依赖进程退出代码来决定是否应该将stderr视为实际错误。

Capturing standard out and error with 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
}

答案 2 :(得分:0)

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

From here