Office 365: Assign licenses based on groups using PowerShell

Important note: The end of an era with licensing scripts is near… and the beginning of a new one with Azure AD Group Based Licensing is here. Group Based Licensing is now in preview and currently requires a paid Azure AD Subscription. Try it out and give Microsoft your feedback on how they can make it even better! 

Update 2016-01-07: Updated the script with a new function to support nested groups.

As a follow up to my earlier post about assigning Office 365 licenses based on ad attribute, I’ve now created another script that uses another approach to assign the licenses.
Instead of using ad attributes, we are here using security groups to assign the licenses.

Since you want to automate license assignment, I am assuming that you are using DirSync.
In this script, the groups and group members are enumerated directly in Windows Azure Active Directory. This means that the groups you will use to assign licenses, must be synchronized to WAAD. If you are looking for a more advanced script with change and removal functions, check this one out.

Note: Users that already have a license are not processed by the script, nor are licenses removed from users that are not longer member of the groups.

Getting started
Getting started with the script is very easy. In the $Licenses hash table, you define the licenses to assign, the group to use for assignment and the license SKU.
The license SKU id’s for your tenant are found with the Get-MsolLicenseSKU cmdlet, as below:

2014-04-15 22-10-25

Here you will find a good translation table that will help you interpret the License SKU ID to the actual license type. When you have done that, just to put in your O365 credentials and UsageLocation in the script and then you’re all set to schedule the script.

2014-04-15 22-37-53

LicenseO365Users.ps1

#2016-01-07 - Updated the script with a new function to support nested groups.
#Import Required PowerShell Modules
#Note - the Script Requires PowerShell 3.0!
Import-Module MSOnline

#Office 365 Admin Credentials
$CloudUsername = 'admin@tenant.onmicrosoft.com'
$CloudPassword = ConvertTo-SecureString 'password' -AsPlainText -Force
$CloudCred = New-Object System.Management.Automation.PSCredential $CloudUsername, $CloudPassword

#Connect to Office 365
Connect-MsolService -Credential $CloudCred
function Get-JDMsolGroupMember {
    param(
        [CmdletBinding(SupportsShouldProcess=$true)]
        [Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0)]
        [ValidateScript({Get-MsolGroup -ObjectId $_})]
        $ObjectId,
        [switch]$Recursive
    )
    begin {
        $MSOLAccountSku = Get-MsolAccountSku -ErrorAction Ignore -WarningAction Ignore
        if (-not($MSOLAccountSku)) {
            throw "Not connected to Azure AD, run Connect-MsolService"
        }
    }
    process {
        $UserMembers = Get-MsolGroupMember -GroupObjectId $ObjectId -MemberObjectTypes User -All
        if ($PSBoundParameters['Recursive']) {
            $GroupsMembers = Get-MsolGroupMember -GroupObjectId $ObjectId -MemberObjectTypes Group -All
            $GroupsMembers | ForEach-Object -Process {
                $UserMembers += Get-JDMsolGroupMember -Recursive -ObjectId $_.ObjectId
            }
        }
        Write-Output ($UserMembers | Sort-Object -Property EmailAddress -Unique) 

    }
    end {

    }
}

$Licenses = @{
                 'E1' = @{
                          LicenseSKU = 'mstlabs:STANDARDPACK'
                          Group = 'E1_Users'
                        }                           

                 'E3' = @{
                          LicenseSKU = 'mstlabs:ENTERPRISEPACK'
                          Group = 'Office 365 E5'
                        }
            }
$UsageLocation = 'SE'

foreach ($license in $Licenses.Keys) {

    $GroupName = $Licenses[$license].Group
    $GroupID = (Get-MsolGroup -All | Where-Object {$_.DisplayName -eq $GroupName}).ObjectId
    $AccountSKU = Get-MsolAccountSku | Where-Object {$_.AccountSKUID -eq $Licenses[$license].LicenseSKU}

    Write-Output "Checking for unlicensed $license users in group $GroupName with ObjectGuid $GroupID..."

    $GroupMembers = (Get-JDMsolGroupMember -ObjectId $GroupID -Recursive | Where-Object {$_.IsLicensed -eq $false}).EmailAddress

    if ($AccountSKU.ActiveUnits - $AccountSKU.consumedunits -lt $GroupMembers.Count) {
        Write-Warning 'Not enough licenses for all users, please remove user licenses or buy more licenses'
      }

        foreach ($User in $GroupMembers) {
          Try {
            Set-MsolUser -UserPrincipalName $User -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
            Set-MsolUserLicense -UserPrincipalName $User -AddLicenses $AccountSKU.AccountSkuId -ErrorAction Stop -WarningAction Stop
            Write-Output "Successfully licensed $User with $license"
          } catch {
            Write-Warning "Error when licensing $User`r`n$_"
          }

        }

}

