Powershell

Get all Switch Parameters for a Powershell function or script

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 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.