Update: Because of the deprecation of the Azure AD and Microsoft Online Services PowerShell modules, Practical365 recommends that you use the Microsoft Graph PowerShell SDK to manage licenses for Microsoft 365 accounts. See this article for details about how to create a licensing report with SDK cmdlets.
In Office 365 we have three methods of managing license assignments for individual or multiple user accounts.
- Using the Office 365 admin portal
- Using Azure AD group-based license management
- Using PowerShell
The Office 365 admin portal provides a simple web interface for managing license assignments. It’s easy to add a license for a user, or for multiple users, enable or disable sub-SKU features (the individual services that are included in a license), or remove a license. Licenses for multiple users can be managed at the same time. This method is useful for ad-hoc license management, or for bulk assigning licenses when you first provision an Office 365 tenant. The web interface is friendly for even a non-technical user, so license management tasks can be delegated to people outside of IT support if necessary.
Azure Active Directory group-based licensing, which I wrote about here, simplifies license management by mapping license assignments to groups. License management for end users is then a simple task of adding or removing users in groups, and doesn’t require the ongoing use of Office 365 management tools.
In this article I’m going to demonstrate how to manage Office 365 licenses using PowerShell. This is more complex than either of the previous methods, but is useful for automating license assignments as part of a user provisioning process. PowerShell is also a good method for querying license usage and generating your own custom reports for license consumption, which can help you to manage your costs over time.
We’ll look at:
- The Azure AD V2 PowerShell Module
- Listing Available Licenses
- Querying License Assignments for User Accounts
- Assigning a Single License Using PowerShell
- Assigning Multiple Licenses Using PowerShell
- Assigning Licenses with Sub-SKU Features Disabled
- Removing Licenses Using PowerShell
The Azure AD V2 PowerShell Module
License management in Office 365 is performed using the Azure Active Directory PowerShell module. The first version of this PowerShell module is also known as the MS Online module, and uses cmdlets with “Msol” in the name, for example Connect-MsolService and Get-MsolUser.
While the MS Online module is still available today, it will be deprecated in the near future. A new Azure Active Directory PowerShell V2 module has been developed to replace it. This module is also known as the Azure AD module. The Azure AD module uses the Office 365 Graph API to interact with Office 365. Microsoft aims to migrate the functionality of the MS Online module to the Azure AD module, and recommends that you use Azure AD for any script development. In this blog post I will demonstrate license management using the Azure AD module.
The Azure AD module is installed using PowerShellGet, which is included with Windows Management Framework (WPF) 5.0 (PowerShell 5.0). Windows 10 and Windows Server 2012 R2 or later ship with PowerShell 5.0 installed by default, which means that PowerShellGet is already available. For earlier operating systems, you’ll either need to upgrade to WMF 5.0, or install PowerShellGet for PowerShell 3.0 or 4.0. Some applications such as Exchange Server are sensitive to changes in the version of WMF that is installed on the system, so you should not upgrade WMF until you’ve verified that all your installed software will continue to work
PS C:\> Install-Module AzureAD
After the Azure AD module is installed you can connect to your Office 365 tenant by running the Connect-AzureAD cmdlet, and then entering your admin credentials when prompted. The Azure AD module supports the use of multi-factor authentication (MFA).
PS C:\> Connect-AzureAD
To explore the available cmdlets in the Azure AD module, run the following command.
PS C:\> Get-Command -Module AzureAD
As a side note, Connect-AzureAD will work with stored credentials function as long as your account does not require MFA or you’re connecting from a network that allows MFA to be bypassed.
PS C:\> Connect-AzureAD -Credential (Get-StoredCredential -UserName admin@exchangeserverpro.onmicrosoft.com)
Listing Available Licenses
The Get-AzureADSubscribedSku cmdlet is used to query the licenses that your organization has subscribed to in Office 365.
PS C:\> Get-AzureADSubscribedSku | Select Sku*,*Units SkuId SkuPartNumber ConsumedUnits PrepaidUnits ----- ------------- ------------- ------------ 6fd2c87f-b296-42f0-b197-1e91e994b900 ENTERPRISEPACK 14 class LicenseUnitsDetail {... efccb6f7-5641-4e0e-bd10-b4976e1bf68e EMS 2 class LicenseUnitsDetail {...
A more detailed view of the licenses that are enabled and consumed is available by expanding the PrepaidUnits property.
PS C:\> Get-AzureADSubscribedSku | Select -Property Sku*,ConsumedUnits -ExpandProperty PrepaidUnits SkuId : 6fd2c87f-b296-42f0-b197-1e91e994b900 SkuPartNumber : ENTERPRISEPACK ConsumedUnits : 17 Enabled : 25 Suspended : 0 Warning : 0 SkuId : efccb6f7-5641-4e0e-bd10-b4976e1bf68e SkuPartNumber : EMS ConsumedUnits : 2 Enabled : 5 Suspended : 0 Warning : 0
In the output above we can see that my tenant has 25 “ENTERPRISEPACK” licenses, and 5 “EMS” licenses. The SkuPartNumber for each does not precisely match the name of the license that you’ll see in Office 365 documentation or in the license management sections of the Office 365 admin portal. For example, ENTERPRISEPACK is the SkuPartNumber for the Enterprise E3 license, while EMS is the SkuPartNumber for the Enterprise Mobility and Security E3 license. A complete list of part numbers and friendly names isn’t available on Microsoft online documentation sites, although with a little searching and common sense you can usually work out what they mean. If there’s any confusion, opening a support ticket with Microsoft will get you the answers you need.
The individual license features and services, also referred to as sub-SKU features, can also be inspected. As with the SkuPartNumber values, the ServicePlanName values are not a match for the friendly names that you see in the Office 365 or Azure admin portals, but names like SWAY, POWERAPPS_O365_P2, and EXCHANGE_S_ENTERPRISE are obvious. Others are not so obvious, such as MCOSTANDARD (Skype for Business Online), but again some searching online will usually clear up any confusion.
PS C:\> $licenses = Get-AzureADSubscribedSku PS C:\> $licenses[0].SkuPartNumber ENTERPRISEPACK PS C:\> $licenses[0].ServicePlans AppliesTo ProvisioningStatus ServicePlanId ServicePlanName --------- ------------------ ------------- --------------- User Success 8c7d2df8-86f0-4902-b2ed-a0458298f3b3 Deskless User Success 76846ad7-7776-4c40-a281-a386362dd1b9 FLOW_O365_P2 User Success c68f8d98-5534-41c8-bf36-22fa496fa792 POWERAPPS_O365_P2 User Success 57ff2da0-773e-42df-b2af-ffb7a2317929 TEAMS1 User Success b737dad2-2f6c-4c65-90e3-ca563267e8b9 PROJECTWORKMANAGEMENT User Success a23b959c-7ce8-4e57-9140-b90eb88a9e97 SWAY Company Success 882e1d05-acd1-4ccb-8708-6ee03664b117 INTUNE_O365 User Success 7547a3fe-08ee-4ccb-b430-5077c5041653 YAMMER_ENTERPRISE User Success bea4c11e-220a-4e6d-8eb8-8ea15d019f90 RMS_S_ENTERPRISE User Success 43de0ff5-c92c-492b-9116-175376d08c38 OFFICESUBSCRIPTION User Success 0feaeb32-d00e-4d66-bd5a-43b5b83db82c MCOSTANDARD User Success e95bec33-7c88-4a70-8e19-b10bd9d0c014 SHAREPOINTWAC User Success 5dbe027f-2339-4123-9542-606e4d348a72 SHAREPOINTENTERPRISE User Success efb87545-963c-4e0d-99df-69c6916d9eb0 EXCHANGE_S_ENTERPRISE PS C:\> $licenses[1].SkuPartNumber EMS PS C:\> $licenses[1].ServicePlans AppliesTo ProvisioningStatus ServicePlanId ServicePlanName --------- ------------------ ------------- --------------- User Success 6c57d4b6-3b23-47a5-9bc9-69f17b4947b3 RMS_S_PREMIUM User Success c1ec4a95-1f05-45b3-a911-aa3fa01094f5 INTUNE_A User Success bea4c11e-220a-4e6d-8eb8-8ea15d019f90 RMS_S_ENTERPRISE User Success 41781fb2-bc02-4b7c-bd55-b576c07bb09d AAD_PREMIUM User Success 8a256a2b-b617-496d-b51b-e76466e88db0 MFA_PREMIUM
Querying License Assignments for User Accounts
There are two user properties that reveal the license assignments for a user. The first is the AssignedLicenses property, which can be retrieved using Get-AzureADUser.
PS C:\> Get-AzureADUser -SearchString jane.tulley@exchangeserverpro.net | Select -ExpandProperty AssignedLicenses DisabledPlans SkuId ------------- ----- {7547a3fe-08ee-4ccb-b430-5077c5041653} 6fd2c87f-b296-42f0-b197-1e91e994b900
In the output above we can see the SkuId of the license that is assigned to the user. The matching license can be found by running Get-AzureADSubscribedSku, which in the ouput below we can see is the ENTERPRISEPACK license (Enterprise E3).
PS C:\> Get-AzureADSubscribedSku | Where {$_.SkuId -eq "6fd2c87f-b296-42f0-b197-1e91e994b900"} ObjectId SkuPartNumber -------- ------------- 2b9bca49-687e-4e5f-8a52-21350b719b06_6fd2c87f-b296-42f0-b197-1e91e994b900 ENTERPRISEPACK
The Get-AzureADUser output shown above also reveals the DisabledPlans property. This property contains the ServicePlanId values of the sub-SKU features that have been disabled for the user. There are two ways to match those ServicePlanId values to the actual names of the sub-SKU features. The first is to use the output of Get-AzureADSubscribedSku to view the ServicePlanId values for the individual services, as demonstrated earlier. For the example of Jane Tulley, the ID of the disabled plan is “7547a3fe-08ee-4ccb-b430-5077c5041653”, which is YAMMER_ENTERPRISE in the list of service plans for the ENTERPRISEPACK license.
The other approach is to look at the AssignedPlans property of the user.
PS C:\> Get-AzureADUser -SearchString jane.tulley@exchangeserverpro.net | Select -ExpandProperty AssignedPlans AssignedTimestamp CapabilityStatus Service ServicePlanId ----------------- ---------------- ------- ------------- 1/05/2017 11:01:50 AM Enabled PowerAppsService c68f8d98-5534-41c8-bf36-22fa496fa792 1/05/2017 11:01:50 AM Enabled ProcessSimple 76846ad7-7776-4c40-a281-a386362dd1b9 1/05/2017 11:01:50 AM Enabled RMSOnline bea4c11e-220a-4e6d-8eb8-8ea15d019f90 1/05/2017 11:01:50 AM Enabled Deskless 8c7d2df8-86f0-4902-b2ed-a0458298f3b3 1/05/2017 11:01:50 AM Enabled Sway a23b959c-7ce8-4e57-9140-b90eb88a9e97 27/02/2017 5:43:09 AM Enabled TeamspaceAPI 57ff2da0-773e-42df-b2af-ffb7a2317929 27/02/2017 5:40:56 AM Suspended YammerEnterprise 7547a3fe-08ee-4ccb-b430-5077c5041653 19/01/2017 6:24:33 AM Enabled exchange efb87545-963c-4e0d-99df-69c6916d9eb0 19/01/2017 6:24:33 AM Enabled SharePoint 5dbe027f-2339-4123-9542-606e4d348a72 19/01/2017 6:24:33 AM Enabled SharePoint e95bec33-7c88-4a70-8e19-b10bd9d0c014 19/01/2017 6:24:33 AM Enabled MicrosoftCommunicationsOnline 0feaeb32-d00e-4d66-bd5a-43b5b83db82c 19/01/2017 6:24:33 AM Enabled MicrosoftOffice 43de0ff5-c92c-492b-9116-175376d08c38 19/01/2017 6:24:33 AM Enabled ProjectWorkManagement b737dad2-2f6c-4c65-90e3-ca563267e8b9
In the output above we can see that the “YammerEnterprise” service is suspended, and has a ServicePlanId matching the ID in the list of DisabledPlans we saw earlier.
You will also notice that the service names returned in the Get-AzureADUser output do always not match the service plan names returned in the Get-AzureADSubscribedSku output. For example, Get-AzureADUser shows a service name of “TeamspaceAPI” whereas Get-AzureADSubscribedSku shows the same service as “TEAMS1”. These differences are mildly irritating but do reinforce the idea that you should match two difference pieces of data by the ServicePlanId, not by the friendly name, whenever you are running PowerShell cmdlets or writing scripts to manage your licenses.
For administrators who are familiar with using the MS Online PowerShell module to manage licenses, there is one minor difference to be aware of. The Get-AzureADUser and Get-MsolUser cmdlets return slightly different information for the same user object. Get-AzureADUser will only return sub-SKU features that are Enabled, Deleted or Suspended, whereas Get-MsolUser will return the status of all sub-SKU features. Here’s an example, using an account where I’ve disabled several sub-SKU features to demonstrate the differences in cmdlet output.
PS C:\> Get-AzureADUser -SearchString aisha.bhari@exchangeserverpro.net | Select -ExpandProperty AssignedPlans AssignedTimestamp CapabilityStatus Service ServicePlanId ----------------- ---------------- ------- ------------- 1/05/2017 11:12:19 AM Enabled SharePoint 5dbe027f-2339-4123-9542-606e4d348a72 1/05/2017 11:12:19 AM Enabled SharePoint e95bec33-7c88-4a70-8e19-b10bd9d0c014 1/05/2017 11:12:19 AM Enabled MicrosoftOffice 43de0ff5-c92c-492b-9116-175376d08c38 1/05/2017 11:12:19 AM Enabled ProjectWorkManagement b737dad2-2f6c-4c65-90e3-ca563267e8b9 1/05/2017 11:12:19 AM Enabled TeamspaceAPI 57ff2da0-773e-42df-b2af-ffb7a2317929 1/05/2017 11:12:19 AM Enabled PowerAppsService c68f8d98-5534-41c8-bf36-22fa496fa792 1/05/2017 11:12:19 AM Enabled ProcessSimple 76846ad7-7776-4c40-a281-a386362dd1b9 PS C:\> (Get-MsolUser -UserPrincipalName aisha.bhari@exchangeserverpro.net).Licenses[0].ServiceStatus ServicePlan ProvisioningStatus ----------- ------------------ Deskless Disabled FLOW_O365_P2 Success POWERAPPS_O365_P2 Success TEAMS1 Success PROJECTWORKMANAGEMENT Success SWAY Disabled INTUNE_O365 Success YAMMER_ENTERPRISE Disabled RMS_S_ENTERPRISE Disabled OFFICESUBSCRIPTION Success MCOSTANDARD Disabled SHAREPOINTWAC Success SHAREPOINTENTERPRISE Success EXCHANGE_S_ENTERPRISE Disabled
Assigning a Single License Using PowerShell
The Set-AzureADUserLicense cmdlet assigns and removes Office 365 licenses to user accounts. A simple example is assigning a license to a new user account. Before assigning the license, the usage location of the account also needs to be configure. The license assignment process involves a series of steps to:
- Create an assigned license (singular) object
- Add the assigned license object to another object representing the assigned licenses (plural)
- Run Set-AzureADUserLicense and provide the value for the assigned licenses (plural)
To perform those steps we need to know the ObjectId of the user account, and the SkuId of the license.
PS C:\> Get-AzureADSubscribedSku | Select Sku* SkuId SkuPartNumber ----- ------------- 6fd2c87f-b296-42f0-b197-1e91e994b900 ENTERPRISEPACK efccb6f7-5641-4e0e-bd10-b4976e1bf68e EMS PS C:\> $User = Get-AzureADUser -SearchString sharon.butler@exchangeserverpro.net PS C:\> $user ObjectId DisplayName UserPrincipalName UserType -------- ----------- ----------------- -------- 9930a287-640e-4670-a2ae-2ba3eb5fca33 Sharon Butler Sharon.Butler@exchangeserverpro.net Member
Now we can go ahead and create the license assignment.
PS C:\> Set-AzureADUser -ObjectId $User.ObjectId -UsageLocation AU PS C:\> $License = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense PS C:\> $License.SkuId = "6fd2c87f-b296-42f0-b197-1e91e994b900" PS C:\> $LicensesToAssign = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses PS C:\> $LicensesToAssign.AddLicenses = $License PS C:\> Set-AzureADUserLicense -ObjectId $User.ObjectId -AssignedLicenses $LicensesToAssign
The user now has a single license SKU assigned, and the plans for that license are enabled.
PS C:\> Get-AzureADUser -ObjectId $User.ObjectId | Select -ExpandProperty AssignedLicenses DisabledPlans SkuId ------------- ----- {} 6fd2c87f-b296-42f0-b197-1e91e994b900 PS C:\> Get-AzureADUser -ObjectId $User.ObjectId | Select -ExpandProperty AssignedPlans AssignedTimestamp CapabilityStatus Service ServicePlanId ----------------- ---------------- ------- ------------- 2/05/2017 2:41:26 AM Enabled TeamspaceAPI 57ff2da0-773e-42df-b2af-ffb7a2317929 2/05/2017 2:41:26 AM Enabled MicrosoftCommunicationsOnline 0feaeb32-d00e-4d66-bd5a-43b5b83db82c 2/05/2017 2:41:26 AM Enabled PowerAppsService c68f8d98-5534-41c8-bf36-22fa496fa792 2/05/2017 2:41:26 AM Enabled ProcessSimple 76846ad7-7776-4c40-a281-a386362dd1b9 2/05/2017 2:41:26 AM Enabled SharePoint e95bec33-7c88-4a70-8e19-b10bd9d0c014 2/05/2017 2:41:26 AM Enabled ProjectWorkManagement b737dad2-2f6c-4c65-90e3-ca563267e8b9 2/05/2017 2:41:26 AM Enabled RMSOnline bea4c11e-220a-4e6d-8eb8-8ea15d019f90 2/05/2017 2:41:26 AM Enabled SharePoint 5dbe027f-2339-4123-9542-606e4d348a72 2/05/2017 2:41:26 AM Enabled YammerEnterprise 7547a3fe-08ee-4ccb-b430-5077c5041653 2/05/2017 2:41:26 AM Enabled Deskless 8c7d2df8-86f0-4902-b2ed-a0458298f3b3 2/05/2017 2:41:26 AM Enabled MicrosoftOffice 43de0ff5-c92c-492b-9116-175376d08c38 2/05/2017 2:41:26 AM Enabled Sway a23b959c-7ce8-4e57-9140-b90eb88a9e97 2/05/2017 2:41:26 AM Enabled exchange efb87545-963c-4e0d-99df-69c6916d9eb0
Assigning Multiple Licenses Using PowerShell
Using the same steps as above you can assign an additional license to a user. For example, if we wanted to add the EMS license to the user who is already licensed for Enterprise E3, we could simply re-run the steps above using the SkuId for the EMS license.
If you would like to assign multiple licenses at the same time you can do so with just a small modification to the process. Remember, we’re creating an assigned license (singular) object, and adding it to an assigned licenses (plural) object. We can add multiple assigned license (singular) objects by repeating those commands. Here’s an example of licensing a user for Enterprise E3 and EMS at the same time.
PS C:\> $User = Get-AzureAdUser -SearchString vik.kirby@exchangeserverpro.net PS C:\> Set-AzureADUser -ObjectId $User.ObjectId -UsageLocation AU PS C:\> $E3License = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense PS C:\> $EMSLicense = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense PS C:\> $E3License.SkuId = "6fd2c87f-b296-42f0-b197-1e91e994b900" PS C:\> $EMSLicense.SkuId = "efccb6f7-5641-4e0e-bd10-b4976e1bf68e" PS C:\> $LicensesToAssign = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses PS C:\> $LicensesToAssign.AddLicenses = $E3License,$EMSLicense PS C:\> Set-AzureADUserLicense -ObjectId $User.ObjectId -AssignedLicenses $LicensesToAssign PS C:\> Get-AzureADUser -ObjectId $User.ObjectId | Select -ExpandProperty AssignedPlans
The user now has multiple license SKUs assigned, and the services for both of those SKUs are enabled.
PS C:\> Get-AzureADUser -ObjectId $User.ObjectId | Select -ExpandProperty AssignedLicenses DisabledPlans SkuId ------------- ----- {} efccb6f7-5641-4e0e-bd10-b4976e1bf68e {} 6fd2c87f-b296-42f0-b197-1e91e994b900 PS C:\> Get-AzureADUser -ObjectId $User.ObjectId | Select -ExpandProperty AssignedPlans AssignedTimestamp CapabilityStatus Service ServicePlanId ----------------- ---------------- ------- ------------- 2/05/2017 2:39:08 AM Enabled TeamspaceAPI 57ff2da0-773e-42df-b2af-ffb7a2317929 2/05/2017 2:39:08 AM Enabled MicrosoftCommunicationsOnline 0feaeb32-d00e-4d66-bd5a-43b5b83db82c 2/05/2017 2:39:08 AM Enabled PowerAppsService c68f8d98-5534-41c8-bf36-22fa496fa792 2/05/2017 2:39:08 AM Enabled AADPremiumService 41781fb2-bc02-4b7c-bd55-b576c07bb09d 2/05/2017 2:39:08 AM Enabled ProcessSimple 76846ad7-7776-4c40-a281-a386362dd1b9 2/05/2017 2:39:08 AM Enabled SharePoint e95bec33-7c88-4a70-8e19-b10bd9d0c014 2/05/2017 2:39:08 AM Enabled ProjectWorkManagement b737dad2-2f6c-4c65-90e3-ca563267e8b9 2/05/2017 2:39:08 AM Enabled RMSOnline bea4c11e-220a-4e6d-8eb8-8ea15d019f90 2/05/2017 2:39:08 AM Enabled RMSOnline 6c57d4b6-3b23-47a5-9bc9-69f17b4947b3 2/05/2017 2:39:08 AM Enabled SharePoint 5dbe027f-2339-4123-9542-606e4d348a72 2/05/2017 2:39:08 AM Enabled YammerEnterprise 7547a3fe-08ee-4ccb-b430-5077c5041653 2/05/2017 2:39:08 AM Enabled Deskless 8c7d2df8-86f0-4902-b2ed-a0458298f3b3 2/05/2017 2:39:08 AM Enabled MultiFactorService 8a256a2b-b617-496d-b51b-e76466e88db0 2/05/2017 2:39:08 AM Enabled MicrosoftOffice 43de0ff5-c92c-492b-9116-175376d08c38 2/05/2017 2:39:08 AM Enabled Sway a23b959c-7ce8-4e57-9140-b90eb88a9e97 2/05/2017 2:39:08 AM Enabled SCO c1ec4a95-1f05-45b3-a911-aa3fa01094f5 2/05/2017 2:39:08 AM Enabled exchange efb87545-963c-4e0d-99df-69c6916d9eb0
In the output above you might notice that Intune, which is included with the EMS license, is not listed as a service. This is another example of how Get-AzureADUser doesn’t show services that are not in an enabled, suspended, or deleted state. Intune requires activation for the user, and is in a “PendingInput” state when the license is initially assigned to the user as you can see in the Get-MsolUser output below.
PS C:\> Get-MsolUser -UserPrincipalName vik.kirby@exchangeserverpro.net | Select -ExpandProperty Licenses | Select -Expa ndProperty ServiceStatus ServicePlan ProvisioningStatus ----------- ------------------ RMS_S_PREMIUM Success INTUNE_A PendingInput RMS_S_ENTERPRISE Success AAD_PREMIUM Success MFA_PREMIUM Success ...
Assigning Licenses with Sub-SKU Features Disabled
Office 365 licenses such as Enterprise E3 and E5 allow access to multiple services and applications. For some organizations it is required to disable some of the features of a license, either because the feature should not be used in that environment, or simply to manage a staged roll out and adoption of Office 365 features.
To assign a license with sub-SKU features disabled we use the same process demonstrated earlier, but this time we need to configure the license object with enable and disabled plans before applying the license to the user. For this example I’ll assign an E3 license but only enabled the Exchange Online mailbox and the Office 365 ProPlus applications.
PS C:\> $User = Get-AzureADUser -SearchString blake.johnson@exchangeserverpro.net PS C:\> Set-AzureADUser -ObjectId $User.ObjectId -UsageLocation AU PS C:\> $SkuFeaturesToEnable = @("EXCHANGE_S_ENTERPRISE","OFFICESUBSCRIPTION") PS C:\> $StandardLicense = Get-AzureADSubscribedSku | Where {$_.SkuId -eq "6fd2c87f-b296-42f0-b197-1e91e994b900"} PS C:\> $SkuFeaturesToDisable = $StandardLicense.ServicePlans | ForEach-Object { $_ | Where {$_.ServicePlanName -notin $SkuFeaturesToEnable }} PS C:\> $License = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense PS C:\> $License.SkuId = $StandardLicense.SkuId PS C:\> $License.DisabledPlans = $SkuFeaturesToDisable.ServicePlanId PS C:\> $LicensesToAssign = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses PS C:\> $LicensesToAssign.AddLicenses = $License PS C:\> Set-AzureADUserLicense -ObjectId $User.ObjectId -AssignedLicenses $LicensesToAssign
The user now has the license SKU assigned, but with multiple disabled plans. Only the two enabled features are showing as enabled services for the user as well.
PS C:\> Get-AzureADUser -ObjectId $User.ObjectId | Select -ExpandProperty AssignedLicenses | fl DisabledPlans : {8c7d2df8-86f0-4902-b2ed-a0458298f3b3, 76846ad7-7776-4c40-a281-a386362dd1b9, c68f8d98-5534-41c8-bf36-22fa496fa792, 57ff2da0-773e-42df-b2af-ffb7a2317929...} SkuId : 6fd2c87f-b296-42f0-b197-1e91e994b900 PS C:\> Get-AzureADUser -ObjectId $User.ObjectId | Select -ExpandProperty AssignedPlans AssignedTimestamp CapabilityStatus Service ServicePlanId ----------------- ---------------- ------- ------------- 2/05/2017 2:58:15 AM Enabled MicrosoftOffice 43de0ff5-c92c-492b-9116-175376d08c38 2/05/2017 2:58:15 AM Enabled exchange efb87545-963c-4e0d-99df-69c6916d9eb0
Removing Licenses Using PowerShell
For the final demonstration in this article let’s look at how to remove an assigned license using PowerShell. The Set-AzureADUserLicense cmdlet is used for this task, and the process is similar to adding a license. The difference is that when creating the assigned licenses (plural) object we use RemoveLicenses instead of AddLicenses, and provide only the SkuId instead of the full license object.
PS C:\> $User = Get-AzureAdUser -SearchString sue.cooper@exchangeserverpro.net PS C:\> $License = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense PS C:\> $License.SkuId = "6fd2c87f-b296-42f0-b197-1e91e994b900" PS C:\> $LicensesToAssign = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses PS C:\> $LicensesToAssign.AddLicenses = @() PS C:\> $LicensesToAssign.RemoveLicenses = $License.SkuId PS C:\> Set-AzureADUserLicense -ObjectId $User.ObjectId -AssignedLicenses $LicensesToAssign
The user has now had each of the previously licensed features marked as deleted due to the license being removed.
PS C:\> Get-AzureADUser -ObjectId $User.ObjectId | Select -ExpandProperty AssignedPlans AssignedTimestamp CapabilityStatus Service ServicePlanId ----------------- ---------------- ------- ------------- 2/05/2017 3:08:16 AM Deleted TeamspaceAPI 57ff2da0-773e-42df-b2af-ffb7a2317929 2/05/2017 3:08:16 AM Deleted MicrosoftCommunicationsOnline 0feaeb32-d00e-4d66-bd5a-43b5b83db82c 2/05/2017 3:08:16 AM Deleted PowerAppsService c68f8d98-5534-41c8-bf36-22fa496fa792 2/05/2017 3:08:16 AM Deleted ProcessSimple 76846ad7-7776-4c40-a281-a386362dd1b9 2/05/2017 3:08:16 AM Deleted SharePoint e95bec33-7c88-4a70-8e19-b10bd9d0c014 2/05/2017 3:08:16 AM Deleted ProjectWorkManagement b737dad2-2f6c-4c65-90e3-ca563267e8b9 2/05/2017 3:08:16 AM Deleted RMSOnline bea4c11e-220a-4e6d-8eb8-8ea15d019f90 2/05/2017 3:08:16 AM Deleted SharePoint 5dbe027f-2339-4123-9542-606e4d348a72 2/05/2017 3:08:16 AM Deleted YammerEnterprise 7547a3fe-08ee-4ccb-b430-5077c5041653 2/05/2017 3:08:16 AM Deleted Deskless 8c7d2df8-86f0-4902-b2ed-a0458298f3b3 2/05/2017 3:08:16 AM Deleted MicrosoftOffice 43de0ff5-c92c-492b-9116-175376d08c38 2/05/2017 3:08:16 AM Deleted Sway a23b959c-7ce8-4e57-9140-b90eb88a9e97 2/05/2017 3:08:16 AM Deleted exchange efb87545-963c-4e0d-99df-69c6916d9eb0
Summary
As you can see, managing Office 365 licenses with the Azure AD V2 PowerShell module is a complex task at first, but once you’ve performed the steps a few times it should become much more comfortable. Azure AD group-based license management is simpler, but won’t fit everyone’s needs. Using PowerShell to manage licenses like this will suit organizations who want to automated license assignments into other processes. The use of the Graph API also means you can ignore the Azure AD module itself and write custom code to interact with the REST API to perform the same tasks. That is out of scope of this blog post, but it’s something you can explore if custom development and integration into third party systems is a requirement for you.
Nice post. For Azure consulting services visit TechTriad
For years I have been running a detailed report of User licensing built from 3 commands:
Get-MsolSubscription
Get-MsolAccountSku
Get-MsolUser -ALL
The report splices out which part of the business owns which subscription and what users are using what licensing.
Now I need to use AzureAD or mgGraph modules and they each hae a command to view the licenses and sku’s
but not to see the individual subscriptions.
Do you know a replacement for the Get-MsolSubscription command??
Thanks
Does https://practical365.com/create-licensing-report-microsoft365-tenant/ help?
Pingback: Microsoft Grants Extension for Azure AD License Management Cmdlets
In the article, you state that the documentation does not provide a human understandable list for the skupartnumbers. I found it, after a looooooong search over here: https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference
This Microsoft “Docs” URL *would* be nice, but in fact, it’s once more just a shame. Microsoft writes:
“These tables are for reference purposes and are accurate only as of the date when this article was last updated. Microsoft does not plan to update them for newly added services periodically.”
Obviously, Microsoft doesn’t value their customers that much to keep “Docs” up to date… or at least provide a service that always offers the latest license information with all this mess: String_IDs, SKUs, GUIDs, etc. etc.
But it’s actually much worse:
Microsoft cheats the many millions of customers by charging licenses multiple times.
Of course I can prove this very easily 🙂
Hi ,
Can you pls brief on the warning key in the Prepaid Units.
Hi Paul,
Great article. How can I get the report for all the o365 licenses assigned to a list of users ?
For eg: My userlist file is C:\UserNamesInput.txt
Hello Paul, thank you very much for th clear exmaples.
Very usefull.
Best regards.
Aleksej
It covers all most everything in Azure AD user Licensing, Very helpful article.
Thanks for Sharing.
Thank you for this article and write-up. Removing a license(s) from users individually or in bulk seems straightforward.
Say we have users leave the org. Accounts and licenses are removed from the user, but the licenses remain in O365 as unassigned and costing money. What I am looking for is the powershell method of deprovisioning unassigned licenses in O365 down to the assigned number. Why pay for licenses we’re not using?
How do we distinguish between a CSP License and an EA License?
I’m trying to construct a report that will show me all my Azure users and what licenses they have assigned.
For Example:
Each User is assigned “Office 365 Enterprise E3” but then inside of “Office 365 Enterprise E3” you have 18 services that can be enable/disabled.
The Ideal would be to create a report on each Product (Office 365 Enterprise E3) then cycle through all the users showing what each user has enabled.
Has anyone got a PowerShell script that could help with this?
VERY HELPFUL
In my ignorance, I opened a ticket to Microsoft support and they are not able to give me such detailed answers…
By chance I happend to get to this mistery of licenses assignements dates I was looking for…
Thanks to you and Internet
Riccardo
I’m trying to remove Yammer from all accounts with a mixture of licenses. I have tried to digest your samples but I’m still unsure how to disable specific Sub Features on an existing license. Is this possible or does the script have to reapply the license with Yammer switched off?
First of all thank you for article.
I would like to get information about users + licensing, I did this code:
Get-AzureADUser | Select DisplayName,mail,Department,CompanyName,UsageLocation,AssignedLicenses -ExpandProperty AssignedLicenses | Where {$_.SkuId -eq “6fd2c87f-b296-42f0-b197-1e91e994b900” -or $_.SkuId -eq “4b585984-651b-448a-9e53-3b10f069cf7f”} | ft -a
Could I show the SkuId name in result?
Like:
DisplayName | Mail | Department | CompanyName | UsageLocation | AssignedLicenses
Hey hello and thanks for your article.
How can I get all the users with specific service like “MicrosoftOffice”? Thanks for your help!
I mean this “Get-AzureADUser -SearchString test@test.com | Select -ExpandProperty AssignedPlans”
Hi Team,
Can anybody know how to check the date when license is assigned, who assign license and to whom with Office 365 Powershell. is it possible ?
Thanks in advance.
thanks for the article. i am looking for a way to Enabled individual ServicePlan for existing users. we use E3 license with only have a few service plans enabled, now we want to enable more plans, such as “Team”. How can we do that without removing the whole license and re-add.
I am also wondering about it. How can we do it in a more friendly way?
Very helpful article
Hi Paul, have you noticed, or is it just me, that the Get-AzureADSubscribedSku now no longer returns the ServicePlans objects with each Sku object but instead returns a string that looks like the following:
class ServicePlanInfo {
AppliesTo: User
ProvisioningStatus: Success
ServicePlanId: efb87545-963c-4e0d-99df-69c6916d9eb0
ServicePlanName: EXCHANGE_S_ENTERPRISE
}
Just wanting to do a sanity check before I start building some code to parse those strings for the ServicePlanId and ServicePlanName. Looks like this is YAML output, essentially, except for the class declaration.
You can ignore the above – the AzureAD commands were being used in my case imported from another PSSession. The serialization must be causing the effect.
Hello Thank you very much for your article. I was wondering. If i have many users, and want to add a licence for all this users? How can i do it? Do i need a csv file or muss write my code in a for each loop? Please can you help me or give me more informations?
Thank you
The Real Person!
The Real Person!
Yes, some PowerShell code to loop through a list of users would do the trick.
Or switch to using group-based license management.
“AdHoc License Administrator” role has been deprecated and “User administrator” role is required at the minimum for managing the licenses.
“User administrator” role gives more access than what I would like to give to the account running the provisioning scripts. Have you found a method to delegate only “License management” permissions to the account running the provisioning scripts.
Thanks Paul, nice post as usual.
On a similar note, I put together a script (still using the MSOL module) to bulk add/remove licenses.
Details: http://ezoltan.blogspot.com/2017/12/assign-or-remove-o365-licenses.html
Download: https://gallery.technet.microsoft.com/Assign-or-Remove-O365-e397e1da
Regards,
Zoltan
Using the get-azureaduser and get-azureaduserlicensedetail I can easily see what license are assigned. Is there a way to determine if the license is directly applied, or applied using Azure AD group based licenses? I found a way using the MSOL module, but not the AzureAD module.
I have a similar question about cmdlets and methods for viewing licenses assigned using security groups. I have the methods that exist today in the MSOnline module will have counterparts in AzureAd module. This is hoping that that v2 supports more features — not less.
I want to remove multiple licenses using PowerShell. Actually I able to remove single licence like below. But How do I remove multiple licenses?
$AzureUser = Get-AzureAdUser -ObjectId $ADuser.UserPrincipalName
$License = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
$License.SkuId = “6fd2c87f-b296-42f0-b197-1e91e994b900” #6fd2c87f-b296-42f0-b197-1e91e994b900 Office 365 E3
$LicensesToAssign = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
$LicensesToAssign.AddLicenses = @()
$LicensesToAssign.RemoveLicenses = $License.SkuId
Set-AzureADUserLicense -ObjectId $AzureUser.ObjectId -AssignedLicenses $LicensesToAssign
Had this question too, and I figured it out. The logic for this seems pretty silly, and the logic is beyond me, but you need to:
– Create an object for each license SkuId
– Add the correct license to the objects made in previous step
– Create the object with the licenses (plural)
– Add the previously created variables to another object (I think)
– Create the array
– Create the variable/property to remove the licenses
– Create the user variable
– Then remove the licenses
So the code would look like this:
#Hard code the username or prompt for username
$ADName = myuserprincipalname / $ADName = Read-host
$E3License = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
$EMSLicense = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
$E3License.SkuId = “6fd2c87f-b296-42f0-b197-1e91e994b900”
$EMSLicense.SkuId = “efccb6f7-5641-4e0e-bd10-b4976e1bf68e”
$LicensesToAssign = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
$LicensesToAssign.AddLicenses = $E3License, $EMSLicense
$LicensesToAssign.AddLicenses = @()
$LicensesToAssign.RemoveLicenses = $E3License.SkuId, $EMSLicense.SkuId
$user = Get-AzureADUser -SearchString “$adname”
Set-AzureADUserLicense -ObjectId $user.ObjectId -AssignedLicenses $LicensesToAssign
What if you want to enable previously disabled plans?
Would this cause disruption? Will it pick up the add or error as the license is already assigned?
The Real Person!
The Real Person!
I don’t understand your question. What is the scenario you’re looking at?
I’m in the same boat Paul.
Two Scenarios I’d like to try and work through:
1) All users were globally disabled Teams (when that was a thing, which it isn’t now), and we want to add that SubSKU (Teams) back in for all enabled / licensed Users.
2) When we piloted Teams, a group of 20 users were given the Teams SubSKU to allow them to evaluate Teams. If 1), above, works, what will happen to those 20 users. Would the script need to iterate through and skip them if they were already enabled for Teams, or would it just enable it again and continue.
TIA
Hi Paul
I also have the same question as everyone else. Can we re-apply a license with additional features enabled or disabled. It seems like that is not the case.
Is the only way to add and remove features to remove the full license then re apply with desired features?
Thank you
This probably won’t help you, but maybe it will help someone else who reads your blog. Your bit on removing licenses was helpful; however, we have a ton of SKUs. There’s no way my Junior Admins or I will remember the SkuIDs for these…so I needed a way to easily remove licenses from a user account without having that information. I wrote this module:
function global:Remove-CompanyUserLicense ($delicenseUID)
{
Try
{
$delicenseEmail = $delicenseUID + ‘@company.com’
$Current = Get-AzureADUser -ObjectId $delicenseEmail | Select -ExpandProperty AssignedLicenses
$License = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
$License.SkuId = $Current.SkuId
$LicensesToAssign = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
$LicensesToAssign.AddLicenses = @()
$LicensesToAssign.RemoveLicenses = $License.SkuId
Set-AzureADUserLicense -ObjectId $delicenseEmail -AssignedLicenses $LicensesToAssign
Write-Host -ForegroundColor Cyan “License has been removed on $delicenseEmail.”
}
Catch
{
Write-Output “Error clearing license.”
}
}
I’m sure there is a more efficient way to do this, as my Powershell is a bit green. At any rate, I thought it might help save someone some time. Great blog, by the way!
Hi Paul
Great article…
Trying to make reporting on a user readable for humans without memorising each SkuId. Has anyone managed a script that gives
The License SkuPartNumber assigned
The assigned License ServicePlanName
Preferably parsable as an object for reporting…
This is my output and its terrible…
Status :
ObjectID : 0e2afe5b-22d9-442f-9ee6-b66c79b5071f
UserPrincipalName : tilda.backslash@domain.com
UsageLocation : NZ
AssignedLicenses : {class AssignedLicense {
DisabledPlans: System.Collections.Generic.List`1[System.String]
SkuId: efccb6f7-5641-4e0e-bd10-b4976e1bf68e
}
, class AssignedLicense {
DisabledPlans: System.Collections.Generic.List`1[System.String]
SkuId: 6fd2c87f-b296-42f0-b197-1e91e994b900
}
}
AssignedPlans : {@{Service=ProjectWorkManagement}, @{Service=MicrosoftOffice}, @{Service=YammerEnterprise}, @{Service=Sway}…}
very nice article
thanks