The other day I was working on a Powershell function to return a list and filter it through a number of switch parameters; anyway if no switch is used I want to return a default, raw result without manipulation, in other words I want the result to look like this:
PS C:\> .\ListSwitchParameters.ps1 -SubscriptionOne -SubscriptionFour Name Value ---- ----- SubscriptionOne 45615ed1-0de1-4ec9-b018-71c0b37eadfd SubscriptionFour 5b9cc023-9250-4421-8bfc-2c98465d97f3 PS C:\> .\ListSwitchParameters.ps1 Name Value ---- ----- SubscriptionOne 45615ed1-0de1-4ec9-b018-71c0b37eadfd SubscriptionTwo 220b4052-c956-4d42-9f74-3d4c111c1c72 SubscriptionThree c70bab09-b330-4557-b856-328bc7ffe1a3 SubscriptionFour 5b9cc023-9250-4421-8bfc-2c98465d97f3 SubscriptionFive 0e9b837d-6b63-41b1-88c1-f42e8325211d
One possible approach to obtain it is code similar to this:
param (
[switch]$SubscriptionOne,
[switch]$SubscriptionTwo,
[switch]$SubscriptionThree,
[switch]$SubscriptionFour,
[switch]$SubscriptionFive
)
$list = @(
@{'SubscriptionOne' = '45615ed1-0de1-4ec9-b018-71c0b37eadfd' },
@{'SubscriptionTwo' = '220b4052-c956-4d42-9f74-3d4c111c1c72' },
@{'SubscriptionThree' = 'c70bab09-b330-4557-b856-328bc7ffe1a3' },
@{'SubscriptionFour' = '5b9cc023-9250-4421-8bfc-2c98465d97f3' },
@{'SubscriptionFive' = '0e9b837d-6b63-41b1-88c1-f42e8325211d' }
)
if ($SubscriptionOne) { $list | where Keys -eq 'SubscriptionOne' }
if ($SubscriptionTwo) { $list | where Keys -eq 'SubscriptionTwo' }
if ($SubscriptionThree) { $list | where Keys -eq 'SubscriptionThree' }
if ($SubscriptionFour) { $list | where Keys -eq 'SubscriptionFour' }
if ($SubscriptionFive) { $list | where Keys -eq 'SubscriptionFive' }
if ((-not $SubscriptionOne) -and (-not $SubscriptionTwo) -and (-not $SubscriptionThree) -and (-not $SubscriptionFour) -and (-not $SubscriptionFive)) {
$list
}
It works, but it’s not very elegant or efficient… for example, what if I need to add more switch options? I would have to add additional if statements but also update the last if to make sure no switch has been used. The example above can be refactored like this:
param (
[switch]$SubscriptionOne,
[switch]$SubscriptionTwo,
[switch]$SubscriptionThree,
[switch]$SubscriptionFour,
[switch]$SubscriptionFive
)
$list = @(
@{'SubscriptionOne' = '45615ed1-0de1-4ec9-b018-71c0b37eadfd' },
@{'SubscriptionTwo' = '220b4052-c956-4d42-9f74-3d4c111c1c72' },
@{'SubscriptionThree' = 'c70bab09-b330-4557-b856-328bc7ffe1a3' },
@{'SubscriptionFour' = '5b9cc023-9250-4421-8bfc-2c98465d97f3' },
@{'SubscriptionFive' = '0e9b837d-6b63-41b1-88c1-f42e8325211d' }
)
$switchParameters = (Get-Command .\ListSwitchParameters.ps1).Parameters.Values | Where-Object SwitchParameter | foreach { Get-Variable $_.Name -ErrorAction 'SilentlyContinue' }
$switchParameters | where Name -in ($switchParameters | where Value).Name
if ($switchParameters.Count -eq ($switchParameters | where -not Value).Count) {
$list
}
The magic happens an line 17, here I have it on a one line but let me break it down: first, we can use Get-Command to retrieve the list of parameters for any script or function (here I have even getting the parameter list for the script ListSwitchParameters.ps1 from within the script itself)
PS C:\> (Get-Command .\ListSwitchParameters.ps1).Parameters
Key Value
--- -----
SubscriptionOne System.Management.Automation.ParameterMetadata
SubscriptionTwo System.Management.Automation.ParameterMetadata
SubscriptionThree System.Management.Automation.ParameterMetadata
SubscriptionFour System.Management.Automation.ParameterMetadata
SubscriptionFive System.Management.Automation.ParameterMetadata
PS C:\> (Get-Command .\ListSwitchParameters.ps1).Parameters.Values | ft
Name ParameterType ParameterSets IsDynamic Aliases Attributes SwitchParameter
---- ------------- ------------- --------- ------- ---------- ---------------
SubscriptionOne System.Management.Automation.SwitchParameter {[__AllParameterSets, System.Management.Automation.ParameterSetMetadata]} False {} {, System.Management.Automation.ArgumentTypeConverterAttribute} True
SubscriptionTwo System.Management.Automation.SwitchParameter {[__AllParameterSets, System.Management.Automation.ParameterSetMetadata]} False {} {, System.Management.Automation.ArgumentTypeConverterAttribute} True
SubscriptionThree System.Management.Automation.SwitchParameter {[__AllParameterSets, System.Management.Automation.ParameterSetMetadata]} False {} {, System.Management.Automation.ArgumentTypeConverterAttribute} True
SubscriptionFour System.Management.Automation.SwitchParameter {[__AllParameterSets, System.Management.Automation.ParameterSetMetadata]} False {} {, System.Management.Automation.ArgumentTypeConverterAttribute} True
SubscriptionFive System.Management.Automation.SwitchParameter {[__AllParameterSets, System.Management.Automation.ParameterSetMetadata]} False {} {, System.Management.Automation.ArgumentTypeConverterAttribute} True
The Values property contains the list of ParameterNames, their type and a boolean indicating if the parameter is a SwitchParameter; since it’s switch parameters we’re looking for, it is easy to filter this list. Last, we can use Get-Variable to retrieve the actual value for each Switch Parameter. Now, I admit my example is not very realistic since I am assuming the Switch Parameter has the same name as the property I want to return from the list but you can still see how with this technique there is no need to explicitly check if each switch parameter has been used or not. This is even clearer in the last if statement, where I am just counting the number of switch parameters whose value is $false and check that number is equal to the total number of switch parameters in the script: if the two values match it means no switch parameter has been used, therefore I can return the raw, unfiltered list
if ($switchParameters.Count -eq ($switchParameters | where -not Value).Count) {
$list
}
I can calculate the motion of heavenly bodies, but not the madness of people – Isaac Newton