LaboratoryGuy
LaboratoryGuy

Reputation: 31

How do I get named but undeclared parameters in a function in Powershell?

Here is an example of what I am trying to do.

Function Get-Parameters { Echo $SomeMagicMethod.Get("Name"); }

Get-Parameters -Name "John Doe"

$SomeMagicMethod is an automatic variable or any other method to get named undeclared parameters.

Is that possible in Powershell?

Upvotes: 3

Views: 702

Answers (3)

Bruce Payette
Bruce Payette

Reputation: 2639

If you truly want a function with no parameters, $args is the way to go. (Why you would want such a thing is a different question.) Anyway, code like the following will parse the $args array into a hashtable of parameter/argument pairs which you can use in the rest of the function body.

function NoParams
{
    $myParams = @{}
    switch ($args)
    {
        -Foo {
            if (!$switch.MoveNext()) {throw "Missing argument for Foo"} 
            $myParams.Foo = $switch.Current 
        }
        -Bar {
            if (!$switch.MoveNext()) {throw "Missing argument for Bar"} 
            $myParams.Bar = $switch.Current 
        }
        -Baz {
            if (!$switch.MoveNext()) {throw "Missing argument for Baz"} 
            $myParams.Baz = $switch.Current 
        }
        default { throw "Invalid parameter '$_'" }
    }
    $myParams
}

Upvotes: 3

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200353

You can define a special parameter to catch all unbound arguments:

Function Get-Parameters {
    Param(
        [Parameter(Mandatory=$true)]
        $SomeParam,

        [Parameter(Mandatory=$false)]
        $OtherParam = 'something',

        ...

        [Parameter(Mandatory=$false, ValueFromRemainingArguments=$true)]
        $OtherArgs
    )

    ...
}

However, that will give you an array with the remaining arguments. There won't be an association between -Name and "John Doe".

If your function doesn't define any other parameters you could use the automatic variable $args to the same end.

If you want some kind of hashtable with the unbound "named" arguments you need to build that yourself, e.g. like this:

$UnboundNamed   = @{}
$UnboundUnnamed = @()
$OtherArgs | ForEach-Object {
    if ($_ -like '-*') {
        $script:named = $_ -replace '^-'
        $UnboundNamed[$script:named] = $null
    } elseif ($script:named) {
        $UnboundNamed[$script:named] = $_
        $script:name = $null
    } else {
        $UnboundUnnamed += $_
    }
}

Upvotes: 4

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174690

You'll have to parse the unbounded arguments yourself and find the argument that's right after whatever parameter name you're looking for.

I'd abstract it away in a separate function (you could also pass $args, but this is cleaner):

function Get-InvocationParameter
{
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [System.Management.Automation.InvocationInfo]
        $Invocation,

        [Parameter(Mandatory = $true, Position = 1)]
        [string]
        $ParameterName
    )

    $Arguments = $Invocation.UnboundArguments

    $ParamIndex = $Arguments.IndexOf("-$ParameterName")

    if($ParamIndex -eq -1){
        return
    }

    return $Arguments[$ParamIndex + 1]
}

Then use it like this:

function Get-Parameter
{
    Get-InvocationParameter -Invocation $MyInvocation -ParameterName "Name"
}

And you should be able to see the arguments right after -Name (or nothing):

PS C:\> Get-Parameter -Name "John Doe"
John Doe
PS C:\> Get-Parameter -Name "John Doe","Jane Doe"
John Doe
Jane Doe
PS C:\> Get-Parameter -ID 123
PS C:\>

Upvotes: 3

Related Questions