102

I always used the following syntax to be sure that variable were expanded in a string:

"my string with a $($variable)"

I recently ran into the following syntax:

"my string with a ${variable}"

Are they equivalent? Any difference?

mklement0
  • 382,024
  • 64
  • 607
  • 775
fra
  • 3,488
  • 5
  • 38
  • 61
  • 16
    `$()` is the sub-expression operator. It can enclose complex expressions or simple things like accessing member properties. `${}` syntax is for when variable names have special symbols that otherwise standard `$variable` won't evaluate properly. – AdminOfThings Feb 20 '20 at 15:22
  • 3
    $() can also be used outside of strings to bring together multiple pipelines separated by a ";". – js2010 Feb 20 '20 at 15:52
  • If anyone else here runs across issues with string interpolation, especially with nested hash table keys and values, I recommend setting the element you want to access as a temp variable with something like `.ToString()` or whatever data type would be appropriate. I wasted a lot of time trying to figure out why `Write-Output` was getting very different strings than the actual strings I was attempting to access, which showed up just fine when output to console directly. – kayleeFrye_onDeck Apr 05 '23 at 22:25

3 Answers3

136

To complement marsze's helpful answer:

${...} (enclosing the variable name in { and }) is indeed always necessary if a variable name contains special characters, such as spaces, ., or -.

  • Not special are _ and - surprisingly and problematically - ?.
  • Note: : is invariably interpreted as terminating a PowerShell drive reference, in the context of namespace variable notation, or a scope specifier, irrespective of whether {...} enclosure is used or required (e.g., in $env:USERNAME or ${env:USERNAME}, env refers to the PowerShell drive representing all environment variables; in $script:foo or ${script:foo}, script refers to the script's scope and its variables).

Note:

  • ${...} - the syntax for disambiguating a variable name - is not to be confused with $(...), the subexpression operator, which is needed to embed any expression or command that goes beyond a stand-alone variable reference inside "...", an expandable (interpolating) string.
  • As such, these two syntax forms are independent of one another and may need to be combined in a given situation; e.g. "$var" / "${var}" work fine, but "$var.someProperty" / "${var}.someProperty" do not: you need "$($var.someProperty)" / "$(${var}.someProperty)"

In the context of "...", there is another reason to use ${...}, even if the variable name itself doesn't need it:

If you need to delineate the variable name from directly following non-whitespace characters, notably including ::

$foo = 'bar'  # example variable

# INCORRECT: PowerShell assumes that the variable name is 'foobarian', not 'foo'
PS> "A $foobarian."
A .  # Variable $foobarian doesn't exist -> reference expanded to empty string.

# CORRECT: Use {...} to delineate the variable name:
PS> "A ${foo}barian."
A barbarian.

# INCORRECT: PowerShell assumes that 'foo:' is a *namespace* (drive) reference
#            (such as 'env:' in $env:PATH) and FAILS:
PS> "$foo: bar"
Variable reference is not valid. ':' was not followed by a valid variable name character. 
Consider using ${} to delimit the name.

# CORRECT: Use {...} to delineate the variable name:
PS> "${foo}: bar"
bar: bar

See this answer for a comprehensive overview of PowerShell string-expansion rules.

Note that you need the same technique when string expansion is implicitly applied, in the context of passing an unquoted argument to a command; e.g.:

# INCORRECT: The argument is treated as if it were enclosed in "...",
#            so the same rules apply.
Write-Output $foo:/bar

# CORRECT
Write-Output ${foo}:/bar

Finally, a somewhat obscure alternative is to `-escape the first character after the variable name, but the problem is that this only works as expected with characters that aren't part of escape sequences (see about_Special_Characters):

# OK: because `: is not an escape sequence.
PS> "$foo`: bar"
bar: bar

# NOT OK, because `b is the escape sequence for a backspace character.
PS> "$foo`bar"
baar # The `b "ate" the trailing 'r' of the variable value
     # and only "ar" was the literal part.
mklement0
  • 382,024
  • 64
  • 607
  • 775
24

Note that $() is helpful for json objects:

"My json property is $($jsonObj.property)"
derekantrican
  • 1,891
  • 3
  • 27
  • 57
  • 3
    This is what I needed for ordinary PowerShell expressions, too. – Grault Jul 01 '22 at 18:52
  • 5
    To elaborate on @Grault's comment: `{` and `}` in `${var}` are syntax elements in the context of referencing a _variable_ alone, to disambiguate its _name_. By contrast, `$(...)` is the subexpression _operator_. As such, the two syntax forms are independent of one another and may need to be _combined_ in a given situation. You need `$(...)` inside `"..."` for any expression that goes _beyond_ a _stand-alone_ variable reference; e.g. `"$var"` / `"${var}"` work fine, but `"$var.someProperty"` / `"${var}.someProperty"` do _not_: you need `"$($var.someProperty)"` / `"$(${var}.someProperty)"` – mklement0 Aug 24 '22 at 13:37
22

${variable} is the syntax for variable names that include special characters.

(See about_Variables -> Variable names that include special characters )

Example:

${var with spaces} = "value"
"var with spaces: ${var with spaces}"

So in your case it's basically the same as simply writing $variable

marsze
  • 15,079
  • 5
  • 45
  • 61