Garret Wilson
Garret Wilson

Reputation: 21486

Call Windows executable from PowerShell script, passing all arguments

I've looked all over, and I can't find the answer. Most things I've seen have answers that go around in circles and talk about all sorts of complicated things with no direct answer.

My question is simple. I have the following Windows batch file foo.bat:

@ECHO OFF
bar.exe %*

If I call foo.bat foobar 123 from the command line, it invokes bar.exe foobar 123. This works with no command-line arguments. This works with multiple command-line arguments.

What is the equivalent PowerShell script that does basically the same thing: invoke another executable, passing all CLI parameters the user provided?

I wouldn't expect this would be difficult, but I sure can't find any straightforward answer.

Upvotes: 2

Views: 699

Answers (1)

mklement0
mklement0

Reputation: 440162

The PowerShell equivalent of your foo.bat file is a foo.ps1 file with the following content:

# Passes all arguments received by this script to bar.exe
bar.exe @args

PowerShell exposes all (unbound) positional arguments[1] as an array stored in the automatic $args variable.

By prefixing $args with @ instead of $, argument splatting is employed, which means that the elements of the $args array are passed as individual arguments to bar.exe

  • Note: This isn't strictly necessary when calling external programs (such as bar.exe) - $args would work there too - but is more versatile in that it can also pass named arguments correctly through to other PowerShell commands, which typically have declared parameters that can be bound by name (e.g., -Path C:\temp to bind value C:\temp to declared parameter -Path)

As for working with $args in general:

  • $args.Count tells you how many (unbound) positional arguments were passed,
  • $args[0] returns the first such argument, $args[1] the second, and so on.

However, it is usually preferable to formally declare parameters in PowerShell scripts and functions, which can then also be bound by name (e.g., -FooParam foo instead of just foo). See this answer for more information.


[1] If your script doesn't formally declare any parameters (via a param(...) block - see about_Scripts and the linked answer), all arguments are by definition unbound (i.e. not mapped to a declared parameter) and positional (not prefixed by a target parameter name). However, if your script does declare parameters, $args only contains those arguments, if any, that were passed in addition to those binding to declared parameters. If your script is an advanced script (or function), $args isn't supported at all, because passing unbound arguments is then categorically prevented. See this answer for more information.

Upvotes: 4

Related Questions