PowerShell ternary operator tips

Like you probably know, the PowerShell ternary operator ? : is the equivalent of the If/Then/Else statement.

The basic example you can find in the official documentation is:

$message = (Test-Path $path) ? "Path exists" : "Path not found"

However, if the ternary operator would be limited to displaying messages, its usefulness would be very limited…

Simple code

Let’s work on a simple situation: removing a file. The code could look like this:

(Test-Path -Path $File) ? remove-item -Path $File -Verbose : 'File has already been removed'

Unfortunately, when you intend to execute code after the question mark ? or the colon : it may not work as expected…

Error: At line:1 char:26
+ (Test-Path -Path $File) ? remove-item -Path $File -Verbose : ‘File ha …
+ ~
You must provide a value expression following the ‘?’ operator.
At line:1 char:27
+ (Test-Path -Path $File) ? remove-item -Path $File -Verbose : ‘File ha …
+ ~~~~~~~~~~~
Unexpected token ‘remove-item’ in expression or statement.

In this case, we just need to surround our code with parenthesizes.

(Test-Path -Path $File) ? (remove-item -Path $File -Verbose) : 'File has already been removed'

Line continuation

As you can notice in the former example, we already need to scroll to the side to read the whole line of code.

But like many operators in PowerShell, the question mark ? and the colon : are compatible with line continuation.

Our command line is now more readable:

(Test-Path -Path $File) ?
(remove-item -Path $File -Verbose) :
'File has already been removed'

Not using the third section

You have to provide the third section when you use the ternary operator.
However, you can reduce it to a minimum.
For example:

(Test-Path $File)?(New-Item -Path $File -Verbose):$Null

The line can also be shorter, but in this case, it will output an empty line.

(Test-Path $File)?(New-Item -Path $File -Verbose):''

Though, if you compare the former command line to the same one using the if statement instead, you can notice that the line with the ternary operator is longer.

if(Test-Path $File){New-Item -Path $File -Verbose}

Thus, if you want to type fewer characters and have no usage of the else statement, just use the if statement instead of the ternary operator.

Running more complex code

There are situations where you want to run more than a single command in the second section of the ternary operator statement, especially when your command doesn’t have a -Verbose parameter or when the -Verbose parameter never outputs anything.

Let’s work on an example with Remove-Item cmdlet.
However, though the -Verbose parameter of this cmdlet works fine, we will not use it and instead, we will display our own message, just for the demonstration.

$File = 'C:\test.txt'

(Test-Path -Path $File) ?
('Removing file...' ; Remove-Item -Path $File) :
'File has already been removed'

Unfortunately, we get an error:

Error: At line:1 char:46
+ (Test-Path -Path $File) ? (‘Removing file…’ ; remove-item -Path $Fi …
+ ~
Missing closing ‘)’ in expression.
At line:1 char:47
+ (Test-Path -Path $File) ? (‘Removing file…’ ; remove-item -Path $Fi …
+ ~
Missing ‘:’ in the ternary expression.
At line:1 char:72
+ … -Path $File) ? (‘Removing file…’ ; remove-item -Path $File) : ‘File …
+ ~
Unexpected token ‘)’ in expression or statement.

To avoid this error we need to wrap the code inside a script block { } and invoke it with the ampersand character &.

$File = 'C:\test.txt'
(Test-Path -Path $File) ?
(&{'Removing file...' ; Remove-Item -Path $File}) :
'File has already been removed'

And if you use line PowerShell line continuation capabilities:

$File = 'C:\test.txt'
(Test-Path -Path $File) ?
        'Removing file...'
        Remove-Item -Path $File
): 'File has already been removed'

And if you run it a second time in a row:

Best practices and use cases

This operator can be especially confusing because it looks like the alias of the Where-Object cmdlet. Thus, as a best practice don’t use the ternary operator in your scripts or functions.

General use case

There could theoretically be an infinite list of use cases.
However, the usage of the ternary operator seems to be intended for short command-lines.

Also, most of the time, you will probably use the ternary operator in the following way:

(<test if something has to be done>) ? (<doing the thing>) : (<displaying that the thing doesn't need to be done>)"

Example when I needed to unlock multiple times a user account:

(Get-ADUser -Identity  -pro LockedOut).LockedOut ?
(Unlock-ADAccount -Identity ) :
'Account not locked out'

Exceptions to the general use case

The registry will be one of the exceptions to my general case above. Usually, we have to test if a property exists, because depending on the result we have to use either the New-ItemProperty cmdlet or the Set-ItemProperty cmdlet.

$Key = 'HKLM:\SOFTWARE\Luke'
$Params = @{Path = $Key; Name = 'ValueName'}

(Get-ItemProperty @Params -ErrorAction SilentlyContinue)?
(Set-ItemProperty @Params -Value 'ValueData'-Verbose):
(New-ItemProperty @Params -Value 'ValueData' -PropertyType 'String' -Verbose)

And if I run the same command a second time in a row:

Leave a Reply

Please log in using one of these methods to post your comment:

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