3

So I have the following powershell script...using the ternary operator of Powershell and I'm starting to doubt it's power:

PS> $dasName="vCs01"

PS> $specialSubDerr @{
    "VCS01"="Derr";
    "VSC02"="dir";
    }

PS> $subDerr = @({"default"},{"$($specialSubDerr[$dasName.ToUpper()])"})[$specialSubDerr.contains($dasName.ToUpper())]
PS> $subDerr
"$($specialSubDerr[$dasName])"

PS> $($specialSubDerr[$dasName.ToUpper()])
Derr

So in the last 2 lines executed, why isn't the value assigned to $subDerr?

leeand00
  • 25,510
  • 39
  • 140
  • 297

1 Answers1

4

using the ternary operator of Powershell

Your code does not use PowerShell's ternary operator, which is available only in v7.0+; instead it uses a suboptimal emulation that combines a 2-element array with a conditional whose Boolean result is mapped onto array index 0 (for $false) or 1 (for $true).
Aside from not being conceptually obvious, the workaround is suboptimal in that it doesn't short-circuit the evaluation of the alternatives; that is, both elements of the array are unconditionally evaluated before one is chosen.

Note:

  • You don't need @(...) for array literals - it is inefficient in PowerShell versions up to 5.0, but, more importantly, it invites conceptual confusion by falsely suggesting that it constructs arrays - see the bottom section of this answer.

  • Don't use $(...) for single commands or expressions, except inside expandable strings ("...") and/or if you need to embed multiple statements in another statement.

  • PowerShell is case-insensitive by default, so there is no need to case-normalize the keys of hashtable entries with .ToUpper().

  • {...} defines a script block, which is a reusable piece of PowerShell code that you can execute on demand later, typically via &, the call operator; by itself, a script block prints as its stringified value, which is the literal contents between the opening { and the closing }; do not use script blocks as-is if you want to output values.


In PowerShell [Core] 7.0+, you can use the null-coalescing operator ?? to get what you want:

$subDerr = $specialSubDerr[$dasName] ?? 'default'

Note: Strictly speaking, the above also selects 'default' if an entry with key $dasName exists, but happens to be have value $null.

Alternatively, using the ternary conditional:

$subDerr = $specialSubDerr.Contains($dasName) ? $specialSubDerr[$dasName] : 'default'

In earlier versions, using the emulation of a ternary conditional (the fixed version of what you tried):

$subDerr = ('default', $specialSubDerr[$dasName])[$specialSubDerr.Contains($dasName)]

or, more explicitly (with short-circuiting):

$subDerr = if ($specialSubDerr.Contains($dasName)) { $specialSubDerr[$dasName] }
           else                                    { 'default' }
mklement0
  • 382,024
  • 64
  • 607
  • 775