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