tl;dr
To pass pass-through arguments to Start-Process
's -ArgumentList
(-Args
) parameter:
$a = "c:\test.ps1"
Start-Process powershell "-noexit -file `"$a`""
Note: Parameter names -FilePath
and -ArgumentList
are positionally implied in this command; that is, the command is equivalent to Start-Process -FilePath powershell -ArgumentList "-noexit -file `"$a`""
As for what you tried:
Start-Process
's -ArgumentList
(-Args
) parameter is [string[]]
typed, i.e. it expects an array of string arguments to pass to the external program being launched - given that strings are the only supported data type when passing arguments to external programs.
- Note: While passing pass-through arguments individually, as the elements of an array, to
-ArgumentList
(-ArgumentList '-noexit', '-file', $a
) is conceptually the best approach, it is unfortunately ill-advised due to a long-standing bug in Start-Process
, still present as of this writing (v7.2) - see GitHub issue #5576.
For now, using a single string comprising all arguments, each enclosed in embedded "..."
quoting if necessary (as shown above), is the only robust approach.
As discussed in the linked GitHub issue, an -ArgumentArray
parameter that supports robust array-based argument passing may be introduced in the future.
When you pass a script block ({ ... }
), it is stringified (its .ToString()
method is implicitly called, and a script block's stringification is its verbatim contents (excluding the enclosing {
and }
), which means that no expansion (string interpolation) takes place;
try { $HOME }.ToString()
, for instance.
- Note: You can use script blocks when you invoke
powershell.exe
directly, synchronously (rather than via Start-Process
), but only from PowerShell, and such script blocks are executed by the callee, and therefore also do not see the caller's variables; you can, however, pass arguments to them; e.g.:
powershell { "args passed: $args" } -args 1, 2