Using Pipeline Chain Operators in PowerShell 7

We all know how pipeline is an important and useful feature of PowerShell. It makes it incredibly easy to take output from one expression / cmdlet and pass it to another expression / cmdlet. It has also allowed to chain them together to create complex expressions. However, what was lacking is the ability to conditionally execute the expressions on the right side of the pipeline operator like the more modern versions of Bash shell. PowerShell 7 covers this gap by introducing Pipeline Chain Operators || and &&. These operators allow the conditional execution of commands or expressions depending on whether the previous command / expression succeeded for failed.

Life Before PowerShell 7

The operators && and || have been reserved to be implemented for future versions. So if you would have used them, you would encountered error that these operators are not available in this version of PoweShell:

In Zeile:1 Zeichen:22
 Write-Output "Hello" || Write-OutPut "World"
 ~~
 Das Token "||" ist in dieser Version kein gültiges Anweisungstrennzeichen.
 In Zeile:2 Zeichen:22
 Write-Output "Hello" && Write-OutPut "World"
 ~~ Das Token "&&" ist in dieser Version kein gültiges Anweisungstrennzeichen. CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
 FullyQualifiedErrorId : InvalidEndOfLine 

So, one would end up using below syntax:

#region: Before PS7

# this does not works -
Write-Output "Hello" || Write-Output "World"
# this works - 
Write-Output "Hello"
if (-not $?){
    Write-Output "World"
}

# this does not works -
Write-Output "Hello" && Write-Output "World"
# this works -
Write-Output "Hello"
if ($?){
    Write-Output "World"
}
#endregion

Life After PowerShell 7

Using && Operator

It is used to run the command following && only if the command preceding the operator is successful. So below commands are executed as you have thought:

# using && operator
# executes both left-hand and right-hand command
Write-Output "Hello" && Write-Output "World"
$true && Write-Output "foo"

But what about below code:

# something wrong here -- note use of exit status: $?
Write-Error "Hello" && Write-Output "World"

Do note that the whether the command is successful or not is indicated by the last exit status: $?. So when we used write-error, it set it to error and second command did not get executed.

Same goes for below code:

# executes both left-hand and right-hand command
$false && Write-Output "foo"

Again, executing $false in itself is not an error:

Using || Operator

Use to run the command following || only if the command preceding || fails. So below commands are executed as you have thought:

# using || operator
# executes only left-hand expression
Write-Output "Hello" || Write-Output "World"
$true || Write-Output "foo"

Again, the below code will also execute only-left expression as executing $false is not an error in itself:

# executes only left-hand expression as exit status of $false is success 
$false || Write-Output "foo"

And below code will execute both left-hand and right-hand expressions as Write-Error throws an error:

# executes both left-hand and right-hand expressions
Write-Error "Hello" || Write-Output "World"

Stretching the use-case

We can chain various pipeline operators as long as we like. Note that these operators are left-associative i.e. the expressions on the left-hand side gets executed first. Consider below code:

# writes only "foo" to stdout 
$false && Write-Output foo || Write-Output bar 

In above code, executing $false in itself is success, which will allow to execute Write-Output foo, hence leading to skip execution of Write-Output bar.

However the output may not always be intuitive. Consider below code:

# writes only "bar" to stdout
$true || Write-Output foo && Write-Output bar 

In above code, executing $true in itself is success, leading to skip execution of Write-Output foo. However, combination of these two is success, hence leading to execution of Write-Output bar.

So far, we have used simple expressions, but you can use complex expressions as well. Also, note that these operators have lower precedence than pipeline operator | itself. It would be better to make use of parenthesis operator () to clearly segregate expression of commands.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s