3

I have the following If block which in a logon script which I am re-writing:

If ($distinguishedname -match 'Joe Bloggs') {
    Map-Drive 'X' "\\path\to\drive"
}
If ($distinguishedname -match 'Steve Bloggs') {
    Map-Drive 'X' "\\path\to\drive"
}
If ($distinguishedname -match 'Joe Jobs') {
    Map-Drive 'X' "\\path\to\drive"
}

Which obviously needs to be re-written as an If/Else statement (as each user only has 1 name!) However, I prefer the look of the following switch -Regex method:

switch -Regex ($distinguishedname) {
    'Joe Bloggs' {Map-Drive 'X' "\\path\to\drive"; break}
    'Steve Bloggs' {Map-Drive 'X' "\\path\to\drive"; break}
    'Joe Jobs' {Map-Drive 'X' "\\path\to\drive"; break}
}

My question is - would using a switch in this manner have any impact on the performance of this function? It must be better than the above (if/if/if), as not every possibility is evaluated each time, but would the switch be faster than an ifelse/ifelse/else?

Bassie
  • 9,529
  • 8
  • 68
  • 159
  • You may want to use groups instead of testing users one by one but that my not apply to your situation – sodawillow Apr 15 '16 at 14:47
  • @sodawillow Thanks for your comment - I am testing groups elsewhere in the script, but the setup which is being performed here is unique for those users so this seems like the best way in my case – Bassie Apr 15 '16 at 14:50
  • [Related if not a dupe](http://stackoverflow.com/questions/445067/if-vs-switch-speed) – Matt Apr 15 '16 at 14:52

2 Answers2

8

I wrote this test to check if I could figure out which way is better using Measure-Command:

function switchtest {
    param($name)

    switch -Regex ($name) {
        $optionsarray[0] {
            Write-host $name
            break
        }
        $optionsarray[1] {
            Write-host $name
            break
        }
        $optionsarray[2] {
            Write-host $name
            break
        }
        $optionsarray[3] {
            Write-host $name
            break
        }
        $optionsarray[4] {
            Write-host $name
            break
        }
        default { }
    }
}
function iftest {
    param($name)

    If ($name -match $optionsarray[0]) {Write-host $name}
    ElseIf ($name -match $optionsarray[1]) {Write-host $name}
    ElseIf($name -match $optionsarray[2]) {Write-host $name}
    ElseIf($name -match $optionsarray[3]) {Write-host $name}
    ElseIf($name -match $optionsarray[4]) {Write-host $name}
}

$optionsarray = @('Joe Bloggs', 'Blog Joggs', 'Steve Bloggs', 'Joe Jobs', 'Steve Joggs')
for ($i=0; $i -lt 10000; $i++) {
    $iftime = 0
    $switchtime = 0

    $rand = Get-Random -Minimum 0 -Maximum 4
    $name = $optionsarray[$rand]

    $iftime = (Measure-Command {iftest $name}).Ticks
    $switchtime = (Measure-Command {switchtest $name}).Ticks

    Add-Content -Path C:\path\to\outfile\timetest.txt -Value "$switchtime`t$iftime"
}

Results

On average, this is how each function performed in 10,000 tests:

Switch - 11592.8566

IfElse - 15740.3281

The results were not the most consistent (sometimes switch was faster, sometimes ifelse was faster) but as switch is faster overall (on mean average) I will be using this instead of ifelse.

Would appreciate any feedback on this decision and my testing.

Community
  • 1
  • 1
Bassie
  • 9,529
  • 8
  • 68
  • 159
3

Typically, switch statements work by building a jump table in the assembly code and using that to determine the appropriate route instead of using comparators like if/else. That's why switch statements are faster. I believe that with strings, the compiler generates a hash code of the strings and uses that to implement the jump table so that the switch statement is still faster. So the switch statement should be faster than the if/if/if you have written above but it may not be since switch statements typically rely on the options being somewhat evenly spaced (e.g. 1 2 3 or 5 10 15).

With that being said, why don't you use an if/else-if/else-if instead of an if/if/if? That'll definitely be faster since not every option is evaluated each time.

Ryan
  • 1,131
  • 3
  • 13
  • 17
  • 1
    You sure this would apply equally to a dynamic/interpreted language like PowerShell? How would you even implement a hash-based jump table for a switch that supports regex pattern matching? – Mathias R. Jessen Apr 15 '16 at 14:44
  • @Ryan Thanks for your answer. I decided to opt for the `switch` based on some testing (See my own answer). Do you think those tests are a valid way of determining which statement is faster? – Bassie Apr 15 '16 at 15:33