Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell ISE wrongly interprets openssl.exe normal output as error

I am trying to debug a script in the PowerShell ISE, but I am running in an issue where the normal output of a line is interpreted as an error by the ISE

I have been able to simplify the reproduction of this issue: I get whichever version of openssl at https://www.openssl.org/related/binaries.html (I tested this with 1.0.2d x86 from the linked repository http://slproweb.com/products/Win32OpenSSL.html)

I open Powershell ISE, navigate to where the exe is and run the following:

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

The output is red and starts like this:

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

If I run this in the normal PowerShell command window, the output is the same but is white and is not considered as an error

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

I have tried using 2>&1 or encaspsulating the call with an ErrorPreference parameter (as suggested in PowerShell ISE throws an error on git checkout) but it still fails

try/catching all exception does work, but I'd rather not if I can avoid it.

I have tried using PowerShell version 3.0 and 4.0

Edit: if you use $ErrorActionPreference = "SilentlyContinue", it does silence the error, but then you lose access to the output, plus legitimate issues also disappear

like image 314
Evren Kuzucuoglu Avatar asked Jul 16 '15 08:07

Evren Kuzucuoglu


People also ask

Can you use OpenSSL in PowerShell?

To do this, open up your PowerShell console and run choco install OpenSSL. Light as shown below. That's it! You've now installed OpenSSL with PowerShell.

What is parsing in PowerShell?

Normally, PowerShell's command line parsing removes the quote character you provided. The parsed arguments are then joined into a single string with each parameter separated by a space. This string is then assigned to the Arguments property of a ProcessStartInfo object.


2 Answers

Powershell interprets any dump into error channel as an error that's happened on the application side, so it stops the script past that point. You should add 2>&1 in the line which calls openssl.exe, so that standard error of the application won't be captured and interpreted by Powershell as an actual error.

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

UPDATE: It's incurable as is, Powershell ISE does intercept standard error channel into Write-Error and triggers stop. There is a workaround here that includes wrapping the external app that generates error channel output into a script block with local override of $ErrorActionPreference, like this:

& { 
  $ErrorActionPreference='silentlycontinue'
  openssl.exe genrsa 2>&1 
}
like image 101
Vesper Avatar answered Oct 17 '22 16:10

Vesper


I found a working solution.

As specified in the edit to the question, setting $ErrorActionPreference = "SilentlyContinue" is a bit of a wrong solution, because it is in this case the PowerShell equivalent of swallowing all errors, and it also removes access to the actual output of the process. But, while testing with parameters for the command that would actually return a legitimate error, I noticed that in this case I would get a non-0 $LASTEXITCODE (note to anyone having a similar issue: this is actually specific to openssl.exe, it might not be the case for whichever application you are calling).

So I decided to rely on the process exit code to decide if I should treat the stderr as an actual error.

Capturing standard out and error with Start-Process gives a solution to keep the output of the process alive, so:

$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
}
like image 3
Evren Kuzucuoglu Avatar answered Oct 17 '22 16:10

Evren Kuzucuoglu