Search code examples
powershellvalidateset

how to get Value from pipeline for a DynamicParam in powershell


My goal is to have a parameter for a powershell functions that supports both

  1. ValidateSet (and the tab-complition) for a set that is known only in runtime
  2. ability to supply the parameter via the pipeline.

I was able to achieve #1, but looks like #2 fails.

Here's a simplified example of my code: initially i had a simple function that prints all parameter names that were supplied to the function. the ValidateSet was static and not generated at runtime. the function is defined as following:

Function Test-Static {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$true, ValueFromPipeline = $true, Position=1)]
        [ValidateSet("val1","val2")]
        $Static
    )

    begin {}
    process {
    Write-Host "bound parameters: $($PSBoundParameters.Keys)"
    }
}

when running the following code

"val1" | Test-Static

the output is

bound parameters: Static

I then moved on to try to do the exact same thing with a dynamic parameter, but it looks like $PsBoundParameters is empty. note that if i'm supplying the value as an argument and not via the pipeline, it does show up in $PsBoundParameters.

Function Test-Dynamic {
    [CmdletBinding()]
    Param(
    )

    DynamicParam {
            # Set the dynamic parameters' name
            $ParameterName = 'Dynamic'

            # 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
            $ParameterAttribute.ValueFromPipeline = $true

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

            # Generate and set the ValidateSet 
            $arrSet = "val1","val2"
            $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
        write-host "bound parameters: $($PsBoundParameters.Keys)"
        $Param = $PsBoundParameters[$ParameterName]
    }

    process {
    }

}

when running

"val1" | test-Dynamic i'm getting the following result:

bound parameters:

which basically means that no parameters are bound.

What am i doing wrong? How can i achieve my original goal?


Solution

  • @CB has the right idea here.

    You can't access the pipeline data from the begin block; only from the process block.

    The begin block will have access to the parameter if it's passed as a named or positional parameter, but not via the pipeline.

    This is true whether you're using dynamic parameters or not.