Invoking an executable from PowerShell with a dynamic number of parameters

Published on: 16 Nov 2014 by: Paul Stovell

Calling an executable from PowerShell is easy - most of the time, you just put an & in front. To illustrate, let's take this C# executable:

static void Main(string[] args)
{
    for (int i = 0; i < args.Length; i++)
    {
        Console.WriteLine("[" + i + "] = '" + args[i] + "'");
    }
}

If we call it like this:

& .\Argsy.exe arg1 "argument 2"

We get:

[0] = 'arg1'
[1] = 'argument 2'

PowerShell variables can also be passed to arguments:

$myvariable = "argument 2"
& .\Argsy.exe arg1 $myvariable

# Output:
[0] = 'arg1'
[1] = 'argument 2'

Note that the value of $myvariable contained a space, but PowerShell was smart enough to pass the whole value as a single argument.

This gets tricky when you want to conditionally or dynamically add arguments. For example, you might be tempted to try this:

$args = ""
$environments = @("My Environment", "Production")
foreach ($environment in $environments) 
{
    $args += "--environment "
    $args += $environment + " "
}

& .\Argsy.exe $args

However, you'll be disappointed with the output:

[0] = '--environment My Environment --environment Production '

The right way

The way to do this instead is to create an array. You can still use the += syntax in PowerShell to build the array:

$args = @() # Empty array
$environments = @("My Environment", "Production")
foreach ($environment in $environments) 
{
    $args += "--environment"
    $args += $environment
}
& .\Argsy.exe $args

Which outputs what we'd expect:

[0] = '--environment'
[1] = 'My Environment'
[2] = '--environment'
[3] = 'Production'

You can also mix regular strings with arrays:

& .\Argsy.exe arg1 "argument 2" $args

# Output:
[0] = 'arg1'
[1] = 'argument 2'
[2] = '--environment'
[3] = 'MyEnvironment'
[4] = '--environment'
[5] = 'Production'

Edge case

There's is a very odd edge case to what I said above about passing a single string with all the arguments. Take this example, which is similar to the one above:

$args = "--project Foo --environment My Environment --environment Production"
& .\Argsy.exe $args

# Output: 
[0] = '--project Foo --environment My Environment --environment Production'

To make it work as intended, just put a quote around the first argument, and the behaviour changes completely! (The backticks are PowerShell's escape characters)

$args = "`"--project`" Foo --environment My Environment --environment Production"
& .\Argsy.exe $args

# Output: 
[0] = '--project'
[1] = 'Foo'
[2] = '--environment'
[3] = 'My'
[4] = 'Environment'
[5] = '--environment'
[6] = 'Production'

The behavior doesn't change if the first argument isn't quoted:

$args = "--project `"Foo`" --environment My Environment --environment Production"
& .\Argsy.exe $args

# Output: 
[0] = '--project Foo --environment My Environment --environment Production'

Ahh, PowerShell. Always full of surprises!