Search code examples
powershellpowershell-coredynamicparameters

Dynamic Parameter cannot be specified in parameter set


Situation:
Powershell 7.4 on Windows 11; playing with Functions; attempting to learn working Dynamic Parameters.

(Which is why I'm making a completely redundant Dynamic Parameter, I know I could just use -Recurse as INT with a default value and call it a day 😉 )

What I do:
I call the function with the -Recurse parameter, or with both -Recurse and -RecurseMax(giving it a INT value, ex: -Recurse -RecurseMax 1)

What I want\expect:
if I call the function with the parameter -Recurse, the dynamic parameter -RecurseMax should become available to the user to chose and, when chosen, the function should still work. I mean, i don't even have implemented it in process{} yet.

What I get\Problem:

  • -RecurseMax never becomes available to the user, even while using -Recurse
  • Whenever I try to call -RecurseMax alongside -Recurse i get a error: Get-DirectoryItemMax: Parameter 'RecurseMax' cannot be specified in parameter set '__AllParameterSets'.

To Note:

  • trying to call -RecurseMax wihtout -Recurse gives the expected Get-DirectoryItemMax: A parameter cannot be found that matches parameter name 'RecurseMax'. error
  • trying to call-RecurseMax wihtout giving it a Value gives the expected Get-DirectoryItemMax: Missing an argument for parameter 'RecurseMax'. Specify a parameter of type 'System.Int32' and try again. error

I'm probably missing something small... or I'm getting everything wrong

Relevant part of the code:

function Get-DirectoryItemMax {
    [CmdletBinding()]
    [Alias('Get-Dir', 'GDMax')]
    param (
        # Directory to list
        [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName )]
        [PSDefaultValue(Help = '$PWD (=Present Working Directory)')]
        [ValidateScript({ Test-Path -PathType Container -Path $_ }, ErrorMessage = { '"{0}" non esiste o non è una Directory' })]
        [string]$Path = $PWD,

        [Parameter(ValueFromPipelineByPropertyName)]
        [PSDefaultValue(Value = '*', Help = "'*' (=everything); NOT A A REGEX")]
        [string]$Pattern = '*',



        [Parameter(ValueFromPipelineByPropertyName)]
        [switch]$Recurse

    )
    
    DynamicParam {
        if ($Recurse) {
            $parameterAttribute = [System.Management.Automation.ParameterAttribute]::new()

            $parameterValidation = [System.Management.Automation.ValidateRangeAttribute]::new(1, [Int32]::MaxValue )
            
            
            $attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
            
            $attributeCollection.Add($parameterAttribute)
            $attributeCollection.Add($parameterValidation)
            
            
            $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]@{
                Name          = 'RecurseMax'
                ParameterType = [Int32]
                Value         = $attributeCollection
            }

            $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()

            $paramDictionary.Add('RecurseMax', $dynParam1)
            
            return $paramDictionary
        }
    }

  process { ... }

Solution

  • You're assigning the attribute collection to the default value expression of the parameter (the expression that usually goes on the right hand side in [Parameter()][int]$RecurseMax = $($attributeCollection)):

    $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]@{
        Name          = 'RecurseMax'
        ParameterType = [Int32]
        Value         = $attributeCollection
    }
    

    Use the appropriate constructor instead:

    $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new('RecurseMax', [int], $attributeCollection)