views:

63

answers:

3

Can you overload functions in powershell ?

What I want to do is that my functin could accept string, array or some switch.

Example what I want:

  • Backup-UsersData singleUser
  • Backup-UsersData @('Alice', 'Bob', 'Joe')
  • Backup-UsersData -all

Best regards.

A: 

Edited: disregard the answer below. In Payette's book about PowerShell v2, he states that overloading is not supported in V1, which made me wrongly assume that it was in V2. But it's not.


This is possible in Powershell V2.

function Backup-UsersData ([string] $user) ...

function Backup-UsersData ([object[]] $array)...

function Backup-UsersData ([switch] $all) ...

In V1, you can test for the variable type (and the switch) explicitly.

Timores
Have you tried this? It should not work, the last function definition should be always called in your case. I have tried, it works as I expect.
Roman Kuzmin
Unfortunately not tried (I don't have access to Powershell right now). Have you tried in V2 ? In V1, what you get is the expected behavior.
Timores
I have tried in V2. If version is not specified then I normally assume it V2.
Roman Kuzmin
imho that won't work in v1, nor v2. What you do, is basically something like this: `Set-Content -path 'function:Backup-UsersData' -value {param([string] $user) write-host user $user }`. Every row sets content of `function:Backup-UsersData`.
stej
I am currently reading PowerShell in action, 2nd Edition, by B. Payette (one of the designers of PS). It states that overloads are not supported in V1 (page 246 of the October draft).
Timores
+6  A: 

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
Roman Kuzmin
+2  A: 

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"
        }
    }
}
OldFart