I’ve spent the last day or so working on how to reliably assign licenses to Office 365 for users with Powershell. My particular test environment is an Office 365 for Education space but the procedure here should work for any Office 365 setup.
There are a few blog posts, magazine articles and forum threads about this process but they only provided pieces of the overall puzzle when I was working this out so this is my attempt to put it all together.
Office 365 Account SKUs and SKU ID’s:
With your Office 365 subscription, you are assigned one or more account SKU’s. These appear to be a combination of your tenant ID and a plan identifier, where the plan identifier represents a bundle of services (which we’ll get to in a bit). To see your assigned sku’s, run the cmdlet get-msolaccountsku, which lists the ones that are available to your tenant and also some statistics about usage.
Below is sample output when I run this cmdlet against an Office 365 tenant which has educational plan A2 assigned:
PS v3.0 C:\ > Get-MsolAccountSku
AccountSkuId ActiveUnits WarningUnits ConsumedUnits
------------ ----------- ------------ -------------
myschool:STANDARDWOFFPACK_STUDENT 1000 0 1
myschool:STANDARDWOFFPACK_FACULTY 100 0 0
myschool:EXCHANGESTANDARD_ALUMNI 1000 0 0
myschool:EXCHANGESTANDARD_STUDENT 1000 0 208
My tenant has four account SKU ID’s present which can be assigned to users. Each Sku ID represents a “bundle” of one or more licensed services such as Sharepoint, Exchange, Lync, the office web apps, etc.
To see the component services of these bundles, you need to crack open its SKU ID and look at the “service plans” that it contains. It’s easiest to do this via a two-step process.
First, you use get-msolaccountsku to get the SkuPartNumber for each of the Sku ID’s. In all my testing, the SkuPartNumber value has been the same as the AccountSkuId minus the domain identifier prefix on it but we should assume that the two can diverge in the future.
PS v3.0 C:\ > Get-MsolAccountSku | ft accountskuid,skupartnumber
AccountSkuId SkuPartNumber
------------ -------------
myschool:STANDARDWOFFPACK_STUDENT STANDARDWOFFPACK_STUDENT
myschool:STANDARDWOFFPACK_FACULTY STANDARDWOFFPACK_FACULTY
myschool:EXCHANGESTANDARD_ALUMNI EXCHANGESTANDARD_ALUMNI
myschool:EXCHANGESTANDARD_STUDENT EXCHANGESTANDARD_STUDENT
Next, let’s open up STANDARDWOFFPACK_STUDENT to see what its component services are.
Note that we’re using the SkuPartNumber here and not the AccountSkuId, which looks similar.
PS v3.0 C:\ > $plans = Get-MsolAccountSku | Where {$_.SkuPartNumber -eq "STANDARDWOFFPACK_STUDENT"}
PS v3.0 C:\ > $plans.servicestatus
ServicePlan ProvisioningStatus
----------- ------------------
SHAREPOINTWAC_EDU Success
MCOSTANDARD Success
SHAREPOINTSTANDARD_EDU Success
EXCHANGE_S_STANDARD Success
And there we see that STANDARDWOFFPACK_STUDENT has four component services:
- SHAREPOINTWAC_EDU: (This is for the 365 web apps, not Sharepoint)
- MCOSTANDARD (Office 365 Lync)
- SHAREPOINTSTANDARD_EDU (Office 365 Sharepoint)
- EXCHANGE_S_STANDARD (Exchange)
Now, how do we use this information to apply licenses to Office 365 users with Powershell?
The primary way that you apply user licenses for O365 with Powershell is with the set-msoluserlicense cmdlet. You can either use it on its own and specify the UPN of the targeted user on the command line or pipe a user object to it with get-msoluser.
set-msoluserlicense has three parameters that I’m focusing on for the purposes of this post:
- -AddLicenses <string[]>
- -LicenseOptions <LicenseOption[]>
- -Removelicenses <string[]>
The first and last options relate to applying or removing all functions within a license “bundle” to a user and the middle one allows you to manage which services are enabled for a particular user. In my testing, it appears that you must have an overall license “bundle” in place for a user (enabling all functions) before you can handle enabling/disabling the individual components.
The -AddLicenses and -RemoveLicenses parameters require a string value that must match one of the available AccountSkuId’s on your 365 tenant.
You can also specify licenses with the new-msoluser cmdlet via the -LicenseAssignment and -LicenseOptions parameters but I’m not going to discuss them here because they work in a similar way.
Here’s a one-liner to enable a single user for all available services within an AccountSkuId. You do this by applying the AccountSkluID for the “bundle” that you want the user to get.
get-msoluser -UserPrincipalName first.last@myschool.edu | set-msoluserlicense -AddLicenses "myschool:STANDARDWOFFPACK_STUDENT"
And here’s how to verify that it worked by checking the ProvisioningStatus of the user’s licenses. Success == good, of course.
PS v3.0 C:\ > (get-msoluser -UserPrincipalName first.last@myschool.edu).licenses.servicestatus
ServicePlan ProvisioningStatus
----------- ------------------
SHAREPOINTWAC_EDU Success
MCOSTANDARD Success
SHAREPOINTSTANDARD_EDU Success
EXCHANGE_S_STANDARD Success
Disabling Specific Office 365 Functions for a User
Let’s say that my hypothetical customer isn’t ready to support Lync, so we want to shut that functionality off for our test user. To do this, we need to create a LicenseOptions object which references the AccountSkluId for the “bundle” that the user is using for and also lists the Lync component on the DisabledPlans parameter.
First, we create a LicenseOptions object which has Lync disabled. I’ll call it $nolync here.
PS v3.0 C:\ > $nolync = New-MsolLicenseOptions -AccountSkuId myschool:STANDARDWOFFPACK_STUDENT -DisabledPlans MCOSTANDARD
PS v3.0 C:\ > $nolync
ExtensionData AccountSkuId DisabledServicePlans
------------- ------------ --------------------
Microsoft.Online.Administration.Acco... {MCOSTANDARD}
Next, we use set-msoluserlicense to apply the license options object that we just created to the user. Everything that’s not listed in the DisabledServicePlans property will be ENABLED after applying this to the user, so “stacking” LicenseOptions calls against a user will result in a last-writer-wins scenario.
PS v3.0 C:\ > get-msoluser -UserPrincipalName first.last@myschool.edu | Set-MsolUserLicense -LicenseOptions $nolync
PS v3.0 C:\ >
Now, we can check the servicestatus property of the user’s licenses to verify that Lync has been shut off:
PS v3.0 C:\ > (get-msoluser -UserPrincipalName first.last@myschool.edu).licenses.servicestatus
ServicePlan ProvisioningStatus
----------- ------------------
SHAREPOINTWAC_EDU Success
MCOSTANDARD Disabled
SHAREPOINTSTANDARD_EDU Success
EXCHANGE_S_STANDARD Success
IMPORTANT NOTE about SharePoint licensing with office 365. I had a lot of trouble attempting to disable just SharePoint for users in my tenant – it failed every time and I couldn’t figure out why. After significant head-scratching and web searches, I eventually found this forum thread, where a Microsoft support person mentions as an aside that Office Web Apps and SharePoint are co-dependent so you can’t disable SharePoint in Office 365 without also disabling the Office web apps. While this solved my problem, the enforced linkage of the two is unfortunate as customers might want their users to have access to the office web apps (which IMO are very nice) but not SharePoint because of the support complexity that SharePoint brings. I suspect this is because the Office web apps use Sharepoint for storage so this may be resolved when/if SkyDrive Pro arrives on the scene for 365. [ UPDATE 12/21/2012 : This has been confirmed. The Office web apps in Office 365 are configured to use a document library on a Sharepoint site as their storage instead of Skydrive like the free versions are. ]
For now, however, if you want to disable SharePoint for your users, make sure you also disable the Office Web Apps or you’ll get an error when you try to apply the change.
This is also a convenient example of how to disable two Office 365 functions together – just provide their identifiers as a comma-separated string to the new-msollicenseoptions cmdlet.
PS v3.0 C:\ > $nosharepoint = New-MsolLicenseOptions -AccountSkuId myschool:STANDARDWOFFPACK_STUDENT -DisabledPlans SHAREPOINTWAC_EDU,SHAREPOINTSTANDARD_EDU
PS v3.0 C:\ > $nosharepoint
ExtensionData AccountSkuId DisabledServicePlans
------------- ------------ --------------------
Microsoft.Online.Administration.Acco... {SHAREPOINTWAC_EDU, SHAREPOINTSTANDA...
PS v3.0 C:\ > get-msoluser -UserPrincipalName first.last@myschool.edu | Set-MsolUserLicense -LicenseOptions $nosharepoint
PS v3.0 C:\ > (get-msoluser -UserPrincipalName first.last@myschool.edu).licenses.servicestatus
ServicePlan ProvisioningStatus
----------- ------------------
SHAREPOINTWAC_EDU Disabled
MCOSTANDARD Success
SHAREPOINTSTANDARD_EDU Disabled
EXCHANGE_S_STANDARD Success
If you want to strip all licenses from a user, use the -removelicenses parameter with the AccountSkuId string for the license bundle and they’re toast. Note that this can deprovision mailboxes, etc so use this with care!
Lastly, a few miscellaneous observations and comments about the license-handling cmdlets and objects themselves that didn’t fit in elsewhere:
- The overall license “bundle” is passed as a STRING to the -addlicenses and -removelicenses parameters to the set-msoluserlicense cmdlet. However, the -licenseoptions parameter to the same cmdlet requires that you pass it an OBJECT of the type LicenseOption, which is helpfully returned by the new-licenseoption cmdlet. It would make a lot more sense if all three parameters agreed on what sort of parameter they required.
- If you want to give a new user a granular set of permissions, it appears that you need to first assign the overall license Sku to a user (which activates all functions) and then stamp it with a licenseoptions object which has the components that you don’t want the user to see listed as disabled. You can’t just stamp an unlicensed user with a LicenseOptions object or the assignment will fail.
- Additionally, according to a reply to this posted request for help, the -addlicenses and -licenseoptions parameters don’t like to be used together. This appears to be my experience as well.
- The -UnlicensedUsersOnly parameter to get-msoluser will (obviously) return only unlicensed users – this is handy.
- Error reporting from assignment of licenses in 365 via Powershell is TERRIBLE. The most common cause of problems is making a typo in the new-msollicenseoptions cmdlet since it doesn’t seem to perform any input validation.