问题
I would like to redirect the output of a command in PowerShell, following these rules:
The command is stored to a variable
Output must be written to the console in real-time (i.e. "ping" results), including errors
Output must be stored to a variable, including errors (real-time is not mandatory here)
Here are my tests, assuming:
$command = "echo:"
to test errors redirection, and:
$command = "ping 127.0.0.1"
to test real-time output.
Output is written in real-time, errors are not redirected at all
Invoke-Expression $command 2>&1 | Tee-Object -Variable out_content
Output is written in real-time, errors are only redirected to the console
Invoke-Expression ($command 2>&1) | Tee-Object -Variable out_content Invoke-Expression $command | Tee-Object -Variable out_content 2>&1
Output is not written in real-time, errors are correctly redirected to both
(Invoke-Expression $command) 2>&1 | Tee-Object -Variable out_content
Is it possible to get those rules working together?
回答1:
Some general recommendations up front:
Invoke-Expression should generally be avoided, because it can be a security risk and introduces quoting headaches; there are usually better and safer solutions available; best to form a habit of avoiding
Invoke-Expression
, unless there is no other solution.There is never a reason to use
Invoke-Expression
to simply execute an external program with arguments, such asping 127.0.0.1
; just invoke it directly - support for such direct invocations is a core feature of any shell, and PowerShell is no exception.If you do need to store a command in a variable or pass it as an argument for later invocation, use script blocks (
{ ... }
); e.g., instead of$command = 'ping 127.0.0.1'
, use$command = { ping 127.0.0.1 }
, and invoke that script block on demand with either&
, the call operator, or.
, the dot-sourcing operator.
When calling external programs, the two operators exhibit the same behavior; when calling PowerShell-native commands,&
executes the code in a child scope, whereas.
(typically) executes in the caller's current scope.
That Invoke-Expression $command 2>&1
doesn't work as expected looks like a bug (as of PowerShell Core 7.0.0-preview.3) and has been reported in this GitHub issue.
As for a workaround for your problem:
PetSerAl, as countless times before, has provided a solution in a comment on the question:
& { Invoke-Expression $command } 2>&1 | Tee-Object -Variable out_content
{ ... }
is a script-block literal that contains the Invoke-Expression
call, and it is invoked with &
, the call operator, which enables applying stream-redirection expression 2>&1
to the &
call, which bypasses the bug.
If $command
contained a PowerShell-native command that you wanted to execute directly in the current scope, such as a function definition, you'd use .
instead of &
.
来源:https://stackoverflow.com/questions/57733552/redirect-powershell-output-and-errors-to-console-in-real-time-and-to-a-variabl