简体   繁体   中英

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

I am trying to get stdout and stderr from running a java process, and saw what seemed like an easy, cool way to do it, but it did not work:

$command = "java -jar secretserver-jconsole.jar -s 123456 Password"
Invoke-Expression $command -OutVariable output -ErrorVariable errors
Write-Host "stdout: $output"
Write-Host "stderr: $errors"

Nothing displays with $output or $errors .

I am using now:

$output = cmd /c $command

This does get me some stdout , but it is not ideal as I want $error message.

I tried even this elaborate method, but it does not even seem to run the process I think as it returns almost instantly, and I know the normal process tasks several seconds. It also shows no output or error:

$psi = New-object System.Diagnostics.ProcessStartInfo 
$psi.CreateNoWindow = $true 
$psi.UseShellExecute = $false 
$psi.RedirectStandardOutput = $true 
$psi.RedirectStandardError = $true 
$psi.FileName = 'java' 
$psi.Arguments = @("-jar","secretserver-jconsole.jar","-
s","123456","Password") 
$process = New-Object System.Diagnostics.Process 
$process.StartInfo = $psi 
[void]$process.Start()
$output = $process.StandardOutput.ReadToEnd() 
$process.WaitForExit()
Write-Host "stdout: $output"
(tried: adding:
do

    $process.StandardOutput.ReadLine()
}
while (!$process.HasExited)

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM