When Do I Have to Put Double Quotes Around Parameter Values?

Ah, yes: the great double quote conundrum. Compared to, say, VBScript, Windows PowerShell is remarkably good at figuring at what it is you want to do. For example, this command returns the voice policy RedmondVoicePolicy:

Get-CsVoicePolicy "RedmondVoicePolicy"

So does this command:

Get-CsVoicePolicy 'RedmondVoicePolicy'

And so does this one:

Get-CsVoicePolicy RedmondVoicePolicy

In other words, it doesn’t seem to matter: single quotes, double quotes, no quotes – PowerShell always seems to figure out that you want to get back the RedmondVoicePolicy.

And yes, former VBScripters – who, on admittedly-rare occasions, have had to string 5 or 6 double quotes together (i.e., """""") – really should send the PowerShell team a thank-you note.

Now, to be honest, the reason any one of the preceding commands works is due, in part, to the fact that PowerShell’s command parser is pretty clever. However, it’s also due to the fact that we cheated a little; after all, we passed Get-CsVoicePolicy a very simple Identity, one that doesn’t include blank spaces or special characters. The fact of the matter is that, if you start throwing in special characters, well, at that point things get a little dicier. And when things start to get dicey, then it's time to start putting double quotes around your parameter values.

For example, one "special" character that PowerShell has problems with is the blank space. Suppose you have a policy named Redmond Voice Policy. What do you think will happen if you run this command:

Get-CsVoicePolicy Redmond Voice Policy

Hey, good guess; as it turns out, you are going to get this error message:

Get-CsVoicePolicy : A positional parameter cannot be found that accepts argument 'Voice'.

So what does that error message actually mean? Well, with Get-CsVoicePolicy, the Identity parameter is known as a "positional" parameter. That means you can leave off the –Identity portion of a command and, as long as the Identity is the very first parameter in that command, PowerShell will be able to figure things out and everything will work just fine. In other words, these two commands – one that includes the actual parameter name (Identity) and one that doesn't – are functionally identical:

Get-CsVoicePolicy -Identity RedmondVoicePolicy

Get-CsVoicePolicy RedmondVoicePolicy

Cool, huh? So then what's the problem with this command:

Get-CsVoicePolicy Redmond Voice Policy

Well, to begin with, one problem with the command Get-CsVoicePolicy Redmond Voice Policy is that PowerShell doesn’t see a parameter anywhere; remember, PowerShell parameters always have to start with a hyphen. (You know, like –Identity.) Because PowerShell doesn't see anything that starts with a hyphen, it assumes that you must be relying on a positional parameter. (You know, like –Identity.) As a result, Get-CsVoicePolicy assumes that you've left off –Identity (which is perfectly legal) and are using Redmond as the first parameter value; in other words, the cmdlet assumes that you’re looking for a voice policy with the Identity Redmond.

That's great. (Incorrect, but great.) PowerShell then looks for the next parameter; that is, for the next item that starts with a hyphen. Again, however, no such item can be found; all PowerShell sees is the value Voice. As a result, the cmdlet assumes that Voice is a parameter value for the second positional parameter. Unfortunately, though, that doesn’t make sense: Get-CsVoicePolicy doesn’t have a second positional parameter. As a result, the command blows up.

Which is probably what any one of us would do when put in a similar situation.

The fact of the matter is that blank spaces will almost always cause problems when used as parameter values; that’s because PowerShell uses blank spaces as its way of determining where one parameter/parameter value ends and the next one begins. But that’s OK; all you have to do is remember that, if you have a blank space in a parameter value, you just have to enclose that value in double quote marks, like so:

Get-CsVoicePolicy "Redmond Voice Policy"

And there you have it: blank spaces represent one occasion where you absolutely have to surround a parameter value in double quote marks.

Commas represent another occasion. Suppose you have a voice policy with this Identity: Redmond,WA. No blanks spaces means no problem, right? Well, let’s find out. Try running this command:

Get-CsVoicePolicy Redmond,WA

Disaster! This time around you get the following error message:

Get-CsVoicePolicy : Cannot convert 'System.Object[]' to the type 'Microsoft.Rtc.Management.Xds.XdsIdentity' required by the parameter 'Identity'. Specified method is not supported.

Well, that should clear everything up, eh?

OK, on the off-chance that this didn’t clear everything up, here’s what the error message means. Some PowerShell cmdlets allow you to enter multiple values for a single parameter. For example, if you want to use the Get-ChildItem cmdlet to return information from 3 separate folders you can use a command like this:

Get-ChildItem C:\Folder_A, C:\Folder_B, C:\Folder_C

Note. Of course that will work. Give it a try and see for yourself. And, just to make things more confusing, try it without spaces after the commas: it still works.

Notice the syntax of that command: three folder names, all separated by commas. For all intents and purposes, what we’re doing in that command is passing Get-ChildItem an array of folder names. That one command is equivalent to the following two commands:

$x = "C:\Folder_A", "C:\Folder_B", "C:\Folder_C"

Get-ChildItem $x

Note. Yes, we have to use double quotes here. That’s because we’re using the folder names in a variable assignment rather than a parameter value. If you assign a string value (like a folder name) to a variable you always have to enclose that value in double quotes (or single quotes; that’ll work, too).

