Ternary operator in PowerShell

PowershellTernary OperatorConditional Operator

Powershell Problem Overview


From what I know, PowerShell doesn't seem to have a built-in expression for the so-called ternary operator.

For example, in the C language, which supports the ternary operator, I could write something like:

<condition> ? <condition-is-true> : <condition-is-false>;

If that doesn't really exist in PowerShell, what would be the best way (i.e. easy to read and to maintain) to accomplish the same result?

Powershell Solutions


Solution 1 - Powershell

$result = If ($condition) {"true"} Else {"false"}

For use in or as an expression, not just an assignment, wrap it in $(), thus:

write-host  $(If ($condition) {"true"} Else {"false"}) 

Solution 2 - Powershell

Powershell 7 has it. https://toastit.dev/2019/09/25/ternary-operator-powershell-7/

PS C:\Users\js> 0 ? 'yes' : 'no'
no
PS C:\Users\js> 1 ? 'yes' : 'no'
yes

Solution 3 - Powershell

The closest PowerShell construct I've been able to come up with to emulate that is:

@({'condition is false'},{'condition is true'})[$condition]

Solution 4 - Powershell

Per this PowerShell blog post, you can create an alias to define a ?: operator:

set-alias ?: Invoke-Ternary -Option AllScope -Description "PSCX filter alias"
filter Invoke-Ternary ([scriptblock]$decider, [scriptblock]$ifTrue, [scriptblock]$ifFalse) 
{
   if (&$decider) { 
      &$ifTrue
   } else { 
      &$ifFalse 
   }
}

Use it like this:

$total = ($quantity * $price ) * (?:  {$quantity -le 10} {.9} {.75})

Solution 5 - Powershell

Try powershell's switch statement as an alternative, especially for variable assignment - multiple lines, but readable.

Example,

$WinVer = switch ( Test-Path "$Env:windir\SysWOW64" ) {
  $true    { "64-bit" }
  $false   { "32-bit" }
}
"This version of Windows is $WinVer"

Solution 6 - Powershell

I too, looked for a better answer, and while the solution in Edward's post is "ok", I came up with a far more natural solution in this blog post

Short and sweet:

# ---------------------------------------------------------------------------
# Name:   Invoke-Assignment
# Alias:  =
# Author: Garrett Serack (@FearTheCowboy)
# Desc:   Enables expressions like the C# operators: 
#         Ternary: 
#             <condition> ? <trueresult> : <falseresult> 
#             e.g. 
#                status = (age > 50) ? "old" : "young";
#         Null-Coalescing 
#             <value> ?? <value-if-value-is-null>
#             e.g.
#                name = GetName() ?? "No Name";
# 			  
# Ternary Usage:  
#         $status == ($age > 50) ? "old" : "young"
#
# Null Coalescing Usage:
#         $name = (get-name) ? "No Name" 
# ---------------------------------------------------------------------------

# returns the evaluated value of the parameter passed in, 
# executing it, if it is a scriptblock   
function eval($item) {
	if( $item -ne $null ) {
		if( $item -is "ScriptBlock" ) {
			return & $item
		}
		return $item
	}
	return $null
}

# an extended assignment function; implements logic for Ternarys and Null-Coalescing expressions
function Invoke-Assignment {
	if( $args ) {
		# ternary
		if ($p = [array]::IndexOf($args,'?' )+1) {
			if (eval($args[0])) {
				return eval($args[$p])
			} 
			return eval($args[([array]::IndexOf($args,':',$p))+1]) 
		}
		
		# null-coalescing
		if ($p = ([array]::IndexOf($args,'??',$p)+1)) {
			if ($result = eval($args[0])) {
				return $result
			} 
			return eval($args[$p])
		} 
		
		# neither ternary or null-coalescing, just a value  
		return eval($args[0])
	}
	return $null
}

# alias the function to the equals sign (which doesn't impede the normal use of = )
set-alias = Invoke-Assignment -Option AllScope -Description "FearTheCowboy's Invoke-Assignment."

Which makes it easy to do stuff like (more examples in blog post):

$message == ($age > 50) ? "Old Man" :"Young Dude" 

Solution 7 - Powershell

As of PowerShell version 7, the ternary operator is built into PowerShell.

1 -gt 2 ? "Yes" : "No"
# Returns "No"

1 -gt 2 ? 'Yes' : $null
# Get a $null response for false-y return value

Solution 8 - Powershell

Since a ternary operator is usually used when assigning value, it should return a value. This is the way that can work:

$var=@("value if false","value if true")[[byte](condition)]

Stupid, but working. Also this construction can be used to quickly turn an int into another value, just add array elements and specify an expression that returns 0-based non-negative values.

Solution 9 - Powershell

The ternary operator in PowerShell was introduced with the PowerShell version7.0.

[Condition] ? (output if True) : (output if False)

Example 01

$a = 5; $b = 6
($a -gt $b) ? "True" : "False"

Output

False

Example 02

($a -gt $b) ? ("$a is greater than $b") : ("$a is less than $b")

Output

5 is less than 6

