我试图从运行 java 进程中获得stdout
和stderr
,并看到了看似简单、很酷的方法,但它没有奏效:
$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)
注意:下面的解决方案假设一个行为良好的外部实用程序:将数据发送到标准输出,并将错误消息发送到标准输出。如果给定实用程序意外地将错误消息发送到 stdout(就像 OP 的情况一样),则必须对 stdout 输出进行自己的解析才能提取错误消息。
$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
变量中。
请注意,捕获标准输出和标准输出的组合实际上更容易:
$stdoutAndStdErr = java -jar secretserver-jconsole.jar -s 123456 Password 2>&1
注意:stderr 行在结果中分别表示为[System.Management.Automation.ErrorRecord]
实例,但它们的计算结果是字符串上下文中行的内容。
至于你尝试过的:
通常不需要将命令存储在字符串中(因此很少需要使用Invoke-Expression
,通常应避免使用并且可能存在风险)。
- 要么:直接调用外部命令行(请注意PowerShell对命令行的可能不需要的解释;在PSv3中,停止解析令牌
--%
关闭PowerShell的解释,但请注意其局限性)。 - 或者:如果需要先将完整命令存储在变量中,请使用脚本块(
$cmd = { ... }
),稍后使用&
(调用运算符) 或.
(点源运算符) 调用它 - 前者为 PS 变量创建子作用域,后者不会。 - 或者:如果需要以编程方式和条件地构造要传递给给定外部程序的参数列表,请使用数组,如本答案中所述。
-OutVariable
和-ErrorVariable
通用参数仅用于处理PowerShell的输出流,而不是外部世界的stdout和stderr。
PowerShell 捕获标准输出输出,就像它已发送到 PowerShell 的成功输出流一样,并将输出行视为字符串数组。
Stderr 输出是直通的(并且不会反映在
$Error
中),但您可以将其重定向到带有2>$file
的文件,也可以将其合并到带有2>&1
的成功流中(在这种情况下,stderr 行分别表示为[System.Management.Automation.ErrorRecord]
实例)。