Search code examples
powershellsyntaxstring-interpolation

PowerShell string interpolation syntax


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?


Solution

  • tl;dr

    Inside "...":

    • $(...) is only needed to embed entire expressions or commands (e.g. "$($PSVersionTable.PSVersion)")

    • ${...} is only needed if a stand-alone reference to a variable that has a regular name needs delimiting (disambiguation), so that subsequent characters in the string aren't interpreted as part of the variable name (e.g, "${foo}_bar" correctly embeds variable $foo; without {...}, PowerShell would look for variable $foo_bar; notably, a subequent : requires this technique too: "${foo}:bar")

    Independently of use in "...", ${...} is also needed for variable names containing special characters (e.g. ${a-b} = 42)

    For a comprehensive overview of PowerShell's expandable strings (string interpolation), see this answer.


    Background information:

    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 -.

    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.