It's not a bug, it's a PowerShell feature
I have been learning and using PowerShell more and more on my daily computer work, even on linux, and I am liking the experience very much but I got severely annoyed at what apparently looked like a bug but I then found it to be a known “issue” or “feature” if we like.
Now, presume we have a program that prints its arguments to the console, in C it would look like this:
#include <stdio.h>
void main(int argc, char** argv)
{
for (int i=0; i < argc; i++)
{
printf("%s\r\n", argv[i]);
}
}
Calling this program with some arguments will yield us to this output:
# SH
$ ./print-argv Hello World
/home/user/print-argv
Hello
World
# PowerShell
> ./print-argv Hello World
/home/user/print-argv
Hello
World
If we wanted to give it a double quote "
as the first argument, we would need
to escape it, on UNIX shell it would be using the \
character, and on
PowerShell it would be the `
character.
# SH
$ ./print-argv \" Hello World
/home/user/print-argv
"
Hello
World
# PowerShell
> ./print-argv `" Hello World
/home/user/print-argv
"
Hello
World
So far so good, everything is working as expected. Now, on Windows, many
programs have the bad behaviour of freeing the console before terminating so
the script will continue executing before the program has terminated so you
would need to use the Start-Process -Wait
cmdlet. So we just copy & paste the
command line we used before and change it to the Start-Process
syntax:
> Start-Process ./print-argv -Wait -ArgumentList `", Hello, World
/home/user/print-argv
Hello World
What? Suddenly 3 arguments become 1 argument and the "
character is nowhere
to be seen? Oh well, if we go to the Start-Process
documentation
it warns us about double quotes that need to be escaped, so we do it again.
> Start-Process ./print-argv -Wait -ArgumentList "`"", Hello, World
/home/user/print-argv
Hello World
… Same result. Then on the same help document it links us to the
quoting rules and at the very very bottom of the page, we find
another page that involves “external commands” and parsing, which
Start-Process
is not but it has a fair warning about a .NET class
ProcessStartInfo
which I presume Start-Process
uses:
The backslash (
\
) character isn’t recognized as an escape character by PowerShell. It’s the escape character used by the underlying API forProcessStartInfo.Arguments
.
So apparently the solution is… Mixing two styles of escaping. Because reasons.
> Start-Process ./print-argv -Wait -ArgumentList \`", Hello, World
/home/user/print-argv
"
Hello
World
There we have it, the expected output, using an unexpected input.