Escaping quotes in powershell.exe -command via command prompt
An interesting situation came up recently that involved having to execute a PowerShell script through the cmd.exe command prompt. It sounds pretty simple, after all you can simply run powershell.exe –file “<path_to_script>” and call it a day. That wasn’t the case here though because the –File parameter is only available in PowerShell V2 and this situation was dealing with V1. The only option then is to use the -command argument of powershell.exe and to execute the necessary code. This works great, but if you need to include a string with quotes, you may have some trouble.
Scroll to the end for the summary if you just want to see how to properly get quotes into your powershell.exe -command argument.
Within PowerShell, it is incredibly simple to execute a script (assuming your script is signed or you have the execution policy set appropriately). There are a few gotchas that people get caught up on when they are starting out with PowerShell so I’ll quickly cover them first.
We want to execute the script, so we just provide the full path to the script and hit enter, right?
That didn’t work because of the spaces in the path. Ok, then we just proceed like we would in a command prompt and put the path in quotes, right?
Unfortunately that doesn’t work either because now you are just telling PowerShell “Hey, here is a string” and it simply spits it back out to you. The correct procedure is to use the Call operator with the entire path in quotes and it should work out fine.
Then, if we want to use the environment variable for the program files directory, we can just do the following:
Now that we know the proper command syntax, we need to switch over to a command prompt, since this script has to be executed from there. We know that powershell.exe can accept a –Command parameter which should allow us to execute the same command we just figured out within the PowerShell prompt.
That doesn’t work, but what exactly is going on here? Based on the output of the error, we can see that the environment variable is being expanded appropriately, but it looks like everything past “script” is being interpreted as an additional parameter. With this in mind, it seems like it’s a simple matter of having to escape the quotation marks around the path of the script to make sure it’s interpreted as a single value. Because we are in a dos prompt though, the first thought might be to use a caret (^) to escape the quotes, which is something we do all the time in batch files.
That doesn’t work either, but the error is slightly different this time. Instead of the intended result of having a quotation mark, the quotes are actually dropped and the caret is inserted. So clearly the caret didn’t help, so next we try the PowerShell escape character, the grave accent (`). This may make more sense because the logic is that whatever is inside the outer quotes, gets passed into the PowerShell executable, then the rest of it gets interpreted. Therefore we need PowerShell to be aware of what we are doing.
Interestingly, the environment variable isn’t being expanded now; additionally the grave accent isn’t being passed at all. It’s as if PowerShell is completely disregarding the text we are inputting.
So what is actually going on here? As it turns out, we aren’t dealing with an issue with choosing the right escape character for DOS, or the right escape character for PowerShell. The problem is that we need to use an escape character that the PowerShell argument parser can understand. The powershell.exe binary isn’t a batch file or powershell script, it is an actual compiled program and as such has to actually parse the arguments that are given to it. With that in mind, we need to use the appropriate escape character, the backslash (\).
So what is the conclusion here? When trying to execute a command in PowerShell via the -Command argument of powershell.exe, be sure to escape your quotes with the C style back slash.
This behavior is by design, there is no doubt there. Ultimately, it all comes down to how the application (powershell.exe in our case) parses the command line arguments. PowerShell handles it this way whereas another app could in theory have it’s own, completely made-up, set of escape characters for arguments that are enclosed in quotes. While it may be confusing when trying to execute commands via the PowerShell binary, this actually is logical behavior when you think about it, and once you are aware of how it works, you will likely never forget.