7

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

2

3 Answers 3

5

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 
}
Sign up to request clarification or add additional context in comments.

5 Comments

I tried this, but it does not change anything. The messages openssl.exe output are not on the error channel at all. They are just normal messages.
Yep, there's a problem. openssl.exe does indeed generate stderr data, and ISE indeed captures it before redirection... thinking further.
This is a very common thing. For example psexec uses std err for the banner that appears when you start the program
$ErrorActionPreference='silentlycontinue' will NOT prevent the swallowing of the stderr messages.
Just to be clear: the problem is with the PowerShell ISE. If you run the script from an ordinary PowerShell terminal, the 2>&1 syntax will work, but only if you wrap the call to OpenSSL in a cmdlet: & { openssl.exe genrsa } 2>&1
4

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
}

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.