Search code examples
powershellvalidateset

Powershell [ValidateSet()] Between Separate Parameter Sets Using Same Parameter Name


OK, so I'm trying to write an advanced function that uses two different parameter set names, one is Default the other is TestAccountsOnly.

Most of this works fine, however, here's my problem:

The output of Get-Help New-SecondaryAccount gives me this in the SYNTAX section:

SYNTAX
    New-SecondaryAccount [-Name] <String> [-AccountType] <String> [-Password] <String> [-Description] <String> [-OwnerEmployeeID] <String> 
    [[-AdditionalDescription]] [<CommonParameters>]

    New-SecondaryAccount [-Name] <String> [-AccountType] <String> [-Password] <String> [-CoreOrReserved] <String> [-Description] <String> 
    [-OwnerEmployeeID] <String> [[-AdditionalDescription]] [<CommonParameters>]

From the looks of it, this is exactly what I want - one parameter set where I can validate a list of a handful of different -AccountTypes and move along where I have passwords, descriptions, etc., and the other where I validate just one value for AccountType and have a CoreOrReserve parameter that only belongs to the TestAccountsOnly parameter set.

Unfortunately, when trying to test this in the ISE, if I type:

New-SecondaryAccount -Name mehSomeAccount -AccountType, the only suggestion I get from IntelliSense is Test.

Can you not use [ValidateSet()] the way I'm trying to, or am I just doing it wrong?

Would really appreciate it if someone could point this out!

Function New-SecondaryAccount(DefaultParameterSetName="Default")
{
<#
.Synopsis
   Creates a new secondary account based on the parameters
.DESCRIPTION
    Creates a secondary AD user account based on parameters
    specified. This includes several different types of accounts,
    and determines the employeeType, OU, and description values
    of the account created.

    The CoreOrReserved parameter can only be used for accounts
    where AccountType is set to Test
.INPUTS
   [String]
.OUTPUTS
   [ADObject]
.NOTES

.COMPONENT
    MyModule_Part1
.FUNCTIONALITY
   Active Directory Things
#>
    [cmdletBinding(DefaultParameterSetName="Default")]
    param(
        [Parameter(Mandatory=$True,
                    Position=0,
                    ParameterSetName="Default",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory=$True,
                    Position=0,
                    ParameterSetName="TestAccountsOnly",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory=$True,
                    Position=1,
                    ParameterSetName="Default")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('ADAdmin','ServerAdmin','ServiceAccount','ChuckNorris')]
        [Parameter(Mandatory=$True,
                    Position=1,
                    ParameterSetName="TestAccountsOnly")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Test")]
        [String]$AccountType,

        [Parameter(Mandatory=$True,
                    Position=2,
                    ParameterSetName="Default")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateScript(
        {
            if($_.Length -ge 12)
            {
                $True
            }
            else
            {
                throw "Password must be at least 12 characters"
                $False
            }
        })]
        [Parameter(Mandatory=$True,
                    Position=3,
                    ParameterSetName="TestAccountsOnly")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateScript(
        {
            if($_.Length -ge 12)
            {
                $True
            }
            else
            {
                throw "Password must be at least 12 characters"
                $False
            }
        })]
        [String]$Password,

        [Parameter(Mandatory=$True,
                    Position=2,
                    ParameterSetName="TestAccountsOnly")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Core","Reserved")]
        [String]$CoreOrReserved,

        [Parameter(Mandatory=$True,
                    Position=3,
                    ParameterSetName="Default")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateScript(
        {
            if($_ -match "^TASK\d{7}\b")
            {
                $True
            }
            else
            {
                throw "Description must be a TASK number only`nEx. TASK1234567"
                $False
            }
        })]
        [Parameter(Mandatory=$True,
                    Position=4,
                    ParameterSetName="TestAccountsOnly")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateScript(
        {
            if($_ -match "^TASK\d{7}\b")
            {
                $True
            }
            else
            {
                throw "Description must be a TASK number only`nEx. TASK1234567"
                $False
            }
        })]
        [String]$Description,

        [Parameter(Mandatory=$True,
                    Position=4,
                    ParameterSetName="Default")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateScript(
        {
            if($(Get-ADUser -Filter {EmployeeID -eq $_ -and EmployeeType -eq "E"}) -ne $NULL)
            {
                $True
            }
            else
            {
                throw "$_ must correspond to a valid FTE user's employeeID number"
                $False
            }
        })]
        [Parameter(Mandatory=$True,
                    Position=5,
                    ParameterSetName="TestAccountsOnly")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateScript(
        {
            if($(Get-ADUser -Filter {EmployeeID -eq $_ -and EmployeeType -eq "E"}) -ne $NULL)
            {
                $True
            }
            else
            {
                throw "$_ must correspond to a valid FTE user's employeeID number"
                $False
            }
        })]
        [String]$OwnerEmployeeID,

        [Parameter(Mandatory=$False,
                    ParameterSetName="Default",
                    Position=5)]
        [Parameter(Mandatory=$False,
                    ParameterSetName="TestAccountsOnly",
                    Position=6)]
        [Switch]$AdditionalDescription

    )
    BEGIN{}
    PROCESS{# implementation doing all the things here}
    END{}

Solution

  • Unfortunately, you cannot declare more than one validate set attribute per parameter, which is one reason why its designation is separate.

    You might be able to play around with dynamic parameters to get what you want. I stripped out a lot of stuff for clarity.

    function New-SecondaryAccount() {
        [cmdletBinding()]
        param (
            [Parameter(Mandatory,
                Position = 0,
                ValueFromPipeline,
                ValueFromPipelineByPropertyName)]
            [string] $Name,
    
            [Parameter(Mandatory, Position = 1)]
            [string] $Password,
    
            [Parameter(Position = 2)]
            [switch] $TestAccount
        )
        DynamicParam {
            $attribute = New-Object System.Management.Automation.ParameterAttribute
            $attribute.Mandatory = $true
    
            $collection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
            $collection.Add($attribute)
    
            if ($TestAccount) {
                $validationSet = @("Test")
            } else {
                $validationSet = @("ADAdmin", "ServerAdmin", "ServiceAccount", "ChuckNorris")
            }
            $collection.Add((New-Object System.Management.Automation.ValidateSetAttribute($validationSet)))  
    
            $param = New-Object System.Management.Automation.RuntimeDefinedParameter('AccountType', [string], $collection)
            $dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
            $dictionary.Add('AccountType', $param)  
    
            return $dictionary
        }
    
        PROCESS {
            <# implementation doing all the things here #>
        }
    }