powershellerror-handlingio-redirectiontee

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


I would like to redirect the output of a command in PowerShell, following these rules:

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?


Solution

  • Some general recommendations up front:


    That Invoke-Expression $command 2>&1 doesn't work as expected looks like a bug (as of PowerShell (Core) 7.4.x) and has been reported in GitHub issue #10476.

    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 &.

    Alternative:

    Include the 2>&1 redirection in the string to evaluate:

    Invoke-Expression "$command 2>&1" | Tee-Object -Variable out_content