Search code examples
stringpowershellparameters

When do values passed to a parameter require quotes?


I have been working with Exchange Online unified groups and Microsoft Teams teams in powershell: New-UnifiedGroup, Set-UnifiedGroup, Get-UnifiedGroup, New-Team, Get-Team etc. I have been creating groups and teams from PowerShell.

I am interested in understanding a bit better when a value for a parameter requires quotes and when it does not.

When I import from CSV, it seems the values are automatically interpreted as strings. When I supply them to a parameter that requires a string, the value does not require quotes even if it has spaces e.g New-UnifiedGroup -DisplayName $item.displayName does not require quotes even when the display name has spaces.

But when I want to create a team from an existing group, and I get the ID of the group, the group id requires quotes: New-Teams -GroupId "$group.ExternalDirectoryObjectId". In this case the parameter -GroupId requires a string value, although the ExternalDirectoryObjectId that it requires is not a string.

Is there a rule that a value does not require quotes if it is a string, and a string value is expected? Does it help to declare a variable as a string before passing it to a parameter that requires a string? For example, if I have a $path variable, I usually have to provide it as -Path "$path". If I declared the path as [String]$path =, would I then not need to use the quotes in -Path $path


Solution

    • Generally, only ever use quoting in PowerShell to explicitly pass a value as a string ([string]).

      • String-literal arguments require quoting if they contain any of the following: spaces or, more generally, PowerShell metacharacters[1], as well as commands or expressions (enclosed in $(...)) if they are part of a larger string (see below).

      • If a string-literal argument is to be used verbatim, use '...' i.e. enclose it in a single-quoted aka verbatim string (use '' to embed a literal ').

    • To pass the value of a variable, one of its properties, or even the result of a method call on it, you do not need quoting in PowerShell (except as part of a larger string - see below), which will pass the resulting value with its original data type; however, when the value is bound to its target parameter, PowerShell may automatically convert it to the parameter's type.

      • If the target parameter is [string]-typed (as is the case with New-Team's -GroupId parameter), PowerShell will automatically convert any non-string argument to a string, essentially by calling .ToString() on it[2]. If the resulting string isn't the right representation, you must perform explicit stringification, by way of an expression or command.

      • E.g., both -GroupId $groupId and -GroupId $group.ExternalDirectoryObjectId work without quoting - even if the string value being passed contains embedded spaces or other PowerShell metacharacters.

    • If you need to pass an object's property, a method call, or any type of command or expression as part of a larger string, enclose the argument in "..." (i.e. a double-quoted, so-called expandable (interpolating) string) (use `" or "" to embed a literal ") and use $(...), the subexpression operator around the expression / command; e.g., "$($group.ExternalDirectoryObjectId)/more"; referencing a variable (including an environment variable) by itself inside "..." does not require $(...); e.g. "$HOME\Project" or "user:$env:USERNAME".

      • Note that "$group.ExternalDirectoryObjectId" definitely does not work as intended, because only variable reference $group by itself is recognized - and stringified - whereas the .ExternalDirectoryObjectId part is treated literally - see first link below for why.

      • A variable-as-a-whole reference preceded or followed by a literal - e.g. $HOME\projects or user:$env:USERNAME - does not strictly need double-quoting, but to avoid edge cases it's better to use it.

    Further reading:


    [1] The metacharacters are (some only need quoting if at the start of the argument):
    <space> ' " ` , ; ( ) { } | & < > @ #

    [2] The exact stringification rules, where culture-sensitivity factors in as well, are detailed in this answer.
    Generally, PowerShell has a very flexible automatic type-conversion system whose rules are complex and not explicitly documented - a peek at the source code may help.
    PowerShell always tries to automatically convert a given value to the target type, where the target type may be dictated by a parameter's type or the (usually) LHS operand of an operator-based expression (e.g., 42 + "1" yields 43).