Search code examples
powershellinvokesplat

Sending Params Correctly without Interpolation with Splat


Can I directly import these parameters to my function with their correct types with only value with respectively?

$appparams = @{ 
    sname  = "RandomAppName"    # type: string
    sdata  = [byte]12           # type: Byte
    sgroup = $null              # type: NULL
}

CASE: not sending as respectively + not correct types

$arglist = ($appparams.GetEnumerator() | Sort-Object Name | % { "$($_.Value)" }) -join ','
Invoke-Function .... $arglist  -> Invoke-Function .... 12,,RandomAppName

Expected: sending only value with respectively and without any interpolation

Invoke-Function .... $arglist  -> Invoke-Function .... "RandomAppName",12,$null

Solution

  • It looks like you're trying to pass the values of your hashtable entries as positional arguments to Invoke-Function.

    • This contrasts with the usual hashtable-based splatting that uses named arguments, where the key of each entry implies the target parameter, and the value the argument.

    • In other words:

      • If Invoke-Function declared parameters named -sname, -sdata, and -sgroup with matching data types, you could use Invoke-Function @appParams to pass your hashtable as-is (except for using @ instead of $, for splatting).

      • Since the parameter binding would then based on names, the fact that a [hashtable] (@{ ... }) instance's entries are inherently unordered would then not a problem, and no sorting is needed.

    • If you get to control the definition of Invoke-Function and it takes a known set of arguments (as opposed to an open-ended list of arguments not known in advance), it is best to make it declare parameters and use hashtable-based splatting, as described.


    If you cannot modify the target command and must pass arguments positionally:

    First, as mclayton points out, you need an ordered hashtable ([ordered]) if the definition order of the entries (values) must be maintained (see below for an alternative based on sorting by keys, as you've tried).

    Then you can use array-based splatting to positionally pass your hashtable's values:

    # *Sample function* that simply echoes its positional arguments
    # and their types.
    # This serves as a *stand-in* for *your* function of that name.
    function Invoke-Function { $args | ForEach-Object { $isNull = $null -eq $_; [pscustomobject] @{ Value = if ($isNull) { '$null' } else { $_ }; Type = if (-not $isNull) { $_.GetType() } } } }
    
    # The ordered hashtable whose values are to be passed as positional arguments.
    $appParams = [ordered] @{ 
        sdata  = [byte]12           # type: Byte
        sgroup = $null              # type: NULL
        sname  = "RandomAppName"    # type: string
    }
    
    # Get the ordered hashtable's values, as an *array*.
    [array] $appParamValues = $appParams.Values
    
    # Pass the values as separate, positional arguments.
    Invoke-Function @appParamValues
    

    Note:

    • If you want to pass the array of values as an array, i.e. as a single argument, simply replace @ with $, i.e. pass the array as-is:

      # Pass the values as a *single argument* that is an *array*.
      Invoke-Function $appParamValues
      
      # *If* your function expects that single argument to be passed
      # as a *named* argument to parameter -ArgumentList
      Invoke-Function -ArgumentList $appParamValues
      
    • If you don't get to control the creation of the hashtable and must indeed use sorting by key, define $appParameterValues as follows:

      $appParamValues = 
        $appParams.Keys | Sort-Object | ForEach-Object { $appParams[$_] }
      

    Output:

    Value         Type
    -----         ----
    RandomAppName System.String
    12            System.Byte
    $null         
    

    As for what you tried:

    ($appparams.GetEnumerator() | Sort-Object Name | % { "$($_.Value)" }) -join ','

    This:

    • stringifies all values due to use of string interpolation ("...")

    • due to -join ',' creates a single string value that is the ,-separated list of all stringified values.

    This results both in loss of the original data types and loss of separate values, and would be seen by any target command as a single string argument, as described.