Search code examples
powershellconditional-operatorternary

Powershell 5.1 ternary with array assignment


I have a question towards ternary operators in Powershell 5.1. It doesn't work as I expected it if I try to assign an array @(...):

    # I can assign an array to a variable:
    $a=@("TRUE")
    write-host "a:" $a
    
    # I can do that in a proper if/then statement, too:
    $b = @(if ($false) {@("True")} else {@("False")})
    write-host "b:" $b
    
    # Assignment of string constants works fine with ternary syntax:
    $c = @( {"True"} , {"False"} )[!$true]
    write-host "c:" $c
    
    # but not with array assignments:
    $d = @( {@("True")} , {@("False")} )[!$false]
    write-host "d:" $d
    # Expected: "False". 
    # Actual output: @("False")

Output:

a: TRUE
b: False
c: "True"
d: @("False")

A thread regarding ternary operators doesn't clarify this for me. (Ternary operator in PowerShell)

Update: $d needs to be an array, as well as the two inner items. Here they were shown with just one string constant for simplicity.


Solution

  • Note:

    • PowerShell (Core) 7+ now has a built-in ternary operator, so that you could use something like $var = $true ? "True" : "False"

    Do not use { ... } around your operands: { ... } is used for script-block literals, which evaluate to their verbatim content (without the delimiters) in a string context.

    Omitting the enclosing { and } solves the immediate problem:

    $d = @( @("True") , @("False") )[!$false]
    write-host "d:" $d
    

    However, the use of @(), the array-subexpression operator seems both redundant and ineffective, depending on your intent; the above is equivalent to:

    $d = ( "True", "False" )[!$false]
    write-host "d:" $d
    

    Note that @(...) is never required for array literals; use of ,, the array constructor operator, is generally sufficient. See the middle section of this answer for more information.

    If you want $d to be an array, you need to apply @(...) to the entire expression:

    # $d is now a 1-element array containing 'False'
    $d = @(( "True", "False" )[!$false])
    write-host "d:" $d
    

    Alternatively, type-constrain $d to be an array:

    # $d is now a 1-element array containing 'False'
    [array] $d = ( "True", "False" )[!$false]
    write-host "d:" $d