6

This question and this blog post address how to pass particular parameters into a PowerShell script from a batch file.

How can one pass all parameters into the PowerShell script? Basically I want to splat all the parameters so that the batch file passes all arguments through transparently.

Edit for more context:

I'm currently using a line like:

PowerShell.exe -Command "& '%~dpn0.ps1' '%1' '%2'"

This works, but creates a redundancy between the files such that, if I update the PowerShell script to take different arguments, I have to update the batch script as well. What would be nice is if I could do something like:

PowerShell.exe -Command "& '%~dpn0.ps1' '%*'"
jtpereyda
  • 6,987
  • 10
  • 51
  • 80
  • Could you provide an example of what you want? `Cmd` does not have splatting like `PSv3`+ has. – Maximilian Burszley Sep 11 '17 at 20:38
  • @TheIncorrigible1 I currently use a line like `PowerShell.exe -Command "& '%~dpn0.ps1' '%1' '%2'"`; I would like to be able to pass through all parameters without having to enumerate them. – jtpereyda Sep 11 '17 at 20:39
  • I'm not sure if this is possible or how, but it would be nice to do something like `PowerShell.exe -Command "& '%~dpn0.ps1' '%*'"` – jtpereyda Sep 11 '17 at 20:40

2 Answers2

8

Try the following:

powershell -File "%~dpn0.ps1" %*
  • In batch files, %* represents all arguments passed.[1]

  • -File is the parameter to use to invoke scripts via PowerShell's CLI.

  • All remaining arguments are then passed through as as-is (whereas -Command would subject them to another round of interpretation by PowerShell[2] ).

[1] Note that for cmd.exe (batch files) to recognize an argument with embedded whitespace as a single argument, you must enclose it in "...".
For instance, if you wanted to pass arguments a and b c to batch file file.cmd, you'd have to call it as
file a "b c".
To pass embedded " instances, \-escape them; e.g., "\"b c\"" makes PowerShell see "b c", including the double quotes.
If you respect these rules, %* - without quoting - properly passes the array of arguments through.
Do not use "%*" - it won't work as expected.

[2] In effect, -Command causes all following arguments to be joined by a single space each, and the resulting string is then interpreted as a PowerShell command - that is, after the arguments are parsed by the rules of cmd.exe (batch files), they are subject to another round of parsing, by PowerShell.
Unfortunately, PowerShell has always worked this way, but the behavior is obscure, and is likely to cause even more confusion in the Unix world, now that PowerShell has gone cross-platform - see this GitHub issue.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • This will miss arguments passed that have spaces in them. `%*` will literally just dump all the arguments. – Maximilian Burszley Sep 11 '17 at 20:45
  • @TheIncorrigible1: No: if you pass them properly quoted to the batch file, they are passed through intact. – mklement0 Sep 11 '17 at 20:47
  • Assuming you're passing them with quotes. In his example, he's quoting them intentionally, so it can be safe to assume they aren't passed that way or he's just being overly explicit – Maximilian Burszley Sep 11 '17 at 20:49
  • 2
    @TheIncorrigible1: There's no way around passing arguments properly by the rules of the _calling_ shell, which is `cmd.exe`. Once you do that, the command works as intended. – mklement0 Sep 11 '17 at 20:52
  • 1
    @TheIncorrigible1 Running `test.cmd a "b c" d` where `test.cmd` has the content `powershell -File "%~dpn0.ps1" %*` will invoke `test.ps1` with 3 arguments: `a`, `b c`, and `d`. You can verify that by echoing `$args` in the PowerShell script. – Ansgar Wiechers Sep 11 '17 at 21:34
  • 1
    Works in my instance. The extra quotes in my example were due to using `-Command` instead of `-File` as explained in the answer. Thank you! – jtpereyda Sep 12 '17 at 00:18
0

I wanted to do something similar, but a bit more complicated recently, and the answers here and information on a few sites helped me a lot. In my case the parameter to be passed from the cmd was a variable number of paths, often with spaces, potentially with $ and & - and the parameter was to be splatted, i.e. it had to have commas between strings, or the script would interpret it as a different argument. No matter what I did, I would break something. So in the end I had concatenated all the individual entries into a single variable, introduced escapes for $ and &, and passed it to the intermediate script:

set a="%~1"
if [%1]==[] goto end
:loop
shift
set b="%~1"
if [%1]==[] goto execute
set a=%a% %b%
goto loop
:execute
set a=%a:&=`&%
set a=%a:$=`$%
powershell -file (fullpath)\intermediatescript.ps1 %a%
:end
exit

which contains just a single line, invoking the main script:

& '(fullpath)\mainscript.ps1' -Path:$args

(I'm sharing this in case someone looks for a solution to the problem similar to mine or if wiser people spot a problem with my approach that I failed to encounter so far.)

jaram
  • 1
  • 1