All pass-through arguments passed to Start-Process
must be the elements of a single array passed to -ArgumentList
.
$ScriptBlock
and $prefix
in your call aren't part of the -ArgumentList
array and therefore constitute additional, positional arguments from Start-Process
's perspective, which it doesn't recognize - that caused the error you saw.
Fundamentally, all pass-through arguments are invariably strings, so you cannot pass a script block as such (it would be turned into its verbatim source code, not including the enclosing {
and }
)
However, since are looking for synchronous invocation (-Wait
) in the same window (-NoNewWindow
), there's no need for Start-Process
at all, and you can simply call pwsh
directly, which - from inside a PowerShell session ony - does allow you to use a script block:
pwsh -NoProfile -NoExit $ScriptBlock -args $prefix
See the docs for PowerShell (Core)'s CLI, pwsh
.
If you do want to use Start-Process
- which is only necessary if you want to run the code in a new window or with elevation (as admin) or with a different user identity - use the following:
For readability and ease of embedding quotes, the solution uses an expandable here-string (@"<newline>...<newline>@"
).
It takes advantage of the fact that script blocks serialize as their verbatim source code, excluding {
and }
, so you make the target PowerShell instance invoke it by enclosing it in & { ... }
in the command string.
- While
& { $ScriptBlock }
would work in your particular case, to make the technique robust, any embedded "
characters must be escaped as \"
-escaped in order to ensure that the CLI's initial command-line parsing doesn't remove them.
This is what the -replace '(?<!\\)(\\*)"', '$1$1\"'
operation below does.
Start-Process pwsh @"
-NoProfile -Command & { $($ScriptBlock -replace '(?<!\\)(\\*)"', '$1$1\"') } "$prefix"
"@
Note:
All pass-through arguments for pwsh
are encoded in a single string passed to the (positionally implied) -ArgumentList
parameter.
- While passing pass-through arguments individually - as the elements of an array, as you originally tried - may be conceptually preferable, a long-standing bug unfortunately makes the single-string approach preferable, because it makes the situational need for embedded double-quoting explicit - see this answer.
While you could alternatively make use of the -EncodedCommand
and (currently undocumented) -EncodedArguments
CLI parameters, doing is even more cumbersome, due to requiring Base64 encoding.
- In direct invocation, as shown in the first snippet, PowerShell actually makes use of these parameters behind the scenes, which makes invocation convenient - see this answer for background information.
If you do want to use these parameters with Start-Process
, see this answer for an example.