2

I was struggling in a situation where I need to make some parameters mandatory ONLY if a switch or combination of switches is used. Below is the example of what I am trying to do:

[CmdletBinding(DefaultParameterSetName='DefaultConfiguration')]
Param
(        
[Parameter(Mandatory=$true)][String]$Location,
[Parameter(Mandatory=$true)][String]$DPMServername,

[Parameter(Mandatory=$False, ParameterSetName='CustomConfiguration')]
[Switch]$CustomizeDPMSubscriptionSettings,
[Parameter(Mandatory=$True, ParameterSetName='CustomConfiguration')]
[String]$StagingAreaPath,

[Parameter(Mandatory=$False, ParameterSetName='EncryptionSettings')]
[Parameter(ParameterSetName='CustomConfiguration')]
[Switch]$SetEncryption,
[Parameter(Mandatory=$true, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$False, ParameterSetName='CustomConfiguration')]
[String]$EncryptionPassPhrase,

[Parameter(Mandatory=$False, ParameterSetName='ProxyEnabled')]
[Parameter(ParameterSetName='CustomConfiguration')]
[Switch]$SetProxy,
[Parameter(Mandatory=$true, ParameterSetName='ProxyEnabled')]
[Parameter(ParameterSetName='CustomConfiguration')]
[String]$ProxyServerAddress,
[Parameter(Mandatory=$true, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$False, ParameterSetName='CustomConfiguration')]
[String]$ProxyServerPort
)

Here, I need to follow below conditions:

  1. If -CustomizeDPMSubscriptionSettings (Switch) parameter is used, it must ask for the Staging AreaPath ---- This is Working fine
  2. ONLY when -CustomizeDPMSubscriptionSettings (Switch) parameter is used with -SetEncryption, it must ask for -EncryptionPassPhrase
  3. And ONLY when -CustomizeDPMSubscriptionSettings (Switch) parameter is used with -SetProxy, it must ask for -ProxyServerAddress and -ProxyServerPort

Sorry if this sounds like a repeated question but other posts I found here are not helping me solve my issue. I am confused :-(

NOTE: Above code is part of what I was trying with different combinations. Please correct as necessary.

SavindraSingh
  • 878
  • 13
  • 39
  • What are the possible combinations? Can you use -SetEncryption and -SetProxy at the same time? – Poorkenny Dec 18 '15 at 11:21
  • Yes I can. But even in that case -CustomizeDPMSubscriptionSettings should be used Thus, all possible combinations are: -CustomizeDPMSubscriptionSettings -SetEncryption, -CustomizeDPMSubscriptionSettings -SetProxy AND -CustomizeDPMSubscriptionSettings -SetEncryption -SetProxy – SavindraSingh Dec 18 '15 at 11:28
  • My point here is it must ask for all Encryption related parameters when combination of `-CustomizeDPMSubscriptionSettings -SetEncryption` is used. And same goes with Proxy related parameters. – SavindraSingh Dec 18 '15 at 11:35

1 Answers1

4

Here is a solution that seems to do what you expect.
What I did was create a parameter set for each possible combination.
- CustomConfiguration
- EncryptionSettings
- ProxyEnabled
- EncryptionAndProxy


One limitation is that it will not prompt for specific missing parameters unless using EncryptionAndProxy, but will instead state that it cannot resolve the parameter set.

[CmdletBinding(DefaultParameterSetName='DefaultConfiguration')]
Param
(        
[Parameter(Mandatory=$true)][String]$Location,
[Parameter(Mandatory=$true)][String]$DPMServername,

[Parameter(Mandatory=$True, ParameterSetName='CustomConfiguration')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$True, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[Switch]$CustomizeDPMSubscriptionSettings,

[Parameter(Mandatory=$True, ParameterSetName='CustomConfiguration')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$True, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[String]$StagingAreaPath,

[Parameter(Mandatory=$True, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[Switch]$SetEncryption,

[Parameter(Mandatory=$true, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[String]$EncryptionPassPhrase,

[Parameter(Mandatory=$True, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[Switch]$SetProxy,

[Parameter(Mandatory=$true, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[String]$ProxyServerAddress,

[Parameter(Mandatory=$true, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[String]$ProxyServerPort
)

I'm looking into a second potential solution based on dynamic parameters.

Edit: As promised, here's a solution based on dynamic parameters

[CmdletBinding(DefaultParameterSetName='DefaultConfiguration')]
Param
(        
    [Parameter(Mandatory=$true)][String]$Location,
    [Parameter(Mandatory=$true)][String]$DPMServername,

    [Switch]$CustomizeDPMSubscriptionSettings,
    [Switch]$SetEncryption,
    [Switch]$SetProxy
)

DynamicParam
{
    $paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
    $attributes = New-Object System.Management.Automation.ParameterAttribute
    $attributes.ParameterSetName = "__AllParameterSets"
    $attributes.Mandatory = $true
    $attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
    $attributeCollection.Add($attributes)
    # If "-SetEncryption" is used, then add the "EncryptionPassPhrase" parameter
    if($SetEncryption)
    { 
        $dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("EncryptionPassPhrase", [String], $attributeCollection)   
        $paramDictionary.Add("EncryptionPassPhrase", $dynParam1)
    }
    # If "-SetProxy" is used, then add the "ProxyServerAddress" "ProxyServerPort" and parameters
    if($SetProxy)
    {
        $dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("ProxyServerAddress", [String], $attributeCollection)   
        $paramDictionary.Add("ProxyServerAddress", $dynParam1)
        $dynParam2 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("ProxyServerPort", [String], $attributeCollection)   
        $paramDictionary.Add("ProxyServerPort", $dynParam2)
    }
    # If "-CustomizeDPMSubscriptionSettings" is used, then add the "StagingAreaPath" parameter
    if($CustomizeDPMSubscriptionSettings)
    {
        $dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("StagingAreaPath", [String], $attributeCollection)   
        $paramDictionary.Add("StagingAreaPath", $dynParam1)
    }
    return $paramDictionary
}
Process{
    foreach($key in $PSBoundParameters.keys)
    {
        Set-Variable -Name $key -Value $PSBoundParameters."$key" -Scope 0
    }
}

What this one does is dynamically add parameters to your function based on the presence of each switch.
This supports autocompletion, and has better support for missing parameters. It will explicitly ask for missing parameters if the corresponding switch is used.
Second edit: I added the Process section that's mandatory with this construct, as well as the variable creation bit, which makes things much easier.

Poorkenny
  • 1,246
  • 11
  • 16
  • 1
    Thank you for putting so much efforts in writing this code. However, I will try this tomorrow after reaching office and let you know which one suits me better. – SavindraSingh Dec 20 '15 at 17:19
  • 1
    The second solution worked like charm. You rock @Poorkenny. I appreciate your efforts and inputs made here. Thanks a lot and Merry Christmas in advance :-) – SavindraSingh Dec 21 '15 at 16:30
  • I am sorry to add comments after accepting this as answer, however, it worked fine until I used this individually. But when I pasted this in the final script, it started giving compilation errors. Can you please help me get rid of the compilation errors? How can I share the complete script file as attachment? _**Edit:**_ For instance, if I you add any function after last line of the code, it will not recognize that function. I don't want to put this entire thing in a function as there are many functions in this script file and I have to call them from the script scope. – SavindraSingh Dec 22 '15 at 10:37
  • I have asked another questions with some issues added. Please refer to the same [HERE](http://stackoverflow.com/questions/34418267/using-validate-set-in-dynamic-parameter-powershell) – SavindraSingh Dec 22 '15 at 14:38