I’m writing a script to deploy Azure VMware Solution (AVS) and ran into a situation many of us likely have: Some parameters depend on other parameters.
I started with Parameter Sets where I did have several parameters participating in multiple Parameter Sets, but that didn’t work how I thought it would (or should).
Here’s what didn’t work:
1 2 3 4 5 6 7 8 9 10 11 12 |
[CmdletBinding(DefaultParametersetName="cli")] param( [Parameter(ParameterSetName="cli")][Parameter(ParameterSetName="createVNET")][Parameter(Mandatory,ParameterSetName="VMInternet")][switch]$createVNET, [Parameter(ParameterSetName="cli")][Parameter(Mandatory,ParameterSetName="createVNET")][Parameter(Mandatory,ParameterSetName="VMInternet")][string]$vNetIPSubnet, [Parameter(ParameterSetName="cli")][Parameter(Mandatory,ParameterSetName="createVNET")][Parameter(Mandatory,ParameterSetName="VMInternet")][string]$vNetGatewaySubnet, [Parameter(ParameterSetName="cli")][Parameter(Mandatory,ParameterSetName="createVNET")][Parameter(Mandatory,ParameterSetName="VMInternet")][string]$vNetBastionSubnet, [Parameter(ParameterSetName="cli")][Parameter(Mandatory,ParameterSetName="createVNET")][Parameter(Mandatory,ParameterSetName="VMInternet")][string]$vNetManagementSubnet [Parameter(ParameterSetName="cli")][Parameter(ParameterSetName="VMInternet")][switch]$EnableVMInternet, [Parameter(ParameterSetName="cli")][Parameter(Mandatory,ParameterSetName="VMInternet")][string]$vNetFirewallSubnet, [Parameter(ParameterSetName="cli")][Parameter(Mandatory,ParameterSetName="VMInternet")][string]$vNetHubSubnet ) |
My intention was to have additional mandatory parameters based on additional switches. For instance, if you add “-createvNet”, the script needs four additional parameters. Also, if you used “-EnableVMInternet” without “-createvNET”, the script will also need to recognize that wasn’t supplied and make the parameters with it mandatory. Spoiler: that didn’t work.
The problem I had was using “-createvNET” doesn’t actually force the four additional parameters to mandatory, since the ParameterSet is “cli” by default. I tried to set the “-createVNET” switch to it’s own parameter set, but that’s where the either/or came in. When I tried to use the mandatory parameters from “cli” AND “createvNET”, PowerShell threw the error:
1 2 |
Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided. |
This won’t work for me because the Parameter Set is “cli”, my additional parameters needed to create the vNet aren’t mandatory, so I decided to try my hand at Dynamic Parameters. These are more complicated because they’re basically built during runtime based on whatever criteria you supply.
In my case, I wanted to start with just the four parameters that become required when supplying the “-createVNET” switch.
Here’s what that looks like (this is my first stab at Dynamic Parameters, fyi):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
[CmdletBinding(DefaultParametersetName="cli")] param( [Parameter(ParameterSetName="cli")][switch]$createVNET, [Parameter(ParameterSetName="cli")][switch]$EnableVMInternet, [Parameter(ParameterSetName="cli")][string]$vNetFirewallSubnet, [Parameter(ParameterSetName="cli")][string]$vNetHubSubnet ) DynamicParam{ if ($createvNET){ $dynamicParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $vNetIPSubnetAttribute = New-Object System.Management.Automation.ParameterAttribute $vNetIPSubnetAttribute.Position = 9 $vNetIPSubnetAttribute.Mandatory = $true $vNetIPSubnetAttribute.HelpMessage = "Please enter a /24 subnet for the overall vNet" $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($vNetIPSubnetAttribute) $dynamicParam = New-Object System.Management.Automation.RuntimeDefinedParameter('vNetIPSubnet',[string],$attributeCollection) $dynamicParamDictionary.Add('vNetIPSubnet',$dynamicParam) $vNetGatewaySubnetAttribute = New-Object System.Management.Automation.ParameterAttribute $vNetGatewaySubnetAttribute.Position = 10 $vNetGatewaySubnetAttribute.Mandatory = $true $vNetGatewaySubnetAttribute.HelpMessage = "Enter a /26 subnet that's in the /24 supplied for the vNet" $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($vNetGatewaySubnetAttribute) $dynamicParam = New-Object System.Management.Automation.RuntimeDefinedParameter('vNetGatewaySubnet',[string],$attributeCollection) $dynamicParamDictionary.Add('vNetGatewaySubnet',$dynamicParam) $vNetBastionSubnetAttribute = New-Object System.Management.Automation.ParameterAttribute $vNetBastionSubnetAttribute.Position = 11 $vNetBastionSubnetAttribute.Mandatory = $true $vNetBastionSubnetAttribute.HelpMessage = "Enter a /26 subnet that's in the /24 supplied for the vNet" $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($vNetBastionSubnetAttribute) $dynamicParam = New-Object System.Management.Automation.RuntimeDefinedParameter('vNetBastionSubnet',[string],$attributeCollection) $dynamicParamDictionary.Add('vNetBastionSubnet',$dynamicParam) $vNetManagementSubnetAttribute = New-Object System.Management.Automation.ParameterAttribute $vNetManagementSubnetAttribute.Position = 12 $vNetManagementSubnetAttribute.Mandatory = $true $vNetManagementSubnetAttribute.HelpMessage = "Enter a /26 subnet that's in the /24 supplied for the vNet" $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($vNetManagementSubnetAttribute) $dynamicParam = New-Object System.Management.Automation.RuntimeDefinedParameter('vNetManagementSubnet',[string],$attributeCollection) $dynamicParamDictionary.Add('vNetManagementSubnet',$dynamicParam) return $dynamicParamDictionary } } |
This actually worked perfectly as desired in two scenarios:
- If I only provided “-createVNET”, the script would prompt for the four missing parameters.
- I could supply “-createVNET” along with the additional four mandatory parameters and it’d work directly in the single CLI.
That’s a lot of code for four parameters, though, and in three months (or three days), I’ll likely forget how this all works. I still have other parameters and dependencies that need to be accounted for. As functional as this is, I might scrap it.
Let me know what you think in the comments.