Dynamic ValidateSet in a Dynamic Parameter

Dynamic ValidateSet in a Dynamic Parameter

  • Comments 8
  • Likes

A colleague of mine needed a way to have a parameter accept only a specific set of paths. I told him this can be accomplished easily with the ValidateSet decoration on the parameter, but he then explained that what the actually needed, is to have the set dynamically defined by the sub folders in the current location, instead of a pre-defined set. This sent me out on a journey to explore the dynamic parameter world.

The result of that journey, and the answer to his request is the example function below:

function Test-DynamicValidateSet {
    [CmdletBinding()]
    Param(
        # Any other parameters can go here
    )
 
    DynamicParam {
            # Set the dynamic parameters' name
            $ParameterName = 'Path'
            
            # Create the dictionary 
            $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

            # Create the collection of attributes
            $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
            
            # Create and set the parameters' attributes
            $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
            $ParameterAttribute.Mandatory = $true
            $ParameterAttribute.Position = 1

            # Add the attributes to the attributes collection
            $AttributeCollection.Add($ParameterAttribute)

            # Generate and set the ValidateSet 
            $arrSet = Get-ChildItem -Path .\ -Directory | Select-Object -ExpandProperty FullName
            $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)

            # Add the ValidateSet to the attributes collection
            $AttributeCollection.Add($ValidateSetAttribute)

            # Create and return the dynamic parameter
            $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
            $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
            return $RuntimeParameterDictionary
    }

    begin {
        # Bind the parameter to a friendly variable
        $Path = $PsBoundParameters[$ParameterName]
    }

    process {
        # Your code goes here
        dir -Path $Path
    }

}

and then you can use it:

Test-DynamicValidateSet -Path [the magic happens here]

HTH,

\Martin.

Comments
  • Great, this is really helpful!

  • This is sweet! Do you know of a method to trigger the auto-expansion of tab-completed fields?

    I'm in a situation where I'm using this technique to populate a list of OUs for an account migration tool, and it can take a very long time to the values to become available.

    Any tips? I could, of course, export the list of values as an .XML or CSV file and then use switching to provide an easy mechanism for the end user to select the appropriate field, but that gets me farther away from the realm of dynamic.

  • @Stephen Owen, unfortunately there is no way of doing what you ask.
    But you could combine both ways: Using the external xml or csv file you mentioned AND dynamically generating it's content.
    In the DynamicParam block, check the file's LastWriteTime, if it's sufficiently new (X days / X Hours / X minutes), use it for the ValidateSet. If not, regenerate it and then use it.

  • Awesome stuff!

  • Any idea how to do similar dynamic parameter validation, if the cmd-let was written in C#? IDynamicParameters interface doesn't seem to be anywhere close to the capability above (available if function / cmdlet was written in Powershell instead of C#)

  • @Anonymous, I agree it's easier in PowerShell. That's why I like it so much.
    Maybe this article can help you a bit: http://www.powershellmagazine.com/2014/06/23/dynamic-parameters-in-c-cmdlets/

  • You can do exactly the same in a C# Cmdlet. The IDynamicParameters.GetDynamicParameters() method can either return an object that has properties with Parameter attributes (as seen in the linked PowerShellMagazine article), or a RuntimeDefinedParameterDictionary, as seen here in the PowerShell code.

  • That was cool
    Put the function into a module named "Test Dynamic Parameters"
    Created a test folder with 3 folders in it (C:\Test\Folder1)
    I did not run the function but did manage to take a picture

    https://vrb6xw.by3301.livefilestore.com/y2pEu-FMti56vHobeZHoM_6dwiae4b1_JGijzEn7XPzstBLgHM-EWo_9KIqtsAzH-kD4aWk63ioQmnqEuVAuGiPJraRtdgGa4Zn5Qj7puA880w/DynamicParameters.png?psid=1

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment