Replacing IF statements with a SWITCH statement

Hi,

I’ve created the below script as part of a training exercise to improve my PowerShell skills. It works as expected but could do with some advice on how to replace the IF statements with a switch statement.

Function Get-LocalProcesses {
    # Default to SortByName
    [CmdletBinding(DefaultParameterSetName = 'SortByName')]
    Param (
        [Parameter(ParameterSetName = 'SortByCPU')]
        [switch]$SortByCPU,

        [Parameter(ParameterSetName = 'SortByRAM')]
        [switch]$SortByRAM,

        [Parameter(ParameterSetName = 'SortByName')]
        [switch]$SortByName,

        [int]$ShowFirst = '5'
    )
    # Outputs which parameter is being used with the command
    $PSCmdlet.ParameterSetName

    # Set sort variable depending on switch used
    If ($SortByCPU) {
        $SortChoice = 'cpu'
    }
    If ($SortByRAM) {
        $SortChoice = 'ws'
    }
    If ($SortByName) {
        $SortChoice = 'name'
    }

    # Get local processes using chosen switch in sort cmdlet
    Get-Process | Sort-Object $SortChoice | Select-Object Id, Handles, @{Label = 'WS(k)'; Expression = { ($_.ws / 1024) } }, @{Label = 'CPU(m)'; Expression = { ($_.cpu).tostring("#.##") } }, @{Label = 'Priority'; Expression = { ($_.Priorityclass) } }, Name, Description -First $ShowFirst | FT -AutoSize
}

Get-LocalProcesses -SortByRAM

Any advice would be very much appreciated.

Cheers

Jamie

As you use Powershell cmdlets, pay attention to how they are named and the parameter names and how they are used.

  • Singular - Notice how cmdlets are named singular (e.g Get-User, Get-Service, Get-Process), not Get-Processes
  • Function Purpose - For what you are doing, the function should just return data. Get-Data | Sort-Data. If you look at other cmdlets, they don't have sort capabilities because the goal of the function should be just to get the data, so you would normally have filter capabilities in a GET cmdlet\function.
  • Switch - In your case, a switch statement isn't applicable. Typically a switch compares the same variable and executes a code block based on different values. If we wanted to check $Name and if it's John, Sue or Sam then do something. In this case, you have three separate variables.
  • Parameter Names - Leveraging Select-Object with a First param, try to follow the same naming schema (i.e. First vs. ShowFirst) so that it's consisten. Anyone that has used First will know what the purpose of the switch is. If you still want to use ShowFirst, then you should set the variable to First and use an Alias for Show First.

A better approach would be to use a validateset to show the possible sort options:

Function Get-LocalProcess {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false)]
        [ValidateSet('CPU','RAM','Name')]
        [string]$SortBy = 'Name',
        [Parameter(Mandatory=$true)]
        [Alias('ShowFirst')]
        [int]$First = '5'
    )

    Write-Verbose -Message ('Sorting on {0}' -f $SortBy)
    Get-Process | 
    Sort-Object $SortBy |
    Select-Object -First $First
}

Get-LocalProcess -ShowFirst 3 -SortBy RAM -Verbose

You can turn your if statement block into switch statements using your parameter sets.

switch ($PSCmdlet.ParameterSetName) {
    'SortByCPU' { $sortchoice = 'cpu' }
    'SortByRam' { $sortchoice = 'ws' }
    default { $sortchoice = 'name' }
}

Hi Rob,

Thanks for the clarification and advice and do understand your corrections, however, there are specific requirements in this instance to simply use switch parameters without specifying criteria. Also, the variable names were required as I provided - SortByCPU, SortByRAM & ShowFirst.

Cheers
Jamie

Hi AdminOfThings45,

Fantastic thanks. This is exactly what I was after and works a treat. The only issue I have now is that I’m specifying “Sort-Object $SortChoice -Descending” in order to get the most resource intense CPU & RAM but when using the default SortByName, this returns the bottom processes. Is there any way to specify -descending order for specific switches?

Cheers
Jamie

Sorted it (Pardon the pun)…

switch ($PSCmdlet.ParameterSetName) {`
'SortByCPU' { $SortChoice = @{expression = 'cpu';descending = $true} }
'SortByRam' { $SortChoice = @{expression = 'ws';descending = $true} }
default { $SortChoice = @{expression = 'name';descending = $false} }

Thanks for the help with all the other bits.

Cheers
Jamie