PowerShell switch statements are one of the easiest ways to compare an expression to multiple conditions. It’s kind of like nesting multiple if statements, but much prettier to look at and easier to understand. In this comprehensive guide, we go over the details and look at several examples you can use to spruce up your PowerShell scripts.
Throughout this guide, I’m using PowerShell version 7.4.3 (formerly called PowerShell Core). However, all of the examples we go over should also work for Windows PowerShell version 5.1. If something doesn’t run as expected, try running it in the latest version of PowerShell.
What is a switch statement?
A switch statement in PowerShell is a simplified way to compare a value against multiple possible results, similar to multiple nested if statements. If a condition evaluates to true, any associated action executes.
How to use a switch statement in PowerShell
Here’s what the basic syntax of a switch statement looks like.
Now, let’s look at an actual example of a PowerShell switch statement.

Switch vs. if statements
PowerShell switch and if statements are similar in many ways and are often interchangeable with a few formatting differences and parameters. Even performance results aren’t drastically different (though specific situations and more advanced conditions could return greater performance differences).
The most common factor when choosing between a switch and an if statement with PowerShell comes down to readability. In most cases, if you are evaluating more than two or three conditions, switch statements become much easier to read.
This script identifies the current day of the week and returns a menu item depending on the result. You may even recognize this script from my PowerShell if statements article. It’s comprised of several if, elseif, and else statements, which can appear repetitive and convoluted. By comparison, here’s a script that returns the same results but uses a switch statement instead of an if statement.
The switch statement is much more scannable and easier to read. Even though the if statement uses fewer lines, it has to repeat the command and comparison operator throughout the example, making it more difficult to read.
Using the default clause with switch statements
The default clause is a built-in keyword that determines what to do if no match is found. Instead of returning nothing, the default clause is given an action to perform just like any other value. Here’s an example of using the default clause.
Since the expression “teal” doesn’t match any of the other values, it executes the default action.

PowerShell switch parameters
The PowerShell switch statement includes several parameters to help define expressions and input sources. Here are a list of the available switch parameters directly from Microsoft’s help documentation.
Wildcard: Indicates that the condition is a wildcard string. If the match clause is not a string, the parameter is ignored. The comparison is case-insensitive.
Exact: Indicates that the match clause, if it is a string, must match exactly. If the match clause is not a string, this parameter is ignored. The comparison is case-insensitive.
CaseSensitive: Performs a case-sensitive match. If the match clause is not a string, this parameter is ignored.
File: Takes input from a file rather than a <test-expression>. If multiple File parameters are included, only the last one is used. Each line of the file is read and evaluated by the switch statement. The comparison is case-insensitive.
PowerShell power user?
Check out The PowerShell Podcast: a weekly exploration of tips and tricks to help you step up your PowerShell game.
How to use multiple expressions in a switch statement
Switch statements can evaluate multiple expressions in the same statement. This can be in the form of an array, multiple variables, integers, strings, etc.
When submitting multiple expressions, separate them with a comma. Multiple expressions are evaluated in the order they are written.

Here we evaluate the letters “a,” “b,” and “d.” Both “a” and “b” return true, but “d” doesn’t match any of the conditions.
PowerShell switch break vs. continue

If you don’t want an expression to match more than once, you can either use the continue or break statement. A continue statement stops evaluating the current expression once a match is found; however, it proceeds to evaluate the next expression if there is one available.
In this example, we use the continue statement to limit each expression to match only one condition. Once the second condition evaluates and matches 2, the switch statement moves onto the next value in the variable, eliminating duplicate matches. Here is the result.

If you want to stop the entire switch once a specific condition is met, use the break statement. Here’s what happens if I replace the continue statement with a break statement in the same example.

The break statement stops the switch from evaluating anything after the first condition returns true.
Switch statement examples
What’s that? You’re still here and you want more PowerShell switch statement examples? Well, as any good rock star concedes to their adoring fans chanting encore, I guess I could muster up a couple more examples to keep my fans happy.
Using switch statements to identify running processes

Counting files by file type with the PowerShell switch statement
In this example, the PowerShell script returns the number of specific file types found in a given directory.
Here are the results when I run this script in my test environment.

