Start-Process doesn't pass arguments with embedded whitespace and double quotes correctly #5576
Description
Updated later to include the problem with embedded double quotes.
Steps to reproduce
Embedded whitespace:
'"Hi!"' > './t 1.ps1'; Start-Process -Wait -NoNewWindow pwsh -ArgumentList '-noprofile', '-file', './t 1.ps1'Embedded double quotes:
Start-Process -Wait -NoNewWindow pwsh -ArgumentList '-noprofile', '-command', '"Hi!"'Expected behavior
In both cases:
Hi!
That is, script file ./t 1.ps1 should execute, and double-quoted string literal "Hi!" should print.
Actual behavior
Embedded whitespace:
Invocation fails, because the ./t 1.ps1 is passed as two arguments:
The argument './t' is not recognized as the name of a script file. Check the spelling of the name, or if a path was included, verify that the path is
correct and try again.
The only way to make this currently work is to embed (potentially escaped) double quotes: '"./t 1.ps1"' or "`"./t 1.ps1`""; e.g.:
Start-Process -Wait -NoNewWindow pwsh -ArgumentList '-noprofile', '-file', "`"./t 1.ps1`""Update: Overall, the best workaround is to pass a single string containing all arguments to -ArgumentList and use embedded quoting and escaping as necessary:
Start-Process -Wait -NoNewWindow pwsh -ArgumentList '-noprofile -file "./t 1.ps1"'Embedded double quotes:
The embedded double quotes are unexpectedly removed.
The only way to make this currently work is to \-escape the embedded double quotes:
Start-Process -Wait -NoNewWindow pwsh -ArgumentList '-noprofile', '-command', '\"Hi!\"'Update: Again, the best workaround is to use a single string:
Start-Process -Wait -NoNewWindow pwsh -ArgumentList '-noprofile -command \"Hi!\"'Environment data
PowerShell Core v6.0.0-rc (v6.0.0-rc) on Microsoft Windows 7 Enterprise (64-bit; v6.1.7601)
Windows PowerShell v5.1.14409.1012 on Microsoft Windows 7 Enterprise (64-bit; v6.1.7601)
Activity
ZSkycat commentedon Nov 29, 2017
I think it just executes
{filename} {ArgumentList.join(' ')}try this code
bergmeister commentedon Dec 15, 2017
The code where it deconstructs
-Argumentlistto the Argument string forProcessStartInfo.Argumentshere and it simply joins the arguments by separating it with a space character. Therefore it sees./tand1.ps1as two separate arguments. As pointed out by ZSkycat (@ZSkycat) one has to correctly quote the file.iSazonov commentedon Dec 16, 2017
I see the feature is documented:
I don't understand how we can fix this for all platforms and for an indefinite number of applications. If there is no standard to which we should follow I would rather expect a common way of passing arguments so that they reach the goal application in exactly the user specified form.
bergmeister commentedon Dec 16, 2017
Well, I guess we can only improve it (see my PR 5703) or maybe the better solution is to add an
-Argumentsparameter that is just a string to reduce complexity and leave the-ArgumentListparameter there only for legacy reasons.mklement0 commentedon Dec 17, 2017
Christoph Bergmeister (@bergmeister): Thanks for taking this on in your PR, but there are additional edge cases to consider, such as tokens ending in
\- see #1995 (comment)Ultimately, the single string passed to
ProcessStartInfo.Argumentsshould be constructed the same way that a direct call to an external program is handled, namely based on inverse of the MSVC++ command-line parsing rules, as discussed in TSlivede's RFC proposal.Longer-term, once https://github.com/dotnet/corefx/issues/23592 is implemented in CoreFx, PowerShell will simply be able to pass the array through. The linked issue also points to a utility method in the CoreFx code where the kind of array-to-command-line transformation that would be needed here is used internally.
And, yes, this will break things, inevitably and in multiple scenarios, but I think if PowerShell wants to be taken seriously as a multi-platform shell, there's no way around that.
While we may consider adding a new
-Argumentsparameter for someone who wants to pass a single-string, pre-escaped command line (directly assignable toProcessStartInfo.Arguments- which, notably, still needs to be split back into an array before creating a process on Unix), it is-ArgumentListthat must be fixed - which breaks things.iSazonov commentedon Dec 18, 2017
Michael Klement (@mklement0) As far as I understand the shortest way to get this is to implement https://github.com/dotnet/corefx/issues/23592, isn't it?
mklement0 commentedon Dec 18, 2017
Ilya (@iSazonov): Yes, with said proposal implemented, PowerShell could just use the new
ProcessStartInfo.ArgumentListproperty directly and, on Windows, let CoreFX translate that into a single command line string with appropriate quoting.bergmeister commentedon Dec 18, 2017
Ok. Shall I close the PR then or do we want to consider it as an intermediate improvement?
iSazonov commentedon Dec 18, 2017
I think it is not critical and not a secure hole so we can wait and it is better to direct our efforts to other areas or contribute directly in CoreFX now.
[-]Start-Process doesn't pass arguments with embedded whitespace correctly[/-][+]Start-Process doesn't pass arguments with embedded whitespace and double quotes correctly[/+]Artoria2e5 commentedon Sep 18, 2019
On a related note, it seems to truncate at the
>character too:(Windows PS 7.0.0-preview3)
read the reply. ho boy... this is bad
51 remaining items
SteveL-MSFT commentedon Jan 17, 2024
I created https://github.com/orgs/PowerShell/discussions/21089 to discuss this broader topic
mklement0 commentedon Jan 1, 2025
Note that the link in the previous comment no longer works; here's the current one:
viocha commentedon Apr 27, 2025
It's hard to imagine that this problem still hasn't been solved after all these years. This is the solution provided by ChatGPT.
microsoft-github-policy-service commentedon Oct 25, 2025
This issue has not had any activity in 6 months, if there is no further activity in 7 days, the issue will be closed automatically.
Activity in this case refers only to comments on the issue. If the issue is closed and you are the author, you can re-open the issue using the button below. Please add more information to be considered during retriage. If you are not the author but the issue is impacting you after it has been closed, please submit a new issue with updated details and a link to this issue and the original.
cbryn commentedon Oct 31, 2025
This is still open.
microsoft-github-policy-service commentedon Apr 29, 2026
This issue has not had any activity in 6 months, if there is no further activity in 7 days, the issue will be closed automatically.
Activity in this case refers only to comments on the issue. If the issue is closed and you are the author, you can re-open the issue using the button below. Please add more information to be considered during retriage. If you are not the author but the issue is impacting you after it has been closed, please submit a new issue with updated details and a link to this issue and the original.
noamper commentedon Apr 29, 2026
Still open
ringerc commentedon May 5, 2026
There's still no correct, portable way to start a process in Powershell, so this issue remains open.