2

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.

jamacoe
  • 519
  • 4
  • 16

1 Answers1

3

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
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    Thank you, it worked. The concret application was to eliminate element number x from array $a by joining the preceeding and succeeding parts: $LastElement = $a.GetUpperBound(0); if ($LastElement -ge 0) { $a = @(@(@(),@($a[0..($x-1)]))[$x -ne 0]; @(@(), @($a[($x+1)..$LastElement]))[$x -ne $LastElement]) } – jamacoe Aug 02 '21 at 16:37