You can easily add more document types to this script to meet your needs. Also, consider adding a default condition for files with no matching file type listed.
Get-Help about_switch info
Hopefully this guide helps you add to your PowerShell repertoire. If you’re interested in more PowerShell basics, definitely check out our guide on PowerShell loops. And if you’re still stuck using the command line, it’s not too late. We have tons of articles that teach you the PowerShell equivalents of your favorite cmd commands, like our PowerShell equivalent of dsquery article.
Lastly, if you need help running scripts against your managed devices, check out PDQ Connect or PDQ Deploy & Inventory. Connect is an agent-based solution that makes local and remote device management easy. Deploy & Inventory specialize in on-prem device management and don’t require an agent installation.

Born in the ’80s and raised by his NES, Brock quickly fell in love with everything tech. With over 15 years of IT experience, Brock now enjoys the life of luxury as a renowned tech blogger and receiver of many Dundie Awards. In his free time, Brock enjoys adventuring with his wife, kids, and dogs, while dreaming of retirement.
Refactoring
Refactoring commands for VS Code.
Refactorings allow you to change or generate code based on the code you have. You will find a list of refactors below. You can invoke a refactor by invoke the Refactor command or by pressing the key binding Ctrl+Alt+R .
Only valid refactors will be returned in the drop down menu.
Convert to $_
This refactoring converts a $PSItem variable to the $_ variable.
Convert to $PSItem
Converts a reference to the $_ variable to $PSItem.
Convert to Multiline Command
Converts a command invocation into a multi-line command. Each parameter and argument is broken up with backticks.
Convert to Splat
Converts a command invocation into a splatting expression and creates a hashtable named $Parameters and then passes that hashtable as a splatting expression to the command. Positional arguments are not added to the hashtable.
Export Module Member
Exports the selected variable or function from a module using Export-ModuleMember.
You can use the Extract Selection to File refactor to create a new file based on the selection in the current active editor.
Generate Function from Usage
You can generate a function based on a command example. This refactoring will analyze the parameters, arguments and whether the command is used in a pipeline. If used in a pipeline, this refactoring will generate an advanced function.
Generate Proxy Function
Proxy functions allow you to extend existing functions with new parameters and functionality. You can select a command that you use within your script and select the Generate Proxy Function refactoring to have it generate the proxy function code for you.
Introduce Using Namespace
The introduce using namespace refactoring adds a using namespace statement to the top of a script and replaces the selected type expression with the namespace removed.
You can reorder parameters by using the Ctrl+PageUp and Ctrl+PageDown key bindings. Ensure that your cursor is on top of a parameter for a command. Press one of the key bindings. To move a parameter to the right, use Page Up. To move a parameter to the left, use Page Down.
The split pipe refactoring will split a pipe into multiple lines. Each element in the pipe is stored in a variable and passed to the next item in the pipe. This can be useful for debugging long or complex pipeline operations.
How can I pass values to my functions in the same way the PowerShell cmdlet Write-Output can be passed multiple values and process them as expected?
'one', 'two' | Write-Outputone
twoI thought this was a way to do that, but it isn’t:
Function ProcessNames ([Parameter(ValueFromPipeline=$true)][string[]]$Names) { Foreach ( $name in $Names ) { # do something }
}
'bob', 'alice' | ProcessNamesIn the above example, only the last element in the list gets processed – in this case ‘alice’.
What am I doing wrong?
asked Aug 23, 2023 at 15:49
Function ProcessNames ([Parameter(ValueFromPipeline=$true)][string[]]$Names) { PROCESS{ Foreach ( $name in $Names ) { $name } }
}
'bob', 'alice' | ProcessNamesanswered Aug 23, 2023 at 16:01

3 gold badges45 silver badges59 bronze badges
To add to TheMadTechnician’s helpful answer:
- Only a
param(...)block allows you to use the[CmdletBinding()]attribute, which modifies the behavior of advanced functions – see this answer.
- Only a
If your intent is to support processing multiple input objects via the pipeline only, you needn’t declare your pipeline-binding parameter as an array.
Supporting multiple input objects via the pipeline only simplifies – and speeds up – things:
function ProcessNames { param( [Parameter(ValueFromPipeline)] [string] $Name # Defined as a *single* string ) process { # Do something with $Name $Name + '!' # sample operation }
}filter ProcessNames { # Do something with $_ $_ + '!' # sample operation
}answered Oct 11, 2023 at 22:42
68 gold badges673 silver badges862 bronze badges
Today’s increased demand for efficiency in IT necessitates knowledge of how to speed up workflow using powerful tools such as PowerShell and Intune.
It is the scripting capability provided by PowerShell that enables the automation of complex tasks, which are performed repeatedly, while Intune, part of Microsoft’s Endpoint Manager, allows devices and applications in an organization to be managed. This makes them achieve improved efficiencies and compliance in Windows application management.
Recap of Part 1: Retrieving Win32 Apps
In our first part titled “PowerShell & Intune automate your work: Part 1 – Retrieve Win32 Apps,” we covered several foundational skills that are essential when interacting with Azure and Microsoft Graph API through PowerShell. We went over some fundamental aspects of the AZ Module, negotiating authorization processes with Azure as well as what Microsoft Graph can do.
Retrieve Win32 App Assignments in Intune using PowerShell
Moving on from our initial exploration, this article delves into retrieving Win32 App Assignments.
Our script kicks off by establishing a connection to Microsoft Graph using specific scopes necessary for accessing detailed app data. These scopes include:
- “User.Read.All”
- “Group.ReadWrite.All”
- “DeviceManagementApps.Read.All”
- “DeviceManagementApps.ReadWrite.All”
- “GroupMember.Read.All”
- “Directory.Read.All”
- “Directory.ReadWrite.All”
- “Group.Read.All”
During the first run and the initial login in your tenant, you will be asked to provide consent to the above scopes:

Alternatively, you can also check the permissions and consent to them when you use the Graph Explorer. Just go to the Modify Permissions tab and everything needed for the operation will be displayed there.

Upon connection, the script fetches all Win32 applications using a targeted Graph API request.
For each application retrieved, it then queries for associated assignments:
Where-Object { ($PSItem.target.'@odata.type' -like "*groupAssignmentTarget") -or ($PSItem.intent -like $Intent) }These are the configurations that dictate how apps are distributed to various groups within the organization.
The script meticulously parses through these assignments to determine details such as the group’s inclusion or exclusion status and the specifics of deployment settings like notifications and restart behavior.
Each piece of assignment data is processed and stored in a custom PowerShell object, providing a structured and actionable overview of app distribution across the organization.
Error handling is built into the script to manage and report any issues encountered during the data retrieval process, ensuring robust and reliable execution.
$PSObject = [PSCustomObject]@{ Type = $Win32AppAssignment.target.'@odata.type' AppName = $Win32MobileApp.displayName GroupID = $Win32AppAssignment.target.groupId GroupName = $AzureADGroupResponse.displayName Intent = $Win32AppAssignment.intent GroupMode = $GroupMode Notifications = $Win32AppAssignment.settings.notifications RestartSettings = $Win32AppAssignment.settings.restartSettings InstallTimeSettings = $Win32AppAssignment.settings.installTimeSettings } $Win32AppAssignmentList.Add($PSObject) | Out-NullHere is the full script for these operations:
Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All", "DeviceManagementApps.Read.All", "DeviceManagementApps.ReadWrite.All", "GroupMember.Read.All", "Directory.Read.All", "Directory.ReadWrite.All", "Group.Read.All"
$Win32AppList = New-Object -TypeName "System.Collections.Generic.List[Object]" $Win32AppAssignmentList = New-Object -TypeName "System.Collections.Generic.List[Object]"
$Win32MobileApps = Invoke-MgGraphRequest -Method GET "https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?`$filter=isof('microsoft.graph.win32LobApp')" if ($Win32MobileApps -ne "") { $Win32MobileApps = $Win32MobileApps.value if ($Win32MobileApps -ne $null) { foreach ($Win32MobileApp in $Win32MobileApps) { #$Win32MobileApp.id | Out-String | Write-Host $Win32MobileApps2 = Invoke-MgGraphRequest -Method GET "https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps/$($Win32MobileApp.id)/assignments" #$Win32MobileApps2.value | Out-String | Write-Host # $Win32AppList.Add($Win32MobileApp) $Win32AppAssignmentMatches = $Win32MobileApps2.value | Where-Object { ($PSItem.target.'@odata.type' -like "*groupAssignmentTarget") -or ($PSItem.intent -like $Intent) } #$Win32AppAssignmentMatches.id | out-string | write-host foreach ($Win32AppAssignment in $Win32AppAssignmentMatches) { try { # Retrieve group name from given group id $Win32AppAssignmentValue = $Win32AppAssignment.target.groupId $AzureADGroupResponse = Invoke-MgGraphRequest -Method GET "https://graph.microsoft.com/v1.0/groups/$Win32AppAssignmentValue" # Determine if assignment is either Include or Exclude for GroupMode property output switch ($Win32AppAssignment.target.'@odata.type') { "#microsoft.graph.groupAssignmentTarget" { $GroupMode = "Include" } "#microsoft.graph.exclusionGroupAssignmentTarget" { $GroupMode = "Exclude" } } # Create a custom object for return value $PSObject = [PSCustomObject]@{ Type = $Win32AppAssignment.target.'@odata.type' AppName = $Win32MobileApp.displayName GroupID = $Win32AppAssignment.target.groupId GroupName = $AzureADGroupResponse.displayName Intent = $Win32AppAssignment.intent GroupMode = $GroupMode Notifications = $Win32AppAssignment.settings.notifications RestartSettings = $Win32AppAssignment.settings.restartSettings InstallTimeSettings = $Win32AppAssignment.settings.installTimeSettings } $Win32AppAssignmentList.Add($PSObject) | Out-Null # $PSObject | out-string | write-host } catch [System.Exception] { Write-Warning -Message "An error occurred while resolving groupId for assignment with ID: $($Win32AppAssignment.id). Error message: $($_.Exception.Message)" } return $Win32AppAssignmentList } } }}Retrieve Win32 App Assignments for a Particular Application
If you only want to find the assignments for a specific application based on the DisplayName, you can easily adapt the script.
All you need to do is check if the DisplayName matches your target application.
if($Win32MobileApp.displayName -like "*vlc*"){
Here’s the full modified code for searching the assignments of a particular app in Intune with PowerShell:
Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All", "DeviceManagementApps.Read.All", "DeviceManagementApps.ReadWrite.All", "GroupMember.Read.All", "Directory.Read.All", "Directory.ReadWrite.All", "Group.Read.All"
$Win32AppList = New-Object -TypeName "System.Collections.Generic.List[Object]" $Win32AppAssignmentList = New-Object -TypeName "System.Collections.Generic.List[Object]"
$Win32MobileApps = Invoke-MgGraphRequest -Method GET "https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?`$filter=isof('microsoft.graph.win32LobApp')" if ($Win32MobileApps -ne "") { $Win32MobileApps = $Win32MobileApps.value if ($Win32MobileApps -ne $null) { foreach ($Win32MobileApp in $Win32MobileApps) { if($Win32MobileApp.displayName -like "*vlc*"){ # $Win32MobileApp.id | Out-String | Write-Host $Win32MobileApps2 = Invoke-MgGraphRequest -Method GET "https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps/$($Win32MobileApp.id)/assignments" $Win32AppAssignmentMatches = $Win32MobileApps2.value | Where-Object { ($PSItem.target.'@odata.type' -like "*groupAssignmentTarget") -or ($PSItem.intent -like $Intent) } foreach ($Win32AppAssignment in $Win32AppAssignmentMatches) { try { $Win32AppAssignmentValue = $Win32AppAssignment.target.groupId $AzureADGroupResponse = Invoke-MgGraphRequest -Method GET "https://graph.microsoft.com/v1.0/groups/$Win32AppAssignmentValue" switch ($Win32AppAssignment.target.'@odata.type') { "#microsoft.graph.groupAssignmentTarget" { $GroupMode = "Include" } "#microsoft.graph.exclusionGroupAssignmentTarget" { $GroupMode = "Exclude" } } # Create a custom object for return value $PSObject = [PSCustomObject]@{ Type = $Win32AppAssignment.target.'@odata.type' AppName = $Win32MobileApp.displayName GroupID = $Win32AppAssignment.target.groupId GroupName = $AzureADGroupResponse.displayName Intent = $Win32AppAssignment.intent GroupMode = $GroupMode Notifications = $Win32AppAssignment.settings.notifications RestartSettings = $Win32AppAssignment.settings.restartSettings InstallTimeSettings = $Win32AppAssignment.settings.installTimeSettings } $Win32AppAssignmentList.Add($PSObject) | Out-Null } catch [System.Exception] { Write-Warning -Message "An error occurred while resolving groupId for assignment with ID: $($Win32AppAssignment.id). Error message: $($_.Exception.Message)" } return $Win32AppAssignmentList } } } }}Conclusion
In addition, it saves time and improves accuracy thus reducing human errors during this process.
We are currently building on our PowerShell & Intune knowledgebase as we consider how IT operations could be improved and how security automation could be achieved.




