How to Remove a Single Service Plan from User Accounts with PowerShell

Remove Service Plans with the Microsoft Graph PowerShell SDK

In 2021, I wrote about how to remove a single service plan from multiple Entra ID user accounts with PowerShell. The original script used cmdlets from the Microsoft Online Services (MSOL) module. To cover all bases, I updated the post with versions of the script using cmdlets from the AzureAD and the Microsoft Graph PowerShell SDK. Microsoft has deprecated the MSOL and AzureAD modules and the final retirement of these modules is due on March 30, 2025.

The problem with updating a script to replace cmdlets is the tendency to keep the same flow and logic. In other words, the script that started off using MSOL cmdlets behaves in much the same way when updated to use Graph SDK cmdlets. It’s natural that things happen in this way because those updating the code want to get the work done as quickly as possible. Who has the time to sit back and ask if code can be improved during script updates, even if new tools like GitHub Copilot are available.

I’ve been using GitHub Copilot integrated into Visual Studio Code for the last month or so. I’m not sure that Copilot has created any great new code in my scripts, but it certainly has an uncanny ability to auto-complete lines of code and comments, just like Word does when I write. I like GitHub Copilot and recommend the combination of it and Visual Studio Code to anyone who writes PowerShell for Microsoft 365.

What the Script Does to Remove Service Plans from Accounts

Which brings us neatly to some upgrades for the version of the script based on the Microsoft Graph PowerShell SDK. The original script:

  • Lists the set of subscriptions (bought products) found in the tenant and asks the administrator to select a product to modify.
  • Lists the set of service plans for the selected product and asks the administrator to select the service plan to disable. For example, a tenant might decide that they don’t wish to use Viva Engage, so they will remove the Viva Engage Core and Viva Engage Seeded service plans from all accounts with the selected product. This is exactly what happens when an administrator edits a user account with the Microsoft 365 admin center and removes access to some of the apps listed for the user (Figure 1). Obviously, it’s much faster to use PowerShell to remove service plans from multiple accounts.
  • Runs a cmdlet to disable the selected service plan for all user accounts that have the selected license.

Removing service plans from an Entra ID account.

How to remove service plans with PowerShell
Figure 1: Removing service plans from an Entra ID account

There’s not much in terms of cmdlets in the script. Get-MgSubscribedSku returns the set of products and service plans. Get-MgUser finds user accounts and Set-MgUserLicense disables the selected service plan for each account. It’s all very straightforward.

Upgrading the Script to Remove Service Plans Faster

Then someone complained that they couldn’t get the script to work in their tenant. Perhaps consent had not been granted for the Directory.ReadWrite.All permission (scope), which is necessary to read the set of subscribed products, read user information, and update user licenses. Or perhaps the person used an interactive session, and the signed-in account didn’t hold one of the necessary administrative roles (remember, delegated permissions are used for Graph SDK interactive sessions). For whatever reason, it was good enough to check the code to see if any improvements were possible.

I found four areas to update:

  1. Some products (like Office 365 E3 or Microsoft 365 E5) are composite licenses that span many service plans. Each service plan has a target. User service plans can be disabled or enabled on a per-user basis. Company service plans are managed at the tenant level. The new code makes sure that the script only lists user service plans for the user to select.
  2. The cmdlets in the MSOL and AzureAD modules didn’t boast good server-side filtering capabilities to find accounts assigned specific licenses, so filtering happens client-side. The complex filters supported by the Graph for user accounts allows the Get-MgUser cmdlet to find the precise set of accounts with the selected license. This change makes the script much more efficient in large tenants.
  3. The previous iteration of the script didn’t check if a service plan was already disabled before attempting to disable a plan. It does now.
  4. The previous iteration didn’t handle errors well and the report generated by the script could include items where the removal of a service plan didn’t work. Better error handling sorted this problem.

You can download the updated script from GitHub.

The Principle is Proved, Now Let Your Imagination Run Wild

The script to remove service plans is intended to demonstrate a principle of license management for Microsoft 365 user accounts. It would be easy to amend the script in different ways. For instance, you could allow the administrator to select multiple service plans to remove or eliminate the need to select a product and find a target service plan in any of the licenses assigned to a user. It’s PowerShell, so let your imagination run wild and improve the script to meet the needs of your tenant.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

Leave a Reply

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