0

I am trying to take my powershell elseif statements and convert them to a switch statement to make my code more optimized, but am unable to figure out how to do so.

Any help would be greatly appreciated.

Code:

    If (Get-InstalledApplication -Name "%AutoCAD 2015%") {
    #Install AutoCAD 2015 Object Enabler 
    $exitCode = (Execute-Process -Path 'Civil3D_2015_OE_64Bit.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    }
    ElseIf (Get-InstalledApplication -Name "%MEP 2015%") {
    #Install AutoCAD 2015 Object Enabler 
    $exitCode = (Execute-Process -Path 'AutoCAD_Architecture_MEP_2015_OE_x64.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    }
    ElseIf (Get-InstalledApplication -Name "%Civil 3D 2015%") {
    #Install AutoCAD 2015 Object Enabler
    $exitCode = (Execute-Process -Path 'Civil3D_2015_OE_64Bit.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    }
    ElseIf (Get-InstalledApplication -Name "%Civil 3D 2017%") {
    #Install AutoCAD 2015 Object Enabler 
    $exitCode = (Execute-Process -Path 'Civil3D_2015_OE_64Bit.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    }
    ElseIf (Get-InstalledApplication -Name "%AutoCAD 2017%") {
    #Install AutoCAD 2015 Object Enabler 
    $exitCode = (Execute-Process -Path 'Civil3D_2015_OE_64Bit.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    }
5
  • Show us the code you tried that didn't work. If possible construct a minimal reproducible example. Commented Mar 10, 2017 at 19:24
  • Can you expand on what you mean by "make my code more optimized"? Commented Mar 10, 2017 at 19:27
  • Are you saying it doesn't work? If that's not what you are saying, can you be more specific about your question? Commented Mar 10, 2017 at 19:29
  • I think you will find This page at 4sysops useful. Aside from that, the reality is that switch vs if-else doesn't really "optimize" in powershell; it's just a little easier to read in cases where you have a lot of possibilities to test for. Commented Mar 10, 2017 at 19:33
  • Thanks for your help. My goal was to remove the else ifs and replace it with something more streamline and not have alot of nested if statements. Commented Mar 13, 2017 at 13:19

2 Answers 2

1

In simplest terms, this is the equivalent of your If/ElseIf chain:

Switch($true){
    {Get-InstalledApplication -Name "%AutoCAD 2015%"} {
    #Install AutoCAD 2015 Object Enabler 
    $exitCode = (Execute-Process -Path 'Civil3D_2015_OE_64Bit.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    continue
    }
    {Get-InstalledApplication -Name "%MEP 2015%"} {
    #Install AutoCAD 2015 Object Enabler 
    $exitCode = (Execute-Process -Path 'AutoCAD_Architecture_MEP_2015_OE_x64.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    continue
    }
    {Get-InstalledApplication -Name "%Civil 3D 2015%"} {
    #Install AutoCAD 2015 Object Enabler
    $exitCode = (Execute-Process -Path 'Civil3D_2015_OE_64Bit.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    continue
    }
    {Get-InstalledApplication -Name "%Civil 3D 2017%"} {
    #Install AutoCAD 2015 Object Enabler 
    $exitCode = (Execute-Process -Path 'Civil3D_2015_OE_64Bit.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    continue
    }
    {Get-InstalledApplication -Name "%AutoCAD 2017%"} {
    #Install AutoCAD 2015 Object Enabler 
    $exitCode = (Execute-Process -Path 'Civil3D_2015_OE_64Bit.exe' -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the Civil 3D 2015 OE is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    continue
    }
}

You do realize that you are installing the same application regardless of what you detect on for everything except one case, right? If it were me I think I'd use a hashtable where the keys are the application titles you are searching for, and the values contain the path to the executable and the title to use in the output log. I think it would make this cleaner.

$Apps = @{
    '%AutoCAD 2015%' = [pscustomobject]@{'Path'='Civil3D_2015_OE_64Bit.exe';'Title'='Civil 3D 2015 OE'}
    '%MEP 2015%' = [pscustomobject]@{'Path'='AutoCAD_Architecture_MEP_2015_OE_x64.exe';'Title'='Civil 3D 2015 OE'}
    '%Civil 3D 2015%' = [pscustomobject]@{'Path'='Civil3D_2015_OE_64Bit.exe';'Title'='Civil 3D 2015 OE'}
    '%Civil 3D 2017%' = [pscustomobject]@{'Path'='Civil3D_2015_OE_64Bit.exe';'Title'='Civil 3D 2015 OE'}
    '%AutoCAD 2017%' = [pscustomobject]@{'Path'='Civil3D_2015_OE_64Bit.exe';'Title'='Civil 3D 2015 OE'}
}

Switch($Apps.Keys){
    {Get-InstalledApplication -Name $_} {
    #Install AutoCAD 2015 Object Enabler 
    $exitCode = (Execute-Process -Path $Apps[$_].Path -Parameters '/s /v /qn,', -wait -passthru).ExitCode
    "The exit code for the $($Apps[$_].Title) is: $exitCode" | Out-File -Append -FilePath C:\Logs\PW-CE\install.log
    break
    }
}

The break line makes it so that when one of them does match it exits the Switch.

Sign up to request clarification or add additional context in comments.

2 Comments

The 2nd option with the map which looks way cleaner. Good answer!
I like this answer. It makes it look cleaner and allows me to expand if needed as well.
1

As other comments already pointed out, you can do pretty much the same with if/else as with switch.

Regarding optimisation: if there is a way of getting a list of all installed applications, I would rather fetch that list once and then switch/case over it, instead of invoking your Cmdlet Get-InstalledApplication multiple times.

Another way of optimising your code could be to use a map/dictionary with the search terms and executables and loop over the keys and check if the application corresponding to the key is installed:

$map = @{};
$map["%Civil 3D 2015%"] = 'Civil3D_2015_OE_64Bit.exe';
$map["%MEP 2015%"] = 'AutoCAD_Architecture_MEP_2015_OE_x64.exe';
$map["%AutoCAD 2015%"] = 'Civil3D_2015_OE_64Bit.exe';
foreach($key in $map.Keys) 
{ 
    if(!(Get-InstalledApplication -Name $key)) { continue; }; 

    <# install your application #>; 
    <# Exeute-Process -Path $map[$key] ... #>
}

I edited my answer based on feedback from @TheMadTechnician

3 Comments

You can use scriptblocks for your case tests in a Switch, so it should be able to do anything that If/ElseIf can do.
@TheMadTechnician thank you for your comment, I was not aware of this. I edited the answer and removed the remark regarding preferring if over switch.
Regarding optimisation: I'm pretty sure that Get-WmiObject -Class Win32_InstalledWin32Program|% Name will get you a list of your installed applications. From the look of how he formats his Name parameter, it looks like he's got a function that's just making a WMI query anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.