Skip to content

Start-Process doesn't pass arguments with embedded whitespace and double quotes correctly #5576

Open

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

  1. ZSkycat commented on Nov 29, 2017

    @ZSkycat

    I think it just executes {filename} {ArgumentList.join(' ')}

    try this code

    Start-Process -Wait -NoNewWindow pwsh.exe -ArgumentList '-noprofile', '-file', '"./t 1.ps1"'
    Start-Process -Wait -NoNewWindow pwsh.exe -ArgumentList '-noprofile', '-file', '"', './t 1.ps1', '"'
  2. added
    Up-for-GrabsUp-for-grabs issues are not high priorities, and may be opportunities for external contributors
    on Dec 12, 2017
  3. bergmeister commented on Dec 15, 2017

    @bergmeister
    Contributor

    The code where it deconstructs -Argumentlist to the Argument string for ProcessStartInfo.Arguments here and it simply joins the arguments by separating it with a space character. Therefore it sees ./t and 1.ps1 as two separate arguments. As pointed out by ZSkycat (@ZSkycat) one has to correctly quote the file.

  4. iSazonov commented on Dec 16, 2017

    @iSazonov
    Collaborator

    I see the feature is documented:

    Arguments are parsed and interpreted by the target application, so must align with the expectations of that application. For.NET applications as demonstrated in the Examples below, spaces are interpreted as a separator between multiple arguments. A single argument that includes spaces must be surrounded by quotation marks, but those quotation marks are not carried through to the target application. In include quotation marks in the final parsed argument, triple-escape each mark.

    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.

  5. bergmeister commented on Dec 16, 2017

    @bergmeister
    Contributor

    Well, I guess we can only improve it (see my PR 5703) or maybe the better solution is to add an -Arguments parameter that is just a string to reduce complexity and leave the -ArgumentList parameter there only for legacy reasons.

  6. mklement0 commented on Dec 17, 2017

    @mklement0
    ContributorAuthor

    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.Arguments should 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 -Arguments parameter for someone who wants to pass a single-string, pre-escaped command line (directly assignable to ProcessStartInfo.Arguments - which, notably, still needs to be split back into an array before creating a process on Unix), it is -ArgumentList that must be fixed - which breaks things.

  7. iSazonov commented on Dec 18, 2017

    @iSazonov
    Collaborator

    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?

  8. mklement0 commented on Dec 18, 2017

    @mklement0
    ContributorAuthor

    Ilya (@iSazonov): Yes, with said proposal implemented, PowerShell could just use the new ProcessStartInfo.ArgumentList property directly and, on Windows, let CoreFX translate that into a single command line string with appropriate quoting.

  9. bergmeister commented on Dec 18, 2017

    @bergmeister
    Contributor

    Ok. Shall I close the PR then or do we want to consider it as an intermediate improvement?

  10. iSazonov commented on Dec 18, 2017

    @iSazonov
    Collaborator

    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.

  11. changed the title [-]Start-Process doesn't pass arguments with embedded whitespace correctly[/-] [+]Start-Process doesn't pass arguments with embedded whitespace and double quotes correctly[/+] on Jul 28, 2019
  12. Artoria2e5 commented on Sep 18, 2019

    @Artoria2e5

    On a related note, it seems to truncate at the > character too:

    PS> Start-Process -Wait -NoNewWindow node -ArgumentList '-e', 'process.argv.slice(1).forEach((x) => console.log(x))'
    [eval]:1
    process.argv.slice(1).forEach((x)
                                    ^
    SyntaxError: missing ) after argument list
    

    (Windows PS 7.0.0-preview3)


    read the reply. ho boy... this is bad

  13. 51 remaining items

  14. SteveL-MSFT commented on Jan 17, 2024

    @SteveL-MSFT
    Member

    I created https://github.com/orgs/PowerShell/discussions/21089 to discuss this broader topic

    GitHub
    The Cmdlet WG was discussing some proposed changes to Start-Process and it was apparent that there needed to be an overall discussion of how we move cmdlets forward in such a way that: We can moder...
  15. mklement0 commented on Jan 1, 2025

    @mklement0
    ContributorAuthor

    Note that the link in the previous comment no longer works; here's the current one:

    GitHub
    The Cmdlet WG was discussing some proposed changes to Start-Process and it was apparent that there needed to be an overall discussion of how we move cmdlets forward in such a way that: We can moder...
  16. viocha commented on Apr 27, 2025

    @viocha

    It's hard to imagine that this problem still hasn't been solved after all these years. This is the solution provided by ChatGPT.

    $argList = $argList | ForEach-Object { $_ | ConvertTo-Json }
  17. microsoft-github-policy-service commented on Oct 25, 2025

    @microsoft-github-policy-service
    Contributor

    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.

  18. cbryn commented on Oct 31, 2025

    @cbryn

    This is still open.

  19. microsoft-github-policy-service commented on Apr 29, 2026

    @microsoft-github-policy-service
    Contributor

    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.

  20. noamper commented on Apr 29, 2026

    @noamper

    Still open

  21. ringerc commented on May 5, 2026

    @ringerc

    There's still no correct, portable way to start a process in Powershell, so this issue remains open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Committee-ReviewedPS-Committee has reviewed this and made a decisionIssue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassifWG-Cmdletsgeneral cmdlet issues

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions