6

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

Evren Kuzucuoglu
  • 3,413
  • 21
  • 47
  • possible duplicate of [Tell PowerShell ISE to not send stderr to Write-Error](http://stackoverflow.com/questions/12537254/tell-powershell-ise-to-not-send-stderr-to-write-error) – Vesper Jul 16 '15 at 09:42
  • There is no answer to my question in there. 2>&1 doesn't work for me. – Evren Kuzucuoglu Jul 16 '15 at 10:29

3 Answers3

4

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 
}
Community
  • 1
  • 1
Vesper
  • 18,037
  • 4
  • 33
  • 55
  • 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. – Evren Kuzucuoglu Jul 16 '15 at 09:16
  • Yep, there's a problem. `openssl.exe` does indeed generate stderr data, and ISE indeed captures it before redirection... thinking further. – Vesper Jul 16 '15 at 09:40
  • This is a very common thing. For example psexec uses std err for the banner that appears when you start the program – Matt Jul 16 '15 at 10:11
  • $ErrorActionPreference='silentlycontinue' will NOT prevent the swallowing of the stderr messages. – Raúl Salinas-Monteagudo May 02 '19 at 08:01
3

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
}
Community
  • 1
  • 1
Evren Kuzucuoglu
  • 3,413
  • 21
  • 47
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

Colin
  • 10,504
  • 24
  • 36