Home > Software design >  Pass Arguments to Start-Process with spaces
Pass Arguments to Start-Process with spaces

Time:01-09

I would like to pass the powershell arguments to an process. The arguments may contain spaces.

Powershell Code:

$proc = Start-Process -FilePath "wsl.exe" -ArgumentList $args -NoNewWindow -PassThru
$proc | Wait-Process

Run Command

powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "`"echo Hello World`""

No Output.


Running this command with static array works fine:

$proc = Start-Process -FilePath "wsl.exe" -ArgumentList @("bash", "-c", "`"echo Hello World`"") -NoNewWindow -PassThru
$proc | Wait-Process

Output

Hello World

What I needed todo to escape the arguments from the CLI args?

See https://github.com/PowerShell/PowerShell/issues/5576 why I have to escape spaces

CodePudding user response:

The obvious answer is this, with $myargs being an array of strings. "echo Hello World" needs embedded double-quotes (or single-quotes) around it, which complicates things.

$myargs = "bash", "-c", "'echo Hello World'"
$proc = Start-Process -FilePath wsl.exe -ArgumentList $myargs -NoNewWindow -PassThru
$proc | Wait-Process

Hello World

I would just do:

.\sh.ps1 bash -c 'echo hello world'

# sh.ps1 contains:
# wsl $args

Or the wsl bash for windows:

bash -c 'echo hello world'

I happened to have pwsh installed within wsl. Without the single-quotes, each word would be put on a new line.

wsl pwsh -c "echo 'hello world'"

This works for me within another powershell, with yet another set of embedded quotes:

powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "`"'echo Hello World'`""

CodePudding user response:

There's no good reason to use Start-Process in your case (see this GitHub docs issue for guidance on when Start-Process is and isn't appropriate).

Instead, use direct execution, which is not only synchronous and runs in the same console window (for console applications such as wsl.exe), but also allows you to directly capture or redirect output.

In doing so, you'll also be bypassing the longstanding Start-Process bug you mention (GitHub issue #5576), because PowerShell double-quotes arguments passed to external programs as needed behind the scenes (namely if they contain spaces).

$exe, $exeArgs = $args   # split argument array into exe and pass-thru args
wsl.exe -e $exe $exeArgs # execute synchronously, via wsl -e 

Note that you then also don't need to embed escaped " in your PowerShell CLI call:

powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "echo Hello World"

However, if your arguments truly needed embedded ", you'd run into another longstanding PowerShell bug that affects only direct invocation of external programs, necessitating manual escaping with \ - see this answer.


If you do need to use Start-Process - e.g. if you want the process to run in a new (console) window - you'll have to provide embedded quoting around those $args elements that need it, along the following lines:

$quotedArgs = foreach ($arg in $args) {
  if ($arg -notmatch '[ "]') { $arg }
  else { # must double-quote
    '"{0}"' -f ($arg -replace '"', '\"' -replace '\\$', '\\')
  }
}

$proc = Start-Process -FilePath "wsl.exe" -ArgumentList $quotedArgs -PassThru
$proc | Wait-Process
  • Related