korra
korra

Reputation: 121

how to use hashtable to pass parameters to a powershell cmd that uses double dashes before the parameters

i m writing a script that makes use of a cmdlet from a console app, let's call the cmdlet as cmdA. I have no control over implementation of cmdA. cmdA takes parameters with a double dash (cmdA --param1 value1 --param2 value2 --param3 value3 --param4 value4 --param5 value5)

Now param2, param3, param4 and param5 are optional. The user of my script may or may not provide values for these optional parameters. In the script, i formed a hashtable using the parameters for which the user provided values. Let's call it paramHashtable.

I am executing cmdA @paramHashtable but this is not working. I think it has to do something with double dashes because this approach works fine with a cmd that takes parameters with single dash

What would be an efficient way to pass parameters to the cmdA (an inefficient way would be to use many if blocks to check which values were provided and make calls accordingly)

edited*

This is how i m creating the hashtable :-

$optionalParameters = @{}
$optionalParameters = ParameterSelection ${OutputFolder} ${PerfQueryIntervalInSec} ${StaticQueryIntervalInSec} ${NumberOfIterations}
$requiredParameters = @{"sqlConnectionStrings " = "$SqlConnectionStrings"}
$parameters = $requiredParameters + $optionalParameters

function ParameterSelection ([string] $outputFolder, [string] $perfQueryIntervalInSec, [string] $staticQueryIntervalInSec, [string] $numberOfIterations)
{
    $parametersList = @{}
    if($outputFolder -ne "")
    {
        $parametersList["outputFolder "] = $outputFolder    
    }
    if($perfQueryIntervalInSec -ne "")
    {
        $parametersList["perfQueryIntervalInSec "] = $perfQueryIntervalInSec 
    }
    if($staticQueryIntervalInSec -ne "")
    {
        $parametersList["staticQueryIntervalInSec "] = $staticQueryIntervalInSec
    }
    if($numberOfIterations -ne "")
    {
        $parametersList["numberOfIterations "] = $numberOfIterations 
    }

    return $parametersList
}

This is how i m calling it :-

& $ExePath actionName @parameters

The $ExePath has the path of the program to be executed The actionName takes parameters like this:-

actionName --sqlConnectionStrings "Data Source=Server1" --outputFolder C:\Output

Upvotes: 4

Views: 2819

Answers (2)

mklement0
mklement0

Reputation: 439193

As noted in the comments, because you are calling an external program, you should use array-based splatting or simply use arrays directly in order to pass programmatically constructed arguments.

  • By contrast, hashtable-based splatting is usually only helpful when calling PowerShell commands (while it technically works with external programs too, the resulting parameter format (e.g. -foo:bar or -foo:"bar none") is unusual and understood by few external programs)

  • Splatting with external programs works implicitly; that is, you can pass an array variable as-is as well as an array literal (whereas splatting with PowerShell commands always requires an intermediate variable and sigil @ instead of $ - though you may choose to use @ with external programs too, to make the intent clear).

Note that the parameter names and values must be passed as separate array elements and the elements representing parameter names must include the - or -- prefix; e.g., consecutive array elements '--sqlConnectionStrings' (the name) and
'Data Source=Server1' (the value).

PowerShell then constructs a command line for invocation of the external program behind the scenes, space-separating the array elements and double-quoting elements with embedded spaces on demand; the above example turns into the following:
--sqlConnectionStrings "Data Source=Server1"

Note that it is up to the target program to parse the single string that is its command line in a way that recognizes parameter name-value pairs.

# Get the array of *optional* parameter names and values from your helper function.
$optionalParameters = ParameterSelection ${OutputFolder} ${PerfQueryIntervalInSec} ${StaticQueryIntervalInSec} ${NumberOfIterations}

# Declare the *required* parameter(s) as an array.
$requiredParameters = '--sqlConnectionStrings', $SqlConnectionStrings

# Pass the arrays as-is to the external program.
# (Empty arrays are effectively ignored.)
& $ExePath actionName $requiredParameters $optionalParmeters

Your ParameterSelection function can be simplified as follows:

function ParameterSelection ([string] $outputFolder, [string] $perfQueryIntervalInSec, [string] $staticQueryIntervalInSec, [string] $numberOfIterations)
{
  # Loop over all bound parameters.
  $PSBoundParameters.GetEnumerator() | ForEach-Object {
    # Emit the parameter name prefixed with '--' and the value.
    # PowerShell automatically collects the output strings in an array
    # when you assign a call to this function to a variable.
    '--' + $_.Key
    $_.Value
  }
}

Upvotes: 3

Santiago Squarzon
Santiago Squarzon

Reputation: 60518

Can splatting with hash table work on cmdlets / functions where it's parameter have dashes?

It may work, but it is definitely not a good idea to have parameter names with dashes as this will result in a function / cmdlet where named parameters cannot be used, PowerShell binds the arguments positionally! (thanks mklement0 for pointing this out):

function Test-Splatting {
    param(${-param1}, ${-param2})
    "${-param1} ${-param2}"
}

$param = @{ '--param1' = 'hello'; '--param2' = 'world' }
Test-Splatting @param # => hello world

Example of what was mentioned before using the same function above:

# --param1 is bound positionally and not interpreted as a parameter:
Test-Splatting --param1 hello # => --param1 hello

As for an external programs, the linked answer in comments explains very well the approach you could take using a wrapper function and the use of the automatic variable $args:

function myfunc {
    $binaryPath = 'path/to/file.exe'
    & $binaryPath actionName $args
    # or @args we can't be sure until testing
}

myfunc --sqlConnectionStrings "Data Source=Server1" --outputFolder C:\Output

Upvotes: 3

Related Questions