【问题标题】:Stderr and stdout for powershell with Invoke-Expression has no output or errors带有 Invoke-Expression 的 powershell 的标准错误和标准输出没有输出或错误
【发布时间】:2017-10-02 17:46:28
【问题描述】:

我正在尝试通过运行 java 进程来获取 stdoutstderr,并看到了一种看似简单、酷炫的方法,但它不起作用:

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

$output$errors 不会显示任何内容。

我现在正在使用:

$output = cmd /c $command

这确实让我得到了一些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)

【问题讨论】:

  • 在 PowerShell ISE 中试用。它应该按照你想要的方式工作。
  • @PetSerAl:这两种方法中的哪一种,为什么在 ISE 中运行会有所不同?
  • @mklement0 第一个。因为 ISE 没有控制台。

标签: powershell stdout stderr


【解决方案1】:

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

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

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

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

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

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

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

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


至于你尝试了什么:

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

  • 或者:直接调用外部命令行(注意 PowerShell 可能不需要的命令行解释;在 PSv3 中,--% 关闭 PowerShell 的解释 - 请参阅 Get-Help about_Parsing),
  • 或者,如果您需要先将命令存储在变量中,请使用 脚本块 ($cmd = { ... }),稍后使用&(调用运算符)或. 调用它(点源运算符)- 前者为 PS 变量创建子作用域,后者没有。

-OutVariable-ErrorVariable 通用参数仅设计用于 PowerShell 的 输出流,而不是外部世界的 stdout 和 stderr。

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

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

【讨论】:

  • 我真的希望它能奏效。我试过它没有错误地运行,它在 $stdout 中显示了一些东西,但是如果我故意让它失败,它会在 $stdout 上显示 stderr。那可能是罐子,所以我尝试了一些不同的东西,其中命令是一个简单的 dir c:\temp,它在 $stdout 上显示了一些东西,然后我做了命令 dir c:\temp2(不存在),它确实在 stderr 上正确显示.我将不得不解析它看起来的标准输出,以寻找表明它不幸的是错误的东西。感谢您对有关 .、&、-OutVariable/-ErrorVariable 等的各个部分的澄清。
  • @user372429:所以 jar 行为不端是因为它将错误消息发送到 stdout 而不是 stderr?如果是这种情况,并且您同意此答案中提出的方法确实适用于表现良好的实用程序,我仍然建议您接受此答案,以便为未来的读者提供指导。
  • 当然,在大多数情况下,答案是合理的,但 jar 文件并没有将错误发送到它出现的 stderr。我想我可以尝试找到它使用的记录器,或者联系供应商并要求他们更新,但我不怀疑他们的响应会特别方便。再次非常感谢您提供的信息。无论如何,我继续将其标记为一个好答案。
  • @user372429:我很感激;绝对值得给供应商反馈。
猜你喜欢
  • 2014-03-22
  • 1970-01-01
  • 2017-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 2013-11-28
  • 2014-07-22
相关资源
最近更新 更多