Looking for other script options using groups?
Office 365: Assign licenses based on groups using PowerShell – Advanced version – adds and removes licenses for the users as well.
Office 365: Assign individual parts of licenses based on groups using PowerShell – script with the ability to add and remove serviceparts of a license.

There are lots of things that are not in the script that could also be automated, please help us prioritize with the features you’d like to have the most.

/Johan

Advertisements

42 thoughts on “Office 365: Assign licenses based on groups using PowerShell

  1. Pingback: Office 365: Assign licenses based on groups using PowerShell – Advanced version | Tailspintoys – 365lab.net

    1. Johan Dahlbom Post author

      Hi Annie,
      Thanks for reading!

      To disable specific options for each plan, look into the following site: http://blogs.technet.com/b/treycarlee/archive/2013/11/01/list-of-powershell-licensing-sku-s-for-office-365.aspx.

      Basically you would need to add a $disabledplans as in the blogpost above for each SKU, use the -LicenseOptions parameter with the Set-MsolUserLicense cmdlet on row 43.

      Hope this helps you, let me know if you need further help!

      /Johan

      Reply
      1. Annie

        Forgive me as aI am not an expert programer. Would the option be added when you define the license with group or where you actually assign the license? I am not sure what syntax to use….

      2. ripulhanda

        Hi Johan,

        I am trying to do this but unable to accomplish. I can assign E3 license but running into issues disabling specific options. Would you be able to share how to use the $disabledplans in the above script?

  2. Johan Dahlbom Post author

    Hi,
    If you have different options for different licenses, it should be added then the Group is defined and picked up later. I’ll put this on my list with things to do follow up posts on.

    /Johan

    Reply
  3. Annie

    I was able to modify the scrips to assign different license options, however I have notified during the testing that if a group contains a disabled AD account it won’t assign licenses to anyone in the group. Have you experienced that?

    Reply
    1. Johan Dahlbom Post author

      Hi,

      Perfect. I’ve tried your scenario with disabled users in the Groups, but have not experienced that particular error.
      I can help you troubleshoot further, but would then need to see the Changes in the code you’ve done.

      Thanks for Reading!

      Reply
      1. Annie Wojcik/Northcentral Technical College

        Hello,
        I would be happy to share!

        (See attached file: ADGroup.ps1)

        Thanks!

  4. Mark

    Hi Johan,

    Thank you for posting this script. I have tried to use it on my system. I have assigned the users to the correct group, adjusted the SKU in the script, edited authentication details.

    When I run the script, I simply get the message “Error when licensing”.

    Is there anything else I need to do in my environment?

    Mark

    Reply
    1. Johan Dahlbom Post author

      Hi Mark,

      Thanks for Reading!
      To be able to troubleshoot further, I have now updated row 47 to include more debugging information. Please replace that row in the script you are running, and hopefully we’ll get more in depth information about the issue.

      Control questions:
      * Are you running PowerShell 3.0 on the machine which are running the script? I’ve seen problems running this on PowerShell 2.0 Machines.
      * Are you running the latest version of the Windows Azure Active Directory module for PowerShell? There are quite a bit of bugs in older versions (one thing with the amount of Group members that could be enumerated. Please update to the latest version if not already running it.

      Hope this helps you out!

      /Johan

      Reply
      1. Mark

        Hi Johan,

        Thank you very much for your swift response, it is very much appreciated. I had updated the Windows Azure Active Directory module, but I had not thought to update my version of PowerShell.

        I have updated to version 3.0 and the script is running perfectly.

        Once again, thank you very much for the script and for your help in getting it working.

        Mark

    1. Johan Dahlbom Post author

      Hi,
      The script will change license if s user gets removed from example the E1 group and added to the E3 group. There are no error handling implemented for conflicting groups (if someone is a member of both groups).

      Thanks for reading!

      /Johan

      Reply
      1. NickDorak

        I just tested, it doesn’t look like its working as you described. Perhaps line 35 where “$_.IsLicensed -eq $false” is preventing the change. I will fiddle with this to my specific needs, thanks for the initial help!

      2. NickDorak

        Removing the ” | Where-Object {$_.IsLicensed -eq $false}” option gives an error for each existing member…
        Unable to assign this license because it is invalid. Use the Get-MsolAccountSku cmdlet to retrieve a list of valid licenses.
        Then for new members (previously assigned to another group) get the following error…
        Unable to update license for this user. The set of licenses includes two or more service plans which cannot be assigned at the same time. Conflicting Service Plans: MCOSTANDARD, MCOSTANDARD.
        I have confirmed that users are only in a single group at a time.

      3. NickDorak

        Here is my contribution to your work which has corrected the issue for me (replace section starting with line 41 / from the second ‘FroEach’)…

        foreach ($User in $GroupMembers) {
        # For Users without license
        If (!(Get-MsolUser -UserPrincipalName $User).Licenses.AccountSkuId) {
        Try {
        Set-MsolUser -UserPrincipalName $User -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
        Set-MsolUserLicense -UserPrincipalName $User -AddLicenses $AccountSKU.AccountSkuId -ErrorAction Stop -WarningAction Stop
        Write-Output “Successfully licensed $User with $license”
        } catch {
        Write-Warning “Error when licensing $User`r`n$_”
        }
        }
        # For Users with wrong license
        If ((Get-MsolUser -UserPrincipalName $User).Licenses.AccountSkuId -ne $AccountSKU.AccountSkuId) {
        Try {
        Set-MsolUser -UserPrincipalName $User -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
        Set-MsolUserLicense -UserPrincipalName $User -RemoveLicenses (Get-MsolUser -UserPrincipalName $User).Licenses.AccountSkuId -AddLicenses $AccountSKU.AccountSkuId -ErrorAction Stop -WarningAction Stop
        Write-Output “Changed license for user $User to new license $license”
        } catch {
        Write-Warning “Error when licensing $User`r`n$_”
        }
        }
        }

  5. Pingback: Azure AD, Licensing users in a Security Group - MiguelNunez - Site Home - MSDN Blogs

  6. Joel Coehoorn

    This is great for seeding new users… do you have something for removing old users? I’d love to change the error handling to add the lines to a list, and then send an e-mail where the body shows any errors, following by number of new licenses/licenses remaining, and then put it into a scheduled task to run overnight that I can forget about as long as the daily e-mail it sends is okay.

    Reply
    1. Johan Dahlbom Post author

      Hi Joel,
      Sorry for the late reply.
      Have you seen the more advanced version which removes and adds licenses?

      Regarding logging, if you look in to the places where I’m using “Write-Output” , it could easily be changed to something else, for example an email.

      Send me an email if you’d like additonal help with that offline.

      /Johan

      Reply
  7. Pingback: What are my SKU names for Office 365 Education and how can I automate the licensing? - Microsoft Education in the Cloud - Site Home - TechNet Blogs

  8. Tom

    Hello Johan and thank you for your useful script.
    Is there by any chance a way to make it works when users are in a group, nested in an other group?
    Right now, the $GroupMembers is empty in my case because the users are not directly in this group but in several nested groups.
    Thank you!
    Tom

    Reply
    1. Johan Dahlbom Post author

      Hi Tom,

      Thanks for reading! Get-MsolGroupMember do not support nested group as it is right now.
      I will give it a couple of minutes and see if I can work an alternative out for you 🙂

      /Johan

      Reply
    2. Johan Dahlbom Post author

      Hi Tom,

      I have now updated the script with a new function for enumerating group members to support nested groups. Let me know if you run in to any problems or if you have any questions.

      /Johan

      Reply
      1. Mike

        I tested this script, but the nested groupmember did not get the licence… it´s checking for unlicensed E3 users,.. but nothing shows after that and the script ends.?!

  9. Patrick

    Can this be modified somehow to assign multiple SKU’s at once?

    For instance, in education if I have tenant:stadardwoffpack_student and tenant:officesubscription_student that I want to assign how can I do that?

    I tried modifying the $licenses section to where it looks like this:
    LicenseSKU = ‘tenant:sku1,tenant:sku2’
    or
    LicenseSKU = ‘”tenant:sku1″,”tenant:sku2″‘

    But it always fails. If I manually modify the set-msoluserlicense line I can get it to work but that just assigns the same sku to every user regardless of the group.

    Help?

    Reply
  10. Pingback: Office 365: Assign licenses based on groups using PowerShell – Advanced version – Nuno Árias Silva Website

  11. Aitazaz Aijaz

    Hi,
    ‘E1’ = @{
    LicenseSKU = ‘aspenhospital:SHAREPOINTSTANDARD’
    Group = ‘All users’
    We are going to assign above license to to group All users, so i have changed following things according my environment, i just want to know what does that ‘E1’ means here??

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s