Search code examples
arrayspowershellvalidateset

How to have a Powershell validatescript parameter pulling from an array?


I have a module with a lot of advanced functions. I need to use a long list of ValidateSet parameters. I would like to put the whole list of possible parameters in an array and then use that array in the functions themselves. How can I pull the list of the whole set from an array?

New-Variable -Name vars3 -Option Constant -Value @("Banana","Apple","PineApple")
function TEST123 {
    param ([ValidateScript({$vars3})]
    $Fruit)
    Write-Host "$Fruit"
}

The problem is that when I use the function it doesn't pull the content from the constant.

TEST123 -Fruit 

If I specify the indexed value of the constant then it works.

TEST123 -Fruit $vars3[1] 

It returns Apple.


Solution

  • You are misunderstanding how ValidateScript ...

    ValidateScript Validation Attribute

    The ValidateScript attribute specifies a script that is used to validate a parameter or variable value. PowerShell pipes the value to the script, and generates an error if the script returns $false or if the script throws an exception.

    When you use the ValidateScript attribute, the value that is being validated is mapped to the $_ variable. You can use the $_ variable to refer to the value in the script.

    ... works. As the others have pointed out thus far. You are not using a script you are using a static variable.

    To get what I believe you are after, you would do it, this way.

    (Note, that Write- is also not needed, since output to the screen is the default in PowerShell. Even so, avoid using Write-Host, except for in targeted scenarios, like using color screen output. Yet, even then, you don't need it for that either. There are several cmdlets that can be used, and ways of getting color with more flexibility. See these listed MS powershelgallery.com modules)*

    Find-Module -Name '*Color*'
    

    Tweaking your code you posted, and incorporating what Ansgar Wiechers, is showing you.

    $ValidateSet =   @('Banana','Apple','PineApple') # (Get-Content -Path 'E:\Temp\FruitValidationSet.txt')
    
    function Test-LongValidateSet
    {
        [CmdletBinding()]
        [Alias('tlfvs')]
    
        Param
        (
            [Validatescript({
                if ($ValidateSet -contains $PSItem) {$true}
                else { throw $ValidateSet}})]
            [String]$Fruit
        )
    
        "The selected fruit was: $Fruit"
    }
    
    # Results - will provide intellisense for the target $ValidateSet
    Test-LongValidateSet -Fruit Apple
    Test-LongValidateSet -Fruit Dog
    
    
    # Results
    
    The selected fruit was: Apple
    
    # and on failure, spot that list out. So, you'll want to decide how to handle that
    
    Test-LongValidateSet -Fruit Dog
    Test-LongValidateSet : Cannot validate argument on parameter 'Fruit'. Banana Apple PineApple
    At line:1 char:29
    

    Just add to the text array / file but this also means, that file has to be on every host you use this code on or at least be able to reach a UNC share to get to it.

    Now, you can use the other documented "dynamic parameter validate set". the Lee_Daily points you to lookup, but that is a bit longer in the tooth to get going.

    Example:

    function Test-LongValidateSet
    {
        [CmdletBinding()]
        [Alias('tlfvs')]
    
        Param
        (
            # Any other parameters can go here
        )
    
        DynamicParam
        {
            # Set the dynamic parameters' name
            $ParameterName = 'Fruit'
    
            # 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-Content -Path 'E:\Temp\FruitValidationSet.txt'
            $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
            $Fruit = $PsBoundParameters[$ParameterName]
        }
    
        process
        {
            # Your code goes here
            $Fruit
        }
    
    }
    
    # Results - provide intellisense for the target $arrSet
    Test-LongValidateSet -Fruit Banana
    Test-LongValidateSet -Fruit Cat
    
    # Results
    
    Test-LongValidateSet -Fruit Banana
    Banana
    
    Test-LongValidateSet -Fruit Cat
    Test-LongValidateSet : Cannot validate argument on parameter 'Fruit'. The argument "Cat" does not belong to the set "Banana,Apple,PineApple" 
    specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again.
    At line:1 char:29
    

    Again, just add to the text to the file, and again, this also means, that file has to be on every host you use this code on or at least be able to reach a UNC share to get to it.