带有 Invoke-Expression 的 powershell 的 Stderr 和 stdout 没有输出或错误

arc*_*ank 3 powershell stdout stderr

我想获得stdoutstderr运行一个Java进程,并看到了似乎是一个简单的,冷静的方式来做到这一点,但它没有工作:

$command = "java -jar secretserver-jconsole.jar -s 123456 Password"
Invoke-Expression $command -OutVariable output -ErrorVariable errors
Write-Host "stdout: $output"
Write-Host "stderr: $errors"
Run Code Online (Sandbox Code Playgroud)

没有显示$output$errors

我现在正在使用:

$output = cmd /c $command
Run Code Online (Sandbox Code Playgroud)

这确实让我得到了一些stdout,但它并不理想,因为我想要$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)
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 5

注意:下面的解决方案假设了一个行为良好的外部实用程序:一个将数据发送到stdout,并将错误消息发送stderr。如果给定的实用程序意外地将错误消息发送到 stdout,就像 OP 的情况一样,您必须自己解析 stdout 输出以提取错误消息。

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

New-TemporaryFile需要 PSv5,但您可以[io.path]::GetTempFileName()在早期版本中使用。

请注意,$stdout$stderr都将包含一个字符串数组,每个项目代表一个输出行。

外部实用程序的退出代码反映在 PowerShell 的自动$LASTEXITCODE变量中。

请注意,合并捕获 stdout 和 stderr实际上更容易:

$stdoutAndStdErr = java -jar secretserver-jconsole.jar -s 123456 Password 2>&1
Run Code Online (Sandbox Code Playgroud)

注意:每个 stderr 行在结果中都表示为一个[System.Management.Automation.ErrorRecord]实例,但它们的计算结果为字符串上下文中该行的内容


至于你尝试了什么:

通常不需要将命令存储在字符串中(因此很少需要使用Invoke-Expression,其使用可能有风险)。

  • 或者:甚至直接调用外部命令行(注意 PowerShell 对命令行的可能不需要的解释;在 PSv3 中,--%关闭 PowerShell 的解释 - 请参阅Get-Help about_Parsing),
  • 或者,如果您需要先将命令存储在变量中,请使用脚本块( $cmd = { ... }),然后使用&(call operator) 或.(dot-sourcing operator)调用它- 前者为 PS 变量创建一个子作用域,后者才不是。

-OutVariable-ErrorVariable常用的参数仅设计工作与PowerShell的输出流,而不是外界的输出和错误。

  • PowerShell 捕获 stdout 输出,就像它已发送到 PowerShell 的成功输出流一样,并将输出行视为字符串数组

  • Stderr 输出通过(并且不会反映在 中$Error),但您可以使用 将其重定向到一个文件2>$file,或者您可以将其合并到成功流中2>&1(在这种情况下,每个 stderr 行都表示为一个[System.Management.Automation.ErrorRecord]实例)。