[SOLVED] Can a Powershell function handle multiple input types?

Issue

I’m working on a function that compares two objects so it detects them if they are identical. However I would like it to also work with other types like strings or integers.

C++ lets you declare different functions with the same name to handle function calls with different input types in a different way. I’m aware of the existence of Parameter Sets, however as far as I know the user is the one who must specify wich Parameter set he is using.

I’m trying to do something like this

function Compare-Objects{
    Param(
        [Parameter(Mandatory=$true,
        Position=0,
        ParameterSetName = "Hashtables")]
        [ValidateNotNullOrEmpty()] 
        [Hashtable]$Item1Hash,

        [Parameter(Mandatory=$true,
        Position=0,
        ParameterSetName = "Integers")]
        [ValidateNotNullOrEmpty()] 
        [int]$Item1int,

        [Parameter(Mandatory=$true,
        Position=1,
        ParameterSetName = "Hashtables")]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$Item2Hash,

        [Parameter(Mandatory=$true,
        Position=1,
        ParameterSetName = "Integers")]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$Item2Int
    )
    if($PSCmdlet.ParameterSetNamePositionv -match "Integers"){ Return ($Item1Int -eq $Item2Int)}
    else{
    #do some other stuff with $Item1Hash and $Item2Hash
    }
}

Extra points if I can also name the variables the same (So $Item1Hash and $Item1Int become both $Item1 with the appropiate type assigned)

Solution

As Jeff Zeitlin states in his comment:

Users do NOT have to specify a parameter set explicitly – PowerShell infers the applicable parameter set from the specific combination of arguments (or absence thereof) passed on invocation.

The inference is based on argument data types, whether arguments are passed positionally (not preceded by the parameter name) and which parameters are marked as mandatory, and the name of the parameter set that takes effect is reflected in $PSCmdlet.ParameterSetName inside the (advanced) script / function invoked.

This ability to infer the applicable parameter set is similar to automatic method overload resolution in C-like languages.


While any given parameter can participate in multiple parameter sets – and indeed is by default part of all of them – you fundamentally cannot declare parameters with the same name but different data types.

If you want such "polymorphic" parameters, you’ll have to implement your own logic, which doesn’t rely on parameter sets:

function Compare-Objects {

  [CmdletBinding(PositionalBinding=$false)]
  Param(
      
      [Parameter(Mandatory, Position=0)]
      [ValidateNotNullOrEmpty()] 
      # Define as [object] to initially accept any value; specific types
      # are later enforced inside the function body.
      [object] $Item1 
      ,
      [Parameter(Mandatory, Position=1)]
      [ValidateNotNullOrEmpty()] 
      [object] $Item2
  )

  # Ensure that a supported type was passed.
  if ($Item1.GetType() -notin [int], [hashtable]) { Throw "Unsupported argument type." }

  # Ensure that both arguments have the same type.
  if ($Item1.GetType() -ne $Item2.GetType()) { Throw "Inconsistent argument types." }
  
  if ($Item1 -is [int]) {
    "[int] arguments given."
  }
  else {
    "[hashtable] arguments given."
  }

}

However, if using the same parameter name isn’t a requirement and you’re content with positional invocation using different data types, parameter sets can help, as the following simplified example demonstrates:

function Foo {
  [CmdletBinding()]
  param(
    [Parameter(ParameterSetName='int', Position=0)]
    [int] $ItemInt
    ,
    [Parameter(ParameterSetName='hash', Position=0)]
    [hashtable] $ItemHash
  )
  "Parameter set chosen: $($PSCmdlet.ParameterSetName)"
 } 

# Call the function first with an [int], then with a [hashtable], positionally.
10, @{ foo = 1 } | ForEach-Object { Foo $_ }

The above yields the following, showing that the argument data type automatically selected the appropriate parameter set:

Parameter set chosen: int
Parameter set chosen: hash

Answered By – mklement0

Answer Checked By – David Goodson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.