Redirect powershell output and errors to console (in real-time) and to a variable

走远了吗. 提交于 2019-12-08 04:41:13

问题


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.

  1. Output is written in real-time, errors are not redirected at all

    Invoke-Expression $command 2>&1 | Tee-Object -Variable out_content
    
  2. 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
    
  3. 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 as ping 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!