There is perpetually a lot of angst around licensing users for Office 365 workloads. Most of my customers over the years have wanted to ease into deployment, only enabling certain services at a time. Of course, as an evergreen service, we are always adding features, leading to new service plans to disable as you discover them.
Oh, what is a service plan? Glad you asked.
Anatomy of an Office 365 License
Licenses are broken into two parts–SKUs and their constituent components, Service Plans. A service plan can be viewed as an individual service or option (think Exchange Online, SharePoint Online, Skype for Business, Exchange Online Archiving, Yammer, Mobile Device Management, etc). A SKU is made up of one or more service plans.
When it comes to discovering and configuring licenses and options, you have a few cmdlets at your disposal:
- Get-MsolAccountSku – List all of the licenses available in your tenant
- New-MsolLicenseOptions – Create a set of service plan assignments
- Set-MsolUserLicense – Assign a license to a user principal object
Diving into them:
- Get-MsolAccountSku [-TenantId <Guid>] [<CommonParameters>]
- New-MsolLicenseOptions -AccountSkuId <string> [-DisabledPlans <string[]>] [<CommonParameters>]
- Set-MsolUserLicense -UserPrincipalName <string> [-AddLicenses <string[]>] [-LicenseOptions <LicenseOption[]>] [-RemoveLicenses <string[]>] [-TenantId <Guid>] [<CommonParameters>]
After connecting to Office 365, let’s go ahead and see what my tenant has:
PS C:\> Get-MsolAccountSku AccountSkuId ActiveUnits WarningUnits ConsumedUnits ------------ ----------- ------------ ------------- contoso:ENTERPRISEPACK_GOV 500 0 4
So, it looks like we have an Enterprise 3 (E3) government plan. But what’s available inside? We unfortunately don’t give you a great simple way to see the inside of a SKU. If you thought you could run a Get-MsolAccountSku | FL, you’d be wrong.
PS C:\> Get-MsolAccountSku | fl ExtensionData : System.Runtime.Serialization.ExtensionDataObject AccountName : contoso AccountSkuId : contoso:ENTERPRISEPACK_GOV ActiveUnits : 500 ConsumedUnits : 4 LockedOutUnits : 0 ServiceStatus : {Microsoft.Online.Administration.ServiceStatus, Microsoft.Online.Administration.ServiceStatus, Microsoft.Online.Administration.ServiceStatus, Microsoft.Online.Administration.ServiceStatus...} SkuPartNumber : ENTERPRISEPACK_GOV SuspendedUnits : 0 TargetClass : User WarningUnits : 0
The licenses are stored in a hash, so you need to enumerate the hash. The information that we’re looking for is stored inside the ServiceStatus property, so let’s dig a little deeper:
PS C:\> (Get-MsolAccountSku | ? { $_.AccountSkuId -like "*ENTERPRISEPACK*" }).SeviceStatus ServicePlan ProvisioningStatus ----------- ------------------ INTUNE_O365 Success RMS_S_ENTERPRISE_GOV Success OFFICESUBSCRIPTION_GOV Success MCOSTANDARD_GOV Success SHAREPOINTWAC_GOV Success SHAREPOINTENTERPRISE_GOV Success EXCHANGE_S_ENTERPRISE_GOV Success
These are the objects that make up the ENTERPRISEPACK_GOV SKU. Now that I’ve satisfied my curiousity about what is in the SKU, how do I assign it?
So, for example, let’s say you have a tenant named contoso.onmicrosoft.com, and you have purchased Enterprise Plan 3 (E3) licenses. Your command would look like something this:
Set-MsolUserLicense -UserPrincipalName user@contoso.com -AddLicenses contoso:ENTERPRISEPACK
That’s great. Simple and easy–as long as you’re satisfied with every user getting every service plan or option enabled. A lot of my customers, however, want to phase it in. And that’s where it gets tricky.
Set-MsolUserLicense has a -LicenseOptions parameter that you can use to specify why service plans you want to disable. By licensing options, we really mean “what service plans do we want to enable or disable?” When we build a licensing option setting, we’re adding objects to a “DisabledOptions” property. Negative assignment isn’t my favorite, but someone who is smarter than me came up with idea, so we’ll go with it.
For example, let’s say you want to disable SharePoint and SharePointWeb Apps for the ENTERPRISEPACK SKU. It would look like this:
PS C:\> $E3Options = New-MsolLicenseOptions -AccountSkuId contoso:ENTERPRISEPACK -DisabledPlans @('SHAREPOINTENTERPRISE_GOV','SHAREPOINTWAC_GOV')
Then, when you assign it to a user, you use this syntax:
PS C:\> Set-MsolUserLicense -UserPrincipalName user@contoso.com -AddLicenses 'contoso:ENTERPRISEPACK' -LicenseOptions $E3Options
A challenge that this negative assignment paradigm presents is, “What if I only want to assign Exchange Online out of SKU, regardless of what other options exist?” Part of the evergreen service model is we always are adding new things, and sometimes this things come in the form of new service plans to existing SKUs.
Since the license option object is built by adding items you DON’T want (instead of including things you do), one way to achieve this outcome is to dynamically create a filter to build the license option for you. Here’s the code that I’ve come up with to do it:
# E3 Exchange and Skype only [array]$DisabledPlans = @() $Sku = (Get-MsolAccountSku | ? { $_.AccountSkuId -like “*ENTERPRISEPACK*”}).AccountSkuId [array]$SkuServicePlans = (Get-MsolAccountSku | ? { $_.AccountSkuId -eq $sku }).ServiceStatus [array]$EnabledPlans = @('EXCHANGE_S_ENTERPRISE_GOV','MCOSTANDARD_GOV') [regex]$EnabledPlansRegex = ‘(?i)^(‘ + (($EnabledPlans |foreach {[regex]::escape($_)}) –join “|”) + ‘)$’ Foreach ($Plan in $SkuServicePlans) { $item = $Plan.ServicePlan.ServiceName If ($item -notmatch $EnabledPlansRegEx) { Write-Host “Adding $($Plan.ServicePlan.ServiceName) to DisabledPlans” $DisabledPlans += $Plan.ServicePlan.ServiceName } } $E3Options = New-MsolLicenseOptions -AccountSkuId $Sku -DisabledPlans $DisabledPlans
What this does is create a dynamic RegEx filter to add service plans not matching service plan names in the $EnabledPlans array object.
Happy scripting!
Aaron et al
Microsoft have put this and other Technet blogs in the trash can!!!!!!
No worries–many of the TN blogs moved to https://techcommunity.microsoft.com; those of us that didn’t struck out on our own. 🙂
Thanks! Was having issue with enabling Azure Premium + Enterprise Pack, causing conflicts. This really helped, first place had I seen using both -addlicenses and -licenseoptions.
My peer, Darryl, has a lot of information regarding individual SKUs and service plans on his blog, here:
https://blogs.technet.microsoft.com/dkegg/2016/10/27/sku-and-service-plan-id-values/
Thanks for this