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…
+ (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:
+ (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: