Why does ($a = Foo) *>&1 write all streams to $a?

Viewed 56

Suppose I have the following function:

function Foo {
    Write-Information 'Info'
    Write-Warning 'Warning'
    Write-Verbose 'Verbose'
    Write-Error 'Error'
    return 'Return'
}

If I assign its output to a variable $a, all streams but the success stream get implicitly written to the terminal (assuming $[Stream]Preference = 'Continue'), while the success stream gets written to $a:

PS1> $a = Foo
Info
WARNING: Warning
VERBOSE: Verbose
Foo : Error
At line:1 char:6
+ $a = Foo
+      ~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Foo

PS1> $a
Return

Running ($a = Foo) yields the same result, except that Return from the success stream also gets dumped to the terminal because of the expression evaluation caused by the parentheses. $a still gets the value Return.

If I redirect all streams to a file, $a still gets the value Return assigned and all streams are redirected as expected:

PS1> ($a = Foo) *>output.txt

PS1> $a
Return

PS1> gc output.txt
Info
Warning
Verbose
Foo : Error
At line:1 char:7
+ ($a = Foo) *>output.txt
+       ~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Foo

Return

But if I redirect all streams to the success stream instead, suddenly $a gets assigned the content of all streams:

PS1> ($a = Foo) *>&1
Info
WARNING: Warning
VERBOSE: Verbose
Foo : Error
At line:1 char:7
+ ($a = Foo) *>&1
+       ~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Foo
 
Return

PS1> # So far so good

PS1> $a
Info
WARNING: Warning
VERBOSE: Verbose
Foo : Error
At line:1 char:7
+ ($a = Foo) *>&1
+       ~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Foo
 
Return

PS1> # ???

How can this behavior be explained? Especially the discrepancy between redirecting to file and redirecting to the success stream. I can understand that $a = Foo *>&1 leads to $a containing everything, but would expect the parentheses to cause the expression to be evaluated before redirecting the streams. Or am I missing something here and the redirection applies before any evaluation? But then $a should be $null when redirecting to file, should it not?

0 Answers
Related