That explains why using a parameter value like Redmond,WA fails, at least when using the Get-CsVoicePolicy cmdlet. In this example, Get-CsVoicePolicy thinks we’re passing it an array of policy Identities: one policy with the Identity Redmond and a second policy with the Identity WA. What's the problem with that? Well, Get-CsVoicePolicy can’t take an array as an Identity parameter value. Remember the error message we got? Silly question; who could forget an error message like this one:

Get-CsVoicePolicy : Cannot convert 'System.Object[]' to the type 'Microsoft.Rtc.Management.Xds.XdsIdentity' required by the parameter 'Identity'. Specified method is not supported.

If you look closely at the text in the error message you'll see the syntax System.Object[] ; this syntax indicates an array. (In PowerShell, [] always indicates an array.) The error message is telling us that it can’t convert an array to an Identity. And because Get-CsVoicePolicy can't accept an array of Identities the command blows up.

The workaround to all this? You guessed it: double quote marks. This command will return the Redmond,WA voice policy:

Get-CsVoicePolicy "Redmond,WA"

In other words, if your parameter value includes a comma then you need to enclose that value in double quote marks.

Just like you do if your parameter value includes a blank space.

Ah, good question: why do we keep saying "double quotes" when single quotes work just as well? Well, it's true that, in general, you can use either single quotes or double quotes. For example, either one of these commands returns the voice policy Redmond,WA, no questions asked:

Get-CsVoicePolicy "Redmond,WA"

Get-CsVoicePolicy 'Redmond,WA'

But consider this: a voice policy that has the Identity Administrator’s Policy. This command is going to work just fine:

Get-CsVoicePolicy "Administrator's Policy"

This command – well, let’s just say that this command isn’t going to work quite as well:

Get-CsVoicePolicy 'Administrator's Policy'

In fact, this command isn’t even going to fail, at least not right away. If you type in the preceding command and then press ENTER PowerShell will respond by showing you this:

>>

If you’ve never seen the >> prompt before, that’s PowerShell’s way of telling you that it’s waiting for the end of the command. If you press ENTER, PowerShell will respond by showing you this:

>>

And if you press ENTER again – well, let's put it this way: you're doomed. The truth is, this loop is going continue forever and ever and ever. Or at least until you press Ctrl+C.)

So what’s the deal here: why is PowerShell waiting for you to "finish" your command even though you already finished your command? Well, here’s why. Our command includes this string value:

'Administrator'

We know that the second single quote mark isn't really a single quote mark; it's an apostrophe. However, PowerShell doesn't know that; it has no idea what an apostrophe is. Instead, PowerShell sees a string value enclosed in a pair of single quote marks; consequently, PowerShell thinks this this is a separate parameter value. We then have this:

s Policy'

To the best of our knowledge, PowerShell has no idea what to make of that. However, it does see just one single quote mark and, when it comes to parameter values, single quote marks tend to travel in pairs. Therefore, it’s waiting for you to "finish" the command by entering the second single quote mark. And PowerShell will keep bugging you until you finally do enter that "concluding" quote mark.

Of course, as soon as you do you'll get the following error message:

Get-CsVoicePolicy : A positional parameter cannot be found that accepts argument 's'.

We won’t bother going into any more detail on this; you can probably figure it out on your own. And besides, that's not really the point; the point is, that if you have a parameter value that includes a single quote mark (i.e., an apostrophe) then you must enclose that value in double quotes rather than single quotes. For example:

Get-CsVoicePolicy "Administrator's Policy"

 

And yes, you do need to flip this around if – heaven forbid – you create a policy that has double quote marks in the Identity; for example, a policy that has the Identity "Test" Policy. In that case, you'll need to enclose the parameter value in single quote marks, like so:

Get-CsVoicePolicy '"Test" Policy'

Of course, the best thing to do is to avoid using special characters when creating Identities. (We’d even go so far as to suggest avoiding blank spaces.) And it's not necessarily a bad idea to get into the habit of enclosing all your string characters in double quotes marks. Do that and – outside of oddball exceptions like "Test" Policy – it should be smooth sailing.

There are one of two exceptions to everything we’ve told you so far. For example, there are times when only single quote marks will do. Here’s an example of creating a new voice normalization rule:

New-CsVoiceNormalizationRule -Parent SeattleUser -Name SeattleFourDigit -Description "Dialing with internal four-digit extension" -Pattern '^(\d{4})$' -Translation '+1206555$1'

Notice the value for the parameter Translastion: '+1206555$1'. This value must be enclosed in single quotes. If you don’t use single quotes, PowerShell will helpfully interpret the $1 at the end of the string as a variable. (Remember that all variables in PowerShell begin with a $.) Assuming you didn’t assign a value to a variable named $1, the value will be empty, so your Translation value will be interpreted as +1206555. We want the $1 to be included with the value, so we must enclose the entire string in single quotes.

Oh, and as long as we’re on the subject, we should mention the fact that special characters can also create some … interesting … issues when you’re working interactively with PowerShell. (That is, when PowerShell is prompting you for information and you’re typing in the requested data and pressing ENTER.) Because of that, it might be worth your while to take a look at Edwin Young’s two-part series %$#@ Special Characters!

This question is one of many asked during a session on managing Lync Server 2010 with Windows PowerShell at the TechReady 11 conference. For more questions and answers asked during that session, take a look at the Questions and Answers from TechReady 11 .