DynamicParam与常规参数

时间:2017-11-07 11:29:53

标签: powershell

我有一个带动态参数和常规参数的函数。

动态参数名为Role,常规参数名为RolePattern

它们是不同集合的一部分。默认设置是使用动态参数。

如果我尝试使用带动态参数的集合,Powershell认为我使用了常规参数。

如果我将常规参数的名称更改为不以Role开头的内容,则可以正常工作。我做错了什么?

以下是测试脚本:

function Test-ParameterConflict {
    [CmdletBinding(DefaultParameterSetName = 'Dynamic')]
    [OutputType()]

    Param (
        [Parameter(Mandatory = $false, ParameterSetName = 'Pattern')]
        [ValidateNotNullOrEmpty()]
        [string] $RolePattern
    )

    dynamicParam {
        # Create the dictionary 
        $runtimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

        # Set the dynamic parameter's name
        $parameterName = 'Role'

        # Create and set the parameter's attributes
        $parameterAttribute = New-Object System.Management.Automation.ParameterAttribute
        $parameterAttribute.Mandatory = $true
        $parameterAttribute.ValueFromPipeline = $true
        $parameterAttribute.ValueFromPipelineByPropertyName = $true
        $parameterAttribute.ParameterSetName = 'Dynamic'

        # Create the collection of attributes
        $attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]

        # Add the attributes to the attributes collection
        $attributeCollection.Add($parameterAttribute)

        # Generate and set the ValidateSet 
        $validValues = @('Role1', 'Role2', 'Role3')
        $validateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($validValues)

        # Add the ValidateSet to the attributes collection
        $attributeCollection.Add($validateSetAttribute)

        # Create and add the dynamic parameter to the dictionary
        $runtimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($parameterName, [string[]], $attributeCollection)
        $runtimeParameterDictionary.Add($parameterName, $runtimeParameter)

        return $runtimeParameterDictionary
    }

    Process {
        "ParameterSetName = $($PSCmdlet.ParameterSetName)"
        $PSCmdlet.MyInvocation.BoundParameters
    }
}

基本上语法是:

Test-ParameterConflict [-RolePattern <string>]
Test-ParameterConflict -Role <string[]> 

这是输出:

Test-ParameterConflict -Role Role1 | ft -AutoSize
ParameterSetName = Pattern

Key         Value
---         -----
RolePattern Role1

1 个答案:

答案 0 :(得分:1)

这听起来像是PowerShell的一个问题。它不像处理常规参数那样处理动态参数 - 无论是错误还是设计。

  

如果我将常规参数的名称更改为不以“角色”开头的内容,则可以正常使用

这部分很重要,并解释了您遇到此问题的原因。 PowerShell会尽可能自动完成参数,如果参数名称不明确,则返回错误。

例如:

PS C:\> Get-help Test -f
Get-Help : Parameter cannot be processed because the parameter name 'f' is ambiguous. Possible matches
include: -Functionality -Full.

在脚本中,使用-R会导致类似的错误,因为脚本无法告诉我们我们指的是-RoleRolePattern。相反,我们得到:

PS C:\> Test-ParameterConflict -R "1"
ParameterSetName = Pattern

Key         Value
---         -----
RolePattern 1

因此,脚本自动完成从-Role-RolePattern 的参数名称。即使标签完整,语法也不然。显然,常规参数的优先级高于动态参数,因此匹配两者的任何内容都将被视为-RolePattern

一种解决方法是使用不同的名称,如原始帖子中所述。另一个是将两个参数都设置为动态或常规。

E.g。将两个参数都设置为动态:

function Test-ParameterConflict {
    [CmdletBinding(DefaultParameterSetName = 'Dynamic')]
    [OutputType()]

    Param (
    )

    dynamicParam {
            # Create the dictionary 
            $runtimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

            # Set the dynamic parameter's name
            $parameterName = 'Role'

            # Create and set the parameter's attributes
            $parameterAttribute = New-Object System.Management.Automation.ParameterAttribute
            $parameterAttribute.Mandatory = $true
            $parameterAttribute.ValueFromPipeline = $true
            $parameterAttribute.ValueFromPipelineByPropertyName = $true
            $parameterAttribute.ParameterSetName = 'Dynamic'

            # Create the collection of attributes
            $attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]

            # Add the attributes to the attributes collection
            $attributeCollection.Add($parameterAttribute)

            # Generate and set the ValidateSet 
            $validValues = @('Role1', 'Role2', 'Role3')
            $validateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($validValues)

            # Add the ValidateSet to the attributes collection
            $attributeCollection.Add($validateSetAttribute)

            # Create and add the dynamic parameter to the dictionary
            $runtimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($parameterName, [string[]], $attributeCollection)
            $runtimeParameterDictionary.Add($parameterName, $runtimeParameter)

            #===============================================================================
            # Copied from above, with different $parameterName and $validValues

            $parameterName = 'RolePattern'

            $parameterAttribute = New-Object System.Management.Automation.ParameterAttribute
            $parameterAttribute.Mandatory = $true
            $parameterAttribute.ValueFromPipeline = $true
            $parameterAttribute.ValueFromPipelineByPropertyName = $true
            $parameterAttribute.ParameterSetName = 'Pattern'
            $attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($parameterAttribute)

            $validValues = @('Role4', 'Role5', 'Role6')

            $validateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($validValues)
            $attributeCollection.Add($validateSetAttribute)
            $runtimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($parameterName, [string[]], $attributeCollection)
            $runtimeParameterDictionary.Add($parameterName, $runtimeParameter)
             #===============================================================================

            return $runtimeParameterDictionary
    }

    Process {
        "ParameterSetName = $($PSCmdlet.ParameterSetName)"
        $PSCmdlet.MyInvocation.BoundParameters
    }
}