Office 365 License Assignment
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 way to see the inside of a SKU. If you thought you could run a Get-MsolAccountSku | FL, you'd be wrong. The licenses are stored in an array, so you need to enumerate the array.
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 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!
Comments
- Anonymous
July 14, 2016
Thanks for this - Anonymous
September 08, 2016
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.- Anonymous
November 30, 2016
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/
- Anonymous