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
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.
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.
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
}
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With