Using Advanced Parameter Sets in a Function with Multiple Unique Switches

2

1

I am using Powershell 4.0.

I am attempting to write a cmdlet and in this cmdlet I would like to use Advanced Parameter sets to have certain options available based on what parameter(s) is/are chosen. This particular function will essentially and eventually be Get-ADComputer but with the -SearchBase preprogrammed for certain options.

I have 6 parameters total. 2 are strings ($ComputerName or $IpAddress), 1 is an integer ($OULevel) and 3 switches ($ComputerOU, $AllCompany, $List).

I have a parameter set each for ComputerName and IPAddress, I would like the user to be able to input one or the other - I think I have this figured out its pretty simple. However, I would like $OULevel, $ComputerOU and $AllCompany to be exclusive meaning if one is used the other should not be able to be used. $List should remain available in each scenario.

I have tried different variations of the parameter sets to no avail. This is what my script looks like now, with some trimmed back:

    function Get-CompanyADComputer{
         [CmdletBinding(DefaultParametersetName="ComputerName")]

    Param(
        [Parameter(Mandatory=$true,
                    ParameterSetName="ComputerName",
                    Position=0,
                    ValueFromPipeline=$false,
                    HelpMessage='Enter a computer name to search in ActiveDirectory.')]
        [Alias('Computer','CN')]
        [string]$ComputerName,

        [Parameter(Mandatory=$true,
                    ParameterSetName="IPAddress",
                    Position=0,
                    ValueFromPipeline=$false,
                    HelpMessage='Enter an IP address to search in ActiveDirectory.')]
        [Alias('IPv4Address','IPv6Address')]
        [string]$IPAddress,

        [Parameter(Mandatory=$false,
                    HelpMessage='Enter a number between 0 and 8. 0 is your current OU Container.')]
        [ValidateRange(0,8)]
        [int]$OULevel = 0,

        [Parameter()]
        [Switch]$ComputerOU,

        [Parameter()]
        [Switch]$AllCompany,

        [Parameter()]
        [Switch]$List
    )

If you are curious our AD is organized by Location, then category (computer, user, groups, contacts, etc) and then it gets more granular in each OU below. This script detects your computer's OU and starts the search there. The purpose of $OULevel is if the user specifies a different number the search will start in a different OU and then search recursively. The purpose of $ComputerOU is to have your search go to the default Computers OU instead of the entire domain or your location. The purpose of $AllCompany is to have the search default to the entire domain instead of any other choice or OU.

Any guidance is appreciated. I can't seem to get the hang of this one without my script getting all convoluted.

cyborgcommando0

Posted 2015-06-18T23:38:08.277

Reputation: 803

Answers

2

I asked Don Jones the powershell guru on another forum and he gave me the info I needed. He explained it to me by saying this:

If I'm understanding the question, then you basically have to factor out all the possible combinations. Remember that a param can belong to 1+ param sets. So, you might have a set with Computername and OULevel, Computername and ComputerOU, and Computername and AllCompany. That's three. Then those three again for IPAddress. I know it's not elegant, but look at the help for Where-Object – not elegant, either, by far. List would then not belong to a set, which means it would belong to all.

That put me on the right track. So I actually ended up changing the way my cmdlet worked so my answer was reworked but now that I understand what to do I will update my existing example so I can be consistent and hopefully help.

    function Get-CompanyADComputer{
     [CmdletBinding(DefaultParametersetName="ComputerName")]

Param(
    [Parameter(Mandatory=$true,
                ParameterSetName="ComputerName",
                Position=0,
                ValueFromPipeline=$false,
                HelpMessage='Enter a computer name to search in ActiveDirectory.')]
    [Parameter(Mandatory=$true,
                ParameterSetName="ComputerNameOULevel",
                Position=0,
                ValueFromPipeline=$false,
                HelpMessage='Enter a computer name to search in ActiveDirectory.')]
    [Parameter(Mandatory=$true,
                ParameterSetName="ComputerNameComputerOU",
                Position=0,
                ValueFromPipeline=$false,
                HelpMessage='Enter a computer name to search in ActiveDirectory.')]
    [Parameter(Mandatory=$true,
                ParameterSetName="ComputerNameAllCompany",
                Position=0,
                ValueFromPipeline=$false,
                HelpMessage='Enter a computer name to search in ActiveDirectory.')]
    [Alias('Computer','CN')]
    [string]$ComputerName,

    [Parameter(Mandatory=$true,
                ParameterSetName="IPAddress",
                Position=0,
                ValueFromPipeline=$false,
                HelpMessage='Enter an IP address to search in ActiveDirectory.')]
    [Parameter(Mandatory=$true,
                ParameterSetName="IPAddressOULevel",
                Position=0,
                ValueFromPipeline=$false,
                HelpMessage='Enter an IP address to search in ActiveDirectory.')]
    [Parameter(Mandatory=$true,
                ParameterSetName="IPAddressComputerOU",
                Position=0,
                ValueFromPipeline=$false,
                HelpMessage='Enter an IP address to search in ActiveDirectory.')]
    [Parameter(Mandatory=$true,
                ParameterSetName="IPAddressAllCompany",
                Position=0,
                ValueFromPipeline=$false,
                HelpMessage='Enter an IP address to search in ActiveDirectory.')]
    [Alias('IPv4Address','IPv6Address')]
    [string]$IPAddress,

    [Parameter(Mandatory=$false,
                ParameterSetName="ComputerNameOULevel",
                HelpMessage='Enter a number between 0 and 8. 0 is your current OU Container.')]
    [Parameter(Mandatory=$false,
                ParameterSetName="IPAddressOULevel",
                HelpMessage='Enter a number between 0 and 8. 0 is your current OU Container.')]
    [ValidateRange(0,8)]
    [int]$OULevel = 0,

    [Parameter(ParameterSetName="ComputerNameComputerOU")]
    [Parameter(ParameterSetName="IPAddressComputerOU")]
    [Switch]$ComputerOU,

    [Parameter(ParameterSetName="ComputerNameAllCompany")]
    [Parameter(ParameterSetName="IPAddressAllCompany")]
    [Switch]$AllCompany,

    [Parameter()]
    [Switch]$List
)

Since I did not want those 3 parameters to be used with each other they had to belong to their own Parameter Sets so when you try to use one parameter, the others will not appear as an option. This greatly helps and simplifies the scripting process itself. Instead of allowing for the script it self to account for user input, the Powershell parameter sets eliminate those options.

The $List parameter does not have a Parameter Set Name because I want that parameter to be available in every scenario.

cyborgcommando0

Posted 2015-06-18T23:38:08.277

Reputation: 803

0

Here is the code that uses DynamicParameters and New-DynamicParameter function to create them:

# DotSource New-DynamicParameter function
. '.\New-DynamicParameter.ps1'

function Get-CompanyADComputer
{
    [CmdletBinding(DefaultParametersetName = 'ComputerName_AllCompany')]
    Param()
    DynamicParam
    {
        $BaseParameters = @(
            @{
                Name = 'ComputerName'
                Type = [string]
                Mandatory = $true
                ParameterSetName = 'ComputerName'
                HelpMessage = 'Enter a computer name to search in ActiveDirectory.'
                Alias = 'Computer', 'CN'
            },
            @{
                Name = 'IPAddress'
                Type = [System.Net.IPAddress]
                Mandatory = $true
                ParameterSetName = 'IPAddress'
                HelpMessage = 'Enter an IP address to search in ActiveDirectory.'
                Alias = 'IPv4Address', 'IPv6Address'
            }
        )

        $MutuallyExclusiveParameters = @(
            @{
                Name = 'OULevel'
                HelpMessage = 'Enter a number between 0 and 8. 0 is your current OU Container.'
                ValidateRange = 0, 8
                Type = [int]
            }
            @{
                Name = 'ComputerOU'
                Type = [switch]
            },
            @{
                Name = 'AllCompany'
                Type = [switch]
            }
        )

        $AllParamSetParameters = @(
            @{
                Name = 'List'
                Type = [switch]
            }
        )

        $DynamicParameters = (
            # For each base parameter
            $BaseParameters | ForEach-Object {
                # Iterate over mutually exclusive parameters
                $MutuallyExclusiveParameters | ForEach-Object -Begin {$BaseParam = $_} -Process {
                    # Generate new ParameterSet name: Base parameter ParameterSetName + mutually exclusive parameter name
                    $CurrParamSetName = '{0}_{1}' -f $BaseParam.ParameterSetName, $_.Name

                    # Clone base parameter, so we modify copy of it
                    $NewBaseParam = $BaseParam.Clone()
                    # Set its ParameterSetName
                    $NewBaseParam.ParameterSetName = $CurrParamSetName

                    # Clone mutually exclusive parameter, so we modify copy of it
                    $NewMEParam = $_.Clone()
                        # Set its ParameterSetName
                    $NewMEParam.ParameterSetName = $CurrParamSetName

                    # Output new base parameter and new mutually exclusive parameter
                    $NewBaseParam
                    $NewMEParam
                }
            }
        ) + $AllParamSetParameters # Add parameters that should exist in all parameter sets

        # Create and output new dynamic parameters
        $DynamicParameters | ForEach-Object {New-Object -TypeName psobject -Property $_} | New-DynamicParameter
    }

    Process
    {
        # Dynamic parameters don't have corresponding variables created,
        # you need to call New-DynamicParameter with CreateVariables switch to fix that.
        New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters

        # Show all parameters
        $PSBoundParameters | Format-Table -AutoSize -HideTableHeaders | Out-String

        <#

            Your code here...

        #>
    }

}

beatcracker

Posted 2015-06-18T23:38:08.277

Reputation: 2 334