5

There are four ways to suppress an output:

  1. Redirection to $null variable
    PS C:\> 1; $(2; return) > $null; 3
    1
    3
    
  2. Piping to Out-Null cmdlet
    PS C:\> 1; $(2; return) | Out-Null; 3
    1
    2
    
  3. Casting to [void] type
    PS C:\> 1; [void]$(2; return); 3
    1
    2
    
  4. Assignment to $null variable
    PS C:\> 1; $null = $(2; return); 3
    1
    2
    

All four cases are expected to be equivalent.

Why redirection to $null behaves different? Have I faced a bug?

An additional example

This example shows unexpected behavior of > $null command in PS 2.0:

PS C:\> 1; $(Write-Output 2; Write-Host 3; return; Write-Host 4) > $null; 5
1
3
5

return command acts as if it exits from some nested context (though there is no command which creates it), stops $() expression execution and then continues the execution (when it shouldn't) in the current context to the Write-Output 5 command.

BEHAVIOR EXPLANATIONS

(from wOxxOm's answer)

  • in PS 1.0 and 2.0 > $null operation is executed before $() expression and suppresses its output; return command does not exit from the current context (considered a BUG), but stops $() expression execution
  • in PS 3.0 and newer > $null operation is executed before $() expression and suppresses its output in all cases; return command exits from the current context completely
  • | Out-Null, [void], $null = operations are executed after $() expression and suppress its output if there is no return command in it; return command exits from the current context completely

SUMMARY

Different methods for suppressing command output:

  1. ... > $null redirection to $null variable
    Bug in PS 1.0 and 2.0. In PS 3.0+ output may differ from other methods
  2. ... | Out-Null piping to Out-Null cmdlet
    Performance issues *
  3. [void]... casting to [void] type
    Advisable
  4. $null = ... assignment to $null variable
    Advisable
Dmitriy Work
  • 773
  • 10
  • 17
  • Regarding your edits: if you don't use `return` in expressions, which seems really weird, you can safely use `>$null` when it's more appropriate than casting or assigning. – wOxxOm Feb 24 '17 at 18:27
  • @wOxxOm can I ask you for an example where `> $null` is more appropriate than casting or assigning? – Dmitriy Work Feb 25 '17 at 21:24
  • I meant subjectively/semantically more appropriate. – wOxxOm Feb 26 '17 at 04:42

1 Answers1

4
  • 2 is actually executed as Write-Output 2
     

  • $() executes the enclosed code in the same context, it doesn't create a new context.

    Things that create a new context are scriptblocks like & { ... }, 1..2 | ForEach { ... },
    ({ ... }).Invoke(), select @{N='calculated property'; E={$_.foo}} and functions.
     

  • Thus, $( return ) exits from the current context so nothing should be evaluated after that (in other words PowerShell 1.0 and 2.0 have a bug).

 

Redirecting the output stream:

1; $(2; return) > $null; 3

The output stream itself of the entire $() expression is suppressed with >$null, which is decided before the expression is evaluated, return exits from the current context before 3 gets a chance.

PS 3 (and newer) correctly prints only 1:

1

PS 1 and 2 incorrectly print both numbers and indeed it's a bug:

1
3

 

Processing the output stream:

1; [void]$(2; return); 3
1; $null = $(2; return); 3
1; $(2; return) | Out-Null; 3

1
2

2 is pushed to the output stream here, then return exits the current context before subsequent operation can take place (casting, assigning, pipelining).

 

As for performance differences, see this answer: | Out-Null is the slowest because it creates a pipeline which is a complex process; the other methods discard the output, no extras created.

Community
  • 1
  • 1
wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • +1 but you might want to make it more clear why 3 is never executed. I dabbled quite some time on why PS 3.0 would only correctly print 1. It just shows my lack of knowledge but I can't be the only one ;) – Lieven Keersmaekers Feb 23 '17 at 06:49