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
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:
Overview of PowerShell's expandable strings (string interpolation, "..."
)
[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
).