1

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

jkroepke
  • 31
  • 6
  • As aside, do not use `$args` as self-defined variable because it is an [Automatic variable](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables?view=powershell-7.2#args). Choose another name for that – Theo Jan 08 '23 at 14:30
  • You do not need to escape the string since it is not inside another string. So use : powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "echo Hello World" – jdweng Jan 08 '23 at 14:35
  • Why use start-process at all? `wsl bash -c 'echo hello world'` The arguments probably need to be an array. – js2010 Jan 08 '23 at 14:44
  • In the case of bash, you can also run it directly: `bash -c 'echo hello world'` You can also install the linux pwsh. – js2010 Jan 08 '23 at 14:51
  • @Theo thats the use case, I want to pass arguments from CLI. I do not define $args by myself. – jkroepke Jan 08 '23 at 15:08
  • 1
    @jdweng It do not work. Tested from windows powershell. Arguments are not correctly passed to Start-Process. - See also https://github.com/PowerShell/PowerShell/issues/5576 – jkroepke Jan 08 '23 at 15:09
  • @js2010 It's windows. – jkroepke Jan 08 '23 at 15:10

2 Answers2

1

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
mklement0
  • 382,024
  • 64
  • 607
  • 775
0

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'`""
js2010
  • 23,033
  • 6
  • 64
  • 66