Function overloading in PowerShell
Solution 1
In PowerShell functions are not overloaded. The last definition overrides the previous in the same scope or hides the previous in a parent scope. Thus, you should create a single function and provide a way to distinguish its call mode by arguments.
In V2 you may use an advanced function, see help about_Functions_Advanced_Parameters
and avoid some manual coding on resolving parameter set ambiguities:
# advanced function with 3 parameter sets
function Backup-UsersData
(
[Parameter(Position=0, ParameterSetName="user")]
[string]$user,
[Parameter(Position=0, ParameterSetName="array")]
[object[]]$array,
[Parameter(Position=0, ParameterSetName="all")]
[switch]$all
)
{
# use this to get the parameter set name
$PSCmdlet.ParameterSetName
}
# test
Backup-UsersData -user 'John'
Backup-UsersData 1, 2
Backup-UsersData -all
# OUTPUT:
# user
# array
# all
Note that this mechanism is sometimes strange. For example in the first test we have to specify parameter name -user
explicitly. Otherwise:
Backup-UsersData : Parameter set cannot be resolved using the specified named parameters.
At C:\TEMP\_101015_110059\try2.ps1:21 char:17
+ Backup-UsersData <<<< 'John'
+ CategoryInfo : InvalidArgument: (:) [Backup-UsersData], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Backup-UsersData
In many cases standard, not advanced, function with mixed parameters will do:
function Backup-UsersData
(
[string]$user,
[object[]]$array,
[switch]$all
)
{
if ($user) {'user'}
elseif ($array) {'array'}
elseif ($all) {'all'}
else {'may be'}
}
Backup-UsersData -user 'John'
Backup-UsersData -array 1, 2
Backup-UsersData -all
Backup-UsersData
But in this case you should resolve (or accept and ignore) ambiguities, e.g. to decide what to do if, say:
Backup-UsersData -user 'John' -array 1, 2 -all
Solution 2
Here is a variant of Roman's answer that I think is a little more flexible:
function Backup
{
[CmdletBinding(DefaultParameterSetName='Users')]
Param (
[parameter(mandatory=$true, ParameterSetName='Users', position=0, ValueFromPipeline=$true)][string[]]$User,
[parameter(mandatory=$true, ParameterSetName='AllUsers')][switch]$All
)
Begin
{
if ($All) { $User = @('User1', 'User2', 'User3') }
}
Process
{
foreach ($u in $User)
{
echo "Backup $u"
}
}
}
Solution 3
1) Build a class...
class c1 {
[int]f1( [string]$x ){ return 1 }
[int]f1( [int ]$x ){ return 2 }
}
1+) Use STATIC METHODS if you prefer to call them without instantiation...
class c1 {
static [int] f1( [string]$x ){ return 1 }
static [int] f1( [int]$x ){ return 2 }
}
2) Call the methods in class or object... overload works OK
$o1 = [c1]::new()
o1.f1( "abc" ) ~> returns 1
o1.f1( 123 ) ~> returns 2
-OR-
[c1]::f1( "abc" ) ~> returns 1
[c1]::f1( 123 ) ~> returns 2
3)
If (like me)
you want to have "Overloaded Functions" placed in a libraries...
so your users can use them transparently...
from code or from Interactive Command Line (REPL)...
the closest I could came to
"Overloading functions in Powershell"
was something like this:
function Alert-String() { [c1]::f1( "abc" ) }
function Alert-Strings(){ [c1]::f1( 123 ) }
function Alert-Stringn(){ [c1]::f1( 123 ) }
Maybe in PS-Core v8??? ;-)
Hope it helps...
Solution 4
If you use PSObject instead of Object to define your parameter type, it should work. For example, The function Get-Control, know's how to overload based on type string or template and can be called using the positional value:
Get-Control "A-Name-Of-A-Control"
Get-Control $template
To make the overload work, use PSObject as follows:
Function Get-Control {
Param(
[Parameter(Mandatory=$False,ParameterSetName="ByTemplate",Position=0)]
[PSObject]
$Template,
[Parameter(Mandatory=$False,ParameterSetName="ByName",Position=0)]
[String]
$Name,
[Parameter(Mandatory=$False)]
[Switch]
$List
)
... # remaining code removed for brevity
Primoz
Updated on October 09, 2020Comments
-
Primoz over 3 years
Can you overload functions in PowerShell?
I want to my function to accept a string, array or some switch.
An example of what I want:
- Backup-UsersData singleUser
- Backup-UsersData @('Alice', 'Bob', 'Joe')
- Backup-UsersData -all
-
Dave F about 3 yearsIt should be mentioned that class functions can be overloaded. This is done similarly to how it is done in other languages, by declaring multiple functions with the same names but different types of parameters. For example, a class with the functions
[string] val([int] $i) { return "Int: $i" }
and[string] val([string] $s) { return "String: $s" }
will outputInt: 1
for$t.val(1)
andString: abc
for$t.val('abc')
(NOTE: I verified that this code worked using PowerShell 5.1 and 7.1) -
anto418 over 2 yearsAlso it should be noted that Powershell (on 5.1, possibly earlier) can and will coerce single values into
[Object[]]
parameters: the function will get an array with the original object as its single value. This works with any type as long as the single value can be coerced into the type contained by the array (ie"plop"
can be coerced into[String[]]
but not into[Int32[]]
).