Can I Quote You on That? Quoting and Variable Expansion in PowerShell
Recently on Twitter there was a brief flurry of tweets regarding best practices when it came to using quotes in PowerShell. That is to say, whether it is better of use single or double quotes. I had my opinion, which surprisingly was at odds with most people so I thought I would revisit the topic. Especially because using quotes throws many beginning PowerShell users.
Quoting and Variable Expansion in PowerShell
First, PowerShell is pretty smart at determining what is a string or text. If you look at cmdlet help, most parameters accept values that will be treated as strings. This means you can run any one of these commands and they will all work.
get-eventlog -LogName system -newest 5 -ComputerName chi-dc04 get-eventlog -LogName "system" -newest 5 -ComputerName "chi-dc04" get-eventlog -LogName 'system' -newest 5 -ComputerName 'chi-dc04'
For any string that doesn’t contain a space, if PowerShell knows how to treat it as a string, I don’t think you need to include any quotes. But when there are spaces, this is where it gets interesting. Again, if you have simple text, PowerShell doesn’t really care if you use ” or “”. Both of these commands will give you the same result.
get-service -DisplayName "Windows Update" get-service -DisplayName 'Windows Update'
Now, what happens when you throw a simple variable in the mix.
PS C:> $n = "Jeff" PS C:> "The current user is $n" The current user is Jeff PS C:> 'The current user is $n' The current user is $n
More on Using Quotes in PowerShell
This is the interesting part of quoting in PowerShell. When you use double quotes, PowerShell will automatically expand the variable with its value. Thus in the first example with double quotes, $n is replaced with its value ‘Jeff’, while in the second example it is not. On Twitter, this behavior was the driving factor behind a recommended best practice. The consensus was to always use single quotes so that you don’t unintentionally expand variables.
However, I always looked at this from the other perspective. If I always use double quotes, then variables will always be expanded if they are in the string. I don’t want someone new to PowerShell to have to figure out whether to use single or double quotes. The question about accidentally expanding a variable puzzles me. Isn’t that the whole point? Now, it may be that your position depends on whether you are approaching PowerShell from a developer or IT pro perspective. I’m definitely in the latter camp.
What is “Inside Microsoft Teams”?
“Inside Microsoft Teams” is a webcast series, now in Season 4 for IT pros hosted by Microsoft Product Manager, Stephen Rose. Stephen & his guests comprised of customers, partners, and real-world experts share best practices of planning, deploying, adopting, managing, and securing Teams. You can watch any episode at your convenience, find resources, blogs, reviews of accessories certified for Teams, bonus clips, and information regarding upcoming live broadcasts. Our next episode, “Polaris Inc., and Microsoft Teams- Reinventing how we work and play” will be airing on Oct. 28th from 10-11am PST.
However, variable expansion with double quotes isn’t always easy. This is something else that often trips up beginners. Let’s say you are building a string to display as a message or write to a log file that will show the state of a service and its display name. You most likely will save the service information to a variable.
$s = get-service wuauserv
You might think all you need to do is write a string like this, using the service properties from $s.
PS C:> "The $s.displayname service is currently $s.status" The System.ServiceProcess.ServiceController.displayname service is currently System.ServiceProcess.ServiceController.status
Not what you might have expected. While we’re at it, here’s the same string but using single quotes.
PS C:> 'The $s.displayname service is currently $s.status' The $s.displayname service is currently $s.status
Still not what I want, but perhaps easier to read. To solve this problem, we need to use something called a sub-expression.
PS C:> "The $($s.displayname) service is currently $($s.status)" The Windows Update service is currently Stopped
Wrap it Up! Use Parentheses to Enclose the Object and Property
The way I tell people to remember this is that by wrapping the object and property in parentheses, PowerShell evaluates that expression and holds the result in memory. Sticking a $ in front of it tells PowerShell, “Look, here’s a variable” and because I’m using double quotes it is expanded. And yes, there are other ways to build strings, which I’m not going to cover now. The point is that if I still use single quotes, I don’t get the expansion.
PS C:> 'The $($s.displayname) service is currently $($s.status)' The $($s.displayname) service is currently $($s.status)
Sometimes, you need to use both single and double quotes. Consider the case where you are writing a script that is building a WMI filter on the fly. You would need to write the command like this:
get-wmiobject win32_service -filter "Name='spooler'"
The filter parameter is expecting a string, which I define with double quotes. The filtering value for name must also be quote for WMI and here I use single quotes. If you try either of these approaches, the command will fail:
get-wmiobject win32_service -filter "Name="spooler"" get-wmiobject win32_service -filter 'Name='spooler''
Although you can work around this by adding more quotes
get-wmiobject win32_service -filter "Name=""spooler""" get-wmiobject win32_service -filter 'Name=''spooler'''
But I don’t recommend this technique as it is difficult to construct especially with more complex filters. If you are using variables, you can still take advantage of expansion.
$n='spooler' get-wmiobject win32_service -filter "Name='$n'"
Even though $n is inside single quotes, the entire string is in double quotes so it gets expanded.
Using Quotes in PowerShell: The Final Word?
So what’s the best practice when it comes to quoting? Frankly I’m not sure. I think much depends on how you approach PowerShell and how you intend to use it. If you always use double quotes, simple string will still work and if the string contains a variable, it will automatically be expanded. Just remember that for rich variables, those with multiple properties, you will need to use a sub expression. If you single quotes, you may not get the result you expect, but it might be easier to read. And perhaps your preference will change over time. As a beginner you might appreciate the simplicity of only using double quotes until you have a better idea on how PowerShell works.
To learn more about this topic, be sure to read the PowerShell help topic about_Quoting_Rules.