more information https://www.tutorialspoint.com/how-ternary-operator-in-powershell-works

Solution 10 - Powershell

Since I have used this many times already and didn't see it listed here, I'll add my piece :

$var = @{$true="this is true";$false="this is false"}[1 -eq 1]

ugliest of all !

kinda source

Solution 11 - Powershell

I've recently improved (open PullRequest) the ternary conditional and null-coalescing operators in the PoweShell lib 'Pscx'
Pls have a look for my solution.


My github topic branch: UtilityModule_Invoke-Operators

Functions:
Invoke-Ternary
Invoke-TernaryAsPipe
Invoke-NullCoalescing
NullCoalescingAsPipe
Aliases
Set-Alias :?:   Pscx\Invoke-Ternary                     -Description "PSCX alias"
Set-Alias ?:    Pscx\Invoke-TernaryAsPipe               -Description "PSCX alias"
Set-Alias :??   Pscx\Invoke-NullCoalescing              -Description "PSCX alias"
Set-Alias ??    Pscx\Invoke-NullCoalescingAsPipe        -Description "PSCX alias"

###Usage

<condition_expression> |?: <true_expression> <false_expression>

<variable_expression> |?? <alternate_expression>

As expression you can pass:
$null, a literal, a variable, an 'external' expression ($b -eq 4) or a scriptblock {$b -eq 4}

If a variable in the variable expression is $null or not existing, the alternate expression is evaluated as output.

Solution 12 - Powershell

PowerShell currently doesn't didn't have a native Inline If (or ternary If) but you could consider to use the custom cmdlet:

IIf <condition> <condition-is-true> <condition-is-false>
See: https://stackoverflow.com/questions/25682507/powershell-inline-if-iif

Solution 13 - Powershell

If you're just looking for a syntactically simple way to assign/return a string or numeric based on a boolean condition, you can use the multiplication operator like this:

"Condition is "+("true"*$condition)+("false"*!$condition)
(12.34*$condition)+(56.78*!$condition)

If you're only ever interested in the result when something is true, you can just omit the false part entirely (or vice versa), e.g. a simple scoring system:

$isTall = $true
$isDark = $false
$isHandsome = $true

$score = (2*$isTall)+(4*$isDark)+(10*$isHandsome)
"Score = $score"
# or
# "Score = $((2*$isTall)+(4*$isDark)+(10*$isHandsome))"

Note that the boolean value should not be the leading term in the multiplication, i.e. $condition*"true" etc. won't work.

Solution 14 - Powershell

Here's an alternative custom function approach:

function Test-TernaryOperatorCondition {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true, Mandatory = $true)]
        [bool]$ConditionResult
        ,
        [Parameter(Mandatory = $true, Position = 0)]
        [PSObject]$ValueIfTrue
        ,
        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateSet(':')]
        [char]$Colon
        ,
        [Parameter(Mandatory = $true, Position = 2)]
        [PSObject]$ValueIfFalse
    )
    process {
        if ($ConditionResult) {
            $ValueIfTrue
        }
        else {
            $ValueIfFalse
        }
    }
}
set-alias -Name '???' -Value 'Test-TernaryOperatorCondition'

Example

1 -eq 1 |??? 'match' : 'nomatch'
1 -eq 2 |??? 'match' : 'nomatch'

Differences Explained

  • Why is it 3 question marks instead of 1?
  • The ? character is already an alias for Where-Object.
  • ?? is used in other languages as a null coalescing operator, and I wanted to avoid confusion.
  • Why do we need the pipe before the command?
  • Since I'm utilising the pipeline to evaluate this, we still need this character to pipe the condition into our function
  • What happens if I pass in an array?
  • We get a result for each value; i.e. -2..2 |??? 'match' : 'nomatch' gives: match, match, nomatch, match, match (i.e. since any non-zero int evaluates to true; whilst zero evaluates to false).
  • If you don't want that, convert the array to a bool; ([bool](-2..2)) |??? 'match' : 'nomatch' (or simply: [bool](-2..2) |??? 'match' : 'nomatch')

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmguassaView Question on Stackoverflow
Solution 1 - PowershellfbehrensView Answer on Stackoverflow
Solution 2 - Powershelljs2010View Answer on Stackoverflow
Solution 3 - PowershellmjolinorView Answer on Stackoverflow
Solution 4 - PowershellEdward BreyView Answer on Stackoverflow
Solution 5 - PowershellnudlView Answer on Stackoverflow
Solution 6 - PowershellGarrett SerackView Answer on Stackoverflow
Solution 7 - Powershelluser189198View Answer on Stackoverflow
Solution 8 - PowershellVesperView Answer on Stackoverflow
Solution 9 - PowershellkrisView Answer on Stackoverflow
Solution 10 - PowershellsodawillowView Answer on Stackoverflow
Solution 11 - PowershellandiDoView Answer on Stackoverflow
Solution 12 - PowershelliRonView Answer on Stackoverflow
Solution 13 - PowershellnmbellView Answer on Stackoverflow
Solution 14 - PowershellJohnLBevanView Answer on Stackoverflow