Invoking a PowerShell script from cmd.exe (or Start | Run)
Earlier today Ying Li over at myITforum.com posted an article about some of the difficulty involved in launching a Windows PowerShell script from cmd.exe (or Start | Run) when there is a space in the path to the ps1 file containing the script. In this article, Ying was pointing out how running a script with a command similar to the following will result in an error:
powershell -noexit & “C:\Documents and Settings\poshoholic\My Documents\PowerShellRocks.ps1″
The reason this generates an error is simply because of how the command line arguments are broken into tokens outside of Powershell and then rebuilt as arguments inside of PowerShell. In the example above, PowerShell is being executed with 3 arguments: -noexit, &, and the path to the PowerShell script. Even though the PowerShell script has quotation marks around it when it is entered in cmd.exe or in the Start | Run dialog, those quotation marks are only used to hold the string together as one argument outside of PowerShell. They are not passed in with the string. When PowerShell actually gets to see the arguments inside, it sees this:
- C:\Documents and Settings\poshoholic\My Documents\PowerShellRocks.ps1
The -noexit argument is a named switch property that is supported by PowerShell, so PowerShell knows to keep the console open when the script is done. The remaining arguments aren’t associated with a named property, so PowerShell treats them as the command by concatenating them together with a space between the tokens. This makes the PowerShell command look like this:
& C:\Documents and Settings\poshoholic\My Documents\PowerShellRocks.ps1
If you try to run this command in PowerShell, you will get an error because the parser doesn’t know what to do with the C:\Documents token. Fortunately, the fix to this is simple. As Ying pointed out, you can use single quotes instead of double quotes. This means you could enter the command like this:
powershell -noexit & ‘C:\Documents and Settings\poshoholic\My Documents\PowerShellRocks.ps1′
In this case, the single quotes are not used to identify one argument to PowerShell.exe, so the argument list looks like this:
Since the single quotes weren’t removed when the command was broken into tokens, the string remains intact when it is rebuilt as the command to execute within PowerShell.
But what if you really needed to use double quotes? Well, double quotes work too, but you have to treat them as a special case because they are used to identify an argument that contains spaces. More specifically, you have to escape them within a surrounding pair of quotes by entering two double quotes side by side. In the case of our example, that means entering the command like this:
powershell -noexit “& “”C:\Documents and Settings\poshoholic\My Documents\PowerShellRocks.ps1″”"
Running this command results in two arguments being passed into PowerShell:
- & “C:\Documents and Settings\poshoholic\My Documents\PowerShellRocks.ps1″
Bingo, that’s the script that we originally intended to run!
While it might not be that common that someone wants to pass quotation marks into PowerShell via cmd.exe or Start | Run, I thought it would be useful to clarify this for whenever the need arises. In general, I recommend always putting external quotation marks around the entire command that you want to pass into PowerShell this way and using paired double-quotes or non-paired single quotes within that quoted command as required. This prevents unnecessary tokenizing and then rebuilding of the command which, as Ying’s article illustrated, doesn’t always rebuild as you would expect it to.
For related information, specifically pertaining to the order you need to use in your PowerShell.exe arguments, read this post.