Stderr and stdout for powershell with Invoke-Expression has no output or errors Stderr and stdout for powershell with Invoke-Expression has no output or errors powershell powershell

Stderr and stdout for powershell with Invoke-Expression has no output or errors


Note: The solution below assumes a well-behaved external utility: one that sends data to stdout, and error messages to stderr. If a given utility unexpectedly sends error messages to stdout instead, as appears to be the case for the OP, you must do your own parsing of stdout output to extract error messages.

$stdout = java -jar secretserver-jconsole.jar -s 123456 Password 2>($tmpFile=New-TemporaryFile)$stderr = Get-Content $tmpFile; Remove-Item $tmpFile

New-TemporaryFile requires PSv5, but you can use [io.path]::GetTempFileName() in earlier versions.

Note that both $stdout and $stderr will contain a string array, with each item representing an output line.

The external utility's exit code is reflected in PowerShell's automatic $LASTEXITCODE variable.

Note that capturing stdout and stderr combined is actually easier:

$stdoutAndStdErr = java -jar secretserver-jconsole.jar -s 123456 Password 2>&1

Note: The stderr lines are each represented as a [System.Management.Automation.ErrorRecord] instance in the result, but they evaluate to the contents of the line in a string context.


As for what you tried:

There's generally no need to store a command in a string (and therefore rarely a need to use Invoke-Expression, whose use can be risky).

  • Either: invoke even external command lines directly (be mindful of possibly unwanted interpretation of the command line by PowerShell; in PSv3, --% turns off PowerShell's interpretation - see Get-Help about_Parsing),
  • or, if you need to store the command in a variable first, use a script block ($cmd = { ... }), and invoke it later with & (call operator) or . (dot-sourcing operator) - the former creates a child scope for PS variables, the latter does not.

The -OutVariable and -ErrorVariable common parameters are only designed to work with PowerShell's output streams, not the outside world's stdout and stderr.

  • PowerShell captures stdout output as if it had been sent to PowerShell's success output stream, and treats the output lines as an array of strings.

  • Stderr output is passed through (and is not reflected in $Error), but you can redirect it to a file with 2>$file, or you can merge it into the success stream with 2>&1 (in which case the stderr lines are each represented as a [System.Management.Automation.ErrorRecord] instance).