Assign Specific Licences in Office 365 Via PowerShell

To add specific licences to users in Office 365 without using the portal, and to assign subsets of the licences available requires two things. First you need to enumerate the licences and licence service plans, then you need to assign the new plan you have created to your users. This can be performed in bulk and is repeatable unlike when using the portal.
First, enumerate the licence plans and create your own licence:

  1. Open Microsoft Online Services Module for Windows PowerShell and connect to the service
    • $cred = Get-Credential
    • Connect-MsolService -Credential $cred
  2. Get-MsolAccountSku | Format-Table AccountSkuId, SkuPartNumber
    • The second column in this list is referenced in the next command as [SkuPartNumber]
  3. $ServicePlans = Get-MsolAccountSku | Where {$_.SkuPartNumber -eq “[SkuPartNumber]“}
  4. $ServicePlans.ServiceStatus
    • This returns all the service plans
  5. $MyO365Sku = New-MsolLicenseOptions -AccountSkuId [tenantname:AccountSkuId] -DisabledPlans Comma_Seperated_List_From_ServicePlan_Output

Secondly you need to assign the licence to the user(s):

  1. Set-MsolUser -UserPrincipalName user@domain.com -UsageLocation GB
  2. Set-MsolUserLicense -UserPrincipalName user@domain.com -AddLicenses [tenantname:AccountSkuId] -LicenseOptions $MyO365Sku
  3. Repeat for any other licences you want to apply for other users or other licence options you want to apply to this user.

For reference, the SkuPartNumber’s that we discovered are:
Inside ENTERPRISEPACK (E3) Sku:

  • YAMMER_ENTERPRISE (Yammer – though you cannot apply this individually or disable it individually, so ignore it for the purposes of this script)
  • OFFICESUBSCRIPTION (this is Office Professional Plus)
  • MCOSTANDARD (this is Lync)
  • SHAREPOINTWAC (this is Office Web Apps)
  • SHAREPOINTENTERPRISE
  • EXCHANGE_S_ENTERPRISE
  • RMS_S_ENTERPRISE (Azure Rights Management)

Inside DESKLESSWOFFPACK Sku:

  • SHAREPOINTWAC
  • SHAREPOINTDESKLESS
  • EXCHANGE_S_DESKLESS

Inside EXCHANGEARCHIVE Sku

  • EXCHANGE_S_ARCHIVE

Inside P1 (Small Business) Tennants

  • MCOLITE
  • SHAREPOINTLITE
  • EXCHANGE_L_STANDARD

K1 – DESKLESSPACK

  • SHAREPOINTDESKLESS
  • EXCHANGE_S_DESKLESS

K2 – DESKLESSWOFFPACK

  • SHAREPOINTWAC
  • SHAREPOINTDESKLESS
  • EXCHANGE_S_DESKLESS

P1 – LITEPACK

  • MCOLITE
  • SHAREPOINTLITE
  • EXCHANGE_L_STANDARD

E1 – STANDARDPACK

  • MCOSTANDARD
  • SHAREPOINTSTANDARD
  • EXCHANGE_S_STANDARD

E4 – ENTERPRISEWITHSCAL

  • YAMMER_ENTERPRISE
  • OFFICESUBSCRIPTION
  • MCOSTANDARD
  • SHAREPOINTWAC
  • SHAREPOINTENTERPRISE
  • EXCHANGE_S_ENTERPRISE
  • RMS_S_ENTERPRISE

Academic A2 Plans

  • SHAREPOINTWAC_EDU
  • MCOSTANDARD
  • SHAREPOINTSTANDARD_EDU
  • EXCHANGE_S_STANDARD

Medium Business Sku (contoso:MIDSIZEPACK)

  • SHAREPOINTWAC
  • OFFICESUBSCRIPTION
  • EXCHANGE_S_STANDARD_MIDMARKET
  • SHAREPOINTENTERPRISE_MIDMARKET
  • MCOSTANDARD_MIDMARKET

With thanks to Donte Henry (Avanade) and Tim Heeney (Microsoft). Discovered during the Office 365 MCM Class for Exchange 2010 MCM’s.

Updated June 2014 with the findings of some of those who added comments below. Note that some comments say you need to have an array for disabled plans – this is not what I find when I run the above.

Comments & Responses

18 Responses so far.

  1. Brian Reid says:

    Powershell commands corrected for US English – the cmdlets spell licence with an s near the end!

  2. For those using P1 (Small Business) tenancies, the SKU components are:

    MCOLITE
    SHAREPOINTLITE
    EXCHANGE_L_STANDARD

    Hope this helps

  3. Roman says:

    I’ve gotten this to work only a few times, only one time with multiple disabled license options.

    Here is the script I’m running:

    Get-MsolAccountSku | Format-Table AccountSkuId, SkuPartNumber

    $SKN = Read-Host “Please enter the SKU Part Number”

    $ServicePlans = Get-MsolAccountSku | Where {$_.SkuPartNumber -eq “$SKN”}

    $ServicePlans.ServiceStatus

    $SKID = Read-Host “Please enter the SKU ID”

    $DLO = Read-Host “Please enter the license options you would like to disable, separated by commasset”

    $MyO365Sku = New-MsolLicenseOptions -AccountSkuId $SKID -DisabledPlans $DLO

    $UPN = Read-Host “Please enter the User Principal Name”

    Set-MsolUserLicense -UserPrincipalName $UPN -AddLicenses $SKID -LicenseOptions $MyO365Sku

    ———————————-

    The majority of the time I get the following error, any insight?

    Set-MsolUserLicense : Unable to assign this license because it is invalid. Use the Get-MsolAccountSku cmdlet to retrieve a list of valid licenses.
    At line:1 char:20
    + Set-MsolUserLicense < <<< -UserPrincipalName $UPN -AddLicenses $SKID -LicenseOptions $MyO365Sku
    + CategoryInfo : OperationStopped: (:) [Set-MsolUserLicense], MicrosoftOnlineException
    + FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.
    InvalidUserLicenseException,Microsoft.Online.
    Administration.Automation.SetUserLicense

  4. Roman says:

    By the way, here are the components for most plans.

    K1 – DESKLESSPACK

    SHAREPOINTDESKLESS
    EXCHANGE_S_DESKLESS

    K2 – DESKLESSWOFFPACK

    SHAREPOINTWAC
    SHAREPOINTDESKLESS
    EXCHANGE_S_DESKLESS

    P1 – LITEPACK

    MCOLITE
    SHAREPOINTLITE
    EXCHANGE_L_STANDARD

    E1 – STANDARDPACK

    MCOSTANDARD
    SHAREPOINTSTANDARD
    EXCHANGE_S_STANDARD

    E2 – STANDARDWOFFPACK (?)

    E3 – ENTERPRISEPACK

    OFFICESUBSCRIPTION
    MCOSTANDARD
    SHAREPOINTWAC
    SHAREPOINTENTERPRISE
    EXCHANGE_S_ENTERPRISE

    E4 – ENTERPRISEWITHSCAL

    OFFICESUBSCRIPTION
    MCOSTANDARD
    SHAREPOINTWAC
    SHAREPOINTENTERPRISE
    EXCHANGE_S_ENTERPRISE

  5. Brian Reid says:

    @Roman, what are you entering for $SKID? It needs to be your TennantID:SKU

  6. Roman says:

    Brian,

    I am using, for example, contoso:enterprisepack

    Like I said, when I first wrote the script, it worked fine, and now it doesn’t.

    So I’m not sure what is going on. At times I can get it to work with just one disabled license option, but not multiple anymore.

    Even a single license option is only about 5% of the time.

    Roman

  7. Roman says:

    After playing around with this a bit more using PowerGui I noticed that when you create the $MyO365Sku variable, it does not read $DLO properly.

    If I manually do this step, everything works properly.

  8. Roman says:

    Just a final followup to my issue.

    The variable $DLO was not being read as an array which was causing the -DisabledPlans parameter to not read the input as a comma separated value.

    To make the script work the variable needs to be:

    $arrayDLO = (Read-Host “Please enter the license options, separated by commas with no space”).Split(“,”)

  9. Brian Reid says:

    Thanks @Roman. If you post the entire script to your own blog then I will paste a link here, or you are welcome to add the working script to the bottom.

  10. Roman says:

    Get-MsolAccountSku | Format-Table AccountSkuId, SkuPartNumber

    $SKN = Read-Host “Please enter the SKU Part Number”

    $ServicePlans = Get-MsolAccountSku | Where {$_.SkuPartNumber -eq “$SKN”}

    $ServicePlans.ServiceStatus

    $SKID = Read-Host “Please enter the SKU ID”

    $DLO = (Read-Host “Please enter the license options, separated by commas with no space”).Split(“,”)

    $MyO365Sku = New-MsolLicenseOptions -AccountSkuId $SKID -DisabledPlans $arrayDLO

    $UPN = Read-Host “Please enter the User Principal Name”

    Set-MsolUserLicense -UserPrincipalName $UPN -AddLicenses $SKID -LicenseOptions $MyO365Sku

  11. TPull says:

    I’m seeing an issue with this. The script runs successfully and I can see through the admin portal that my user was assigned the license. However, I’m still getting a warning for “Users with mailboxes but no licenses assigned”, even though the script assigned the Exchange Online license. Not until I open the user in the admin portal and click “Save” does the warning go away. It seems as though Set-MsolUserLicense isn’t doing whatever “Save” does in the web interface.

  12. Steve says:

    Thanks very much, Brian! Not sure how we would have ever figured this out.

    One note: in your original post i think you use “LicenceOptions” where the correct option is “LicenseOptions” (note the ‘c’ to a ‘s’). ;-)

    thanks again!

  13. Brian Reid says:

    @Steve, English UK (my language) changed to English US (Office 365 admin language). I think that is it for the regional errors now.

  14. Anonymous says:

    These are the service plans for the Academic A2 plans.

    SHAREPOINTWAC_EDU
    MCOSTANDARD
    SHAREPOINTSTANDARD_EDU
    EXCHANGE_S_STANDARD

  15. jreed336 says:

    just ran through this. what we have found is that (at least with A2 licenses) you must assign the full license first. then go back and remove the serviceplans you do not want (separate commands). not sure why yet, but it’s the only way it’s working right now.

  16. Brian Reid says:

    Here is the SKU for AADRM: RIGHTSMANAGEMENT_ADHOC
    And the Service Plan for the same is RMS_S_ADHOC

  17. Peter Nield says:

    Hi,

    I was struggling with this, but I’ve found that when you create the New-MsolLicenseOptions, the disabled options parameter needs to be a array object, not just a comma separated list, e.g.

    Works when assigning license options:

    $LicOptions = New-MsolLicenseOptions -AccountSkuId “:STANDARDWOFFPACK_STUDENT” -DisabledPlans @(“SHAREPOINTWAC_EDU”,”MCOSTANDARD”,”SHAREPOINTSTANDARD_EDU”)

    Does not work when assigning license options:

    $LicOptions = New-MsolLicenseOptions -AccountSkuId “:STANDARDWOFFPACK_STUDENT” -DisabledPlans SHAREPOINTWAC_EDU, MCOSTANDARD, SHAREPOINTSTANDARD_EDU

    And the -LicenseOptions parameter for Set-MSOLUserLicense only works if:

    1. Modifying an license already assigned to the user.

    2. Adding the corresponding license in the same command.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>