Tag Archives: Set-MsolUserLicense

Office 365: Assign individual parts of 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! 

The story continues… After numerous requests regarding handling parts of licenses in my older licensing scripts , I’ve now created an example on how to do this using security groups.

Please note that this is of course not a complete solution, just an example on how to incorporate this in to one of the earlier solutions created.

SCENARIO
In this example, I will have three groups each assigning different parts of an E3 License. One assiging the Full E3, one assigning Exchange Online and one assigning Lync Online + Office 365 ProPlus.
In order to assign them with PowerShell, we need the ServicePlan name of each part we want to assign. Those can be found with the following command for an E3-license:

(Get-MsolAccountSku | Where-Object {$_.SkuPartNumber -eq "ENTERPRISEPACK"}).ServiceStatus

2014-12-16_20-32-02
As seen above the names are pretty easy to recognise, if you are unsure which one is which, you will find a good translation table here.

Disabling plans with PowerShell requires you to to select the ones that you want to disable rather than the ones you want to enable, just like in the portal. In my example I’m choosing the parts I want to assign per group, which means I’m disabling all other parts than just the ones you want.
See the example below how I’ve configured my $Licenses hashtable for my scenario:

$Licenses = @{
                 'E3-ExchangeOnline' = @{
                          LicenseSKU = 'tenant:ENTERPRISEPACK'
                          EnabledPlans = 'EXCHANGE_S_ENTERPRISE'
                          Group = 'E3-ExchangeOnline-Users'
                        }
                 'E3-LyncO365ProPlus' = @{
                          LicenseSKU = 'tenant:ENTERPRISEPACK'
                          EnabledPlans = 'MCOSTANDARD','OFFICESUBSCRIPTION'
                          Group = 'E3-LyncO365ProPlus-Users'
                        }
                 'E3' = @{
                          LicenseSKU = 'tenant:ENTERPRISEPACK'
                          Group = 'E3-Users'
                        }
            }

RUNNING THE SCRIPT
After editing the $Licenses hashtable, $UsageLocation and tenant credentials, you’re ready to run the script as in the screenshot below.
2014-12-16_21-52-24

2014-12-16_21-40-47
A user that have been assigned licenses with the E3-LyncO365ProPlus-Users group in the example

LicenseO365Users.ps1

<# .SYNOPSIS     Script that assigns Office 365 licenses based on Group membership in AAD. .NOTES     Author: Johan Dahlbom      Blog: 365lab.net      Email: johan[at]dahlbom.eu      The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights.     Requires PowerShell Version 3.0! #>

#Import Required PowerShell Modules
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
$UsageLocation = 'SE'

$Licenses = @{
                 'E3-ExchangeOnline' = @{
                          LicenseSKU = 'tenant:ENTERPRISEPACK'
                          EnabledPlans = 'EXCHANGE_S_ENTERPRISE'
                          Group = 'E3-ExchangeOnline-Users'
                        }
                 'E3-LyncO365ProPlus' = @{
                          LicenseSKU = 'tenant:ENTERPRISEPACK'
                          EnabledPlans = 'MCOSTANDARD','OFFICESUBSCRIPTION'
                          Group = 'E3-LyncO365ProPlus-Users'
                        }
                 'E3' = @{
                          LicenseSKU = 'tenant:ENTERPRISEPACK'
                          Group = 'E3-Users'
                        }
            }

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"

    #region Disable non specific plans
    $EnabledPlans = $Licenses[$license].EnabledPlans
    if ($EnabledPlans) {
        $LicenseOptionHt = @{
            AccountSkuId = $AccountSKU.AccountSkuId
            DisabledPlans =  (Compare-Object -ReferenceObject $AccountSKU.ServiceStatus.ServicePlan.ServiceName -DifferenceObject $EnabledPlans).InputObject
        }
        $LicenseOptions = New-MsolLicenseOptions @LicenseOptionHt
    }
    #endregion Disable non specific plans

    #Get all unlicensed group members - needs to be changed if a user should be able to have more than one license
    $GroupMembers = (Get-MsolGroupMember -GroupObjectId $GroupID -All | Where-Object {$_.IsLicensed -eq $false}).EmailAddress
    #Warn if not enough licenses are available
    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 UsageLocation
            Set-MsolUser -UserPrincipalName $User -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
            $LicenseConfig = @{
                UserPrincipalName = $User
                AddLicenses = $AccountSKU.AccountSkuId
            }
            if ($EnabledPlans) {
                $LicenseConfig['LicenseOptions'] = $LicenseOptions
            }
            Set-MsolUserLicense @LicenseConfig -ErrorAction Stop -WarningAction Stop
            Write-Output "SUCCESS: licensed $User with $license"
        } catch {
            Write-Warning "Error when licensing $User`r`n$_"
        }
    }
 }

Let me know if you have any questions or feedback!

/Johan

Office 365: Assign licenses based on groups using PowerShell – Advanced version

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! 

The never ending story about Office 365 licensing continues… This time it’s an extension of my script to assign licenses based on groups, with additional functionality to remove and change licenses for users.
I’ve come across scenarios where this have been a requirement a couple of times, and wanted to see how much work that was required to get the job done. 🙂

If you just want to assign licenses for users based on groups, plain and simple, this is not the script for you…

Running the script
The script is tested in a tenant with two different license types (E1 and E3). Therefore, the functionality has been verified against that, so if you have three or four different licenses to assign in your tenant, you have to do your own testing! 🙂

The following functions are included in the script:

  • Assignment of licenses for new users based on groups/licenseSKU’s in the $licenses hashtable
  • Switch of licensetype if a user is moved from one group to another
  • Removal of license if the user no longer is a member in any of the license assignment groups

LicenseFix

IMPORTANT: Since the script actually will remove licenses for users that are not in any of the groups, you have to make sure that you populate the license assignment groups prior to first time running the script.

Apart from the above, the script requirements and setup details are the same as in this post.

LicenseO365Users.ps1

<#   .SYNOPSIS      Script that assigns Office 365 licenses based on Group membership in WAAD. .DESCRIPTION     The script assigns of licenses for new users based on groups/licenseSKUs in the $licenses hashtable.     It switch licensetype if a user is moved from one group to Another.     It removes the license if the user no longer is a member in any of the license assignment Groups.     Updated 2015-03-25 to support multiple skus for each user.     The script REQUIRES PowerShell 3.0 or later! .NOTES      Author: Johan Dahlbom      Blog: 365lab.net      Email: johan[at]dahlbom.eu      The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights.      #>
#Import Required PowerShell Modules
Import-Module MSOnline

#Office 365 Admin Credentials
$CloudUsername = 'admin@365lab.net'
$CloudPassword = ConvertTo-SecureString 'Password' -AsPlainText -Force
$CloudCred = New-Object System.Management.Automation.PSCredential $CloudUsername, $CloudPassword

#Connect to Office 365
Connect-MsolService -Credential $CloudCred

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

                 'E3' = @{
                          LicenseSKU = 'mstlabs:ENTERPRISEPACK'
                          Group = 'E3_Users'
                        }
            }

$UsageLocation = 'SE'

#Get all currently licensed users and put them in a custom object
$LicensedUserDetails = Get-MsolUser -All | Where-Object {$_.IsLicensed -eq 'True'} | ForEach-Object {
 [pscustomobject]@{
            UserPrincipalName = $_.UserPrincipalName
            License = $_.Licenses.AccountSkuId
            }
 }

#Create array for users to change or delete
$UsersToChangeOrDelete = @()

foreach ($license in $Licenses.Keys) {

  #Get current group name and ObjectID from Hashtable
  $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..."
  #Get all members of the group in current scope
  $GroupMembers = (Get-MsolGroupMember -GroupObjectId $GroupID -All).EmailAddress
  #Get all already licensed users in current scope
  $ActiveUsers = ($LicensedUserDetails | Where-Object {$_.License -eq $licenses[$license].LicenseSKU}).UserPrincipalName
  $UsersToHandle = ''

    if ($GroupMembers) {
        if ($ActiveUsers) {
            #Compare $Groupmembers and $Activeusers
            #Users which are in the group but not licensed, will be added
            #Users licensed, but not, will be evaluated for deletion or change of license
            $UsersToHandle = Compare-Object -ReferenceObject $GroupMembers -DifferenceObject $ActiveUsers -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
            $UsersToAdd = ($UsersToHandle | Where-Object {$_.SideIndicator -eq '<='}).InputObject             $UsersToChangeOrDelete += ($UsersToHandle | Where-Object {$_.SideIndicator -eq '=>'}).InputObject
        } else {
            #No licenses currently assigned for the license in scope, assign licenses to all group members.
            $UsersToAdd = $GroupMembers
        }

    } else {
      Write-Warning  "Group $GroupName is empty - will process removal or move of all users with license $($AccountSKU.AccountSkuId)"
      #If no users are a member in the group, add them for deletion or change of license.
      $UsersToChangeOrDelete += $ActiveUsers
    }

  #Check the amount of licenses left...
  if ($AccountSKU.ActiveUnits - $AccountSKU.consumedunits -lt $UsersToAdd.Count) {
        Write-Warning 'Not enough licenses for all users, please remove user licenses or buy more licenses'
  }

     foreach ($User in $UsersToAdd){

        #Process all users for license assignment, if not already licensed with the SKU in order.
          if ((Get-MsolUser -UserPrincipalName $User).Licenses.AccountSkuId -notcontains $AccountSku.AccountSkuId) {
            try {
                  #Assign UsageLocation and License.
                  Set-MsolUser -UserPrincipalName $User -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
                  Set-MsolUserLicense -UserPrincipalName $User -AddLicenses $AccountSKU.AccountSkuId -ErrorAction Stop -WarningAction Stop
                  Write-Output "SUCCESS: Licensed $User with $license"
            } catch {
                  Write-Warning "Error when licensing $User"

            }

          }
     }
}

#Process users for change or deletion
if ($UsersToChangeOrDelete -ne $null) {
        foreach ($User in $UsersToChangeOrDelete) {
          if ($user -ne $null) {

            #Fetch users old license for later usage
            $OldLicense = ($LicensedUserDetails | Where-Object {$_.UserPrincipalName -eq $User}).License

             #Loop through to check if the user group assignment has been changed, and put the old and the new license in a custom object.
             #Only one license group per user is currently supported.
             $ChangeLicense = $Licenses.Keys | ForEach-Object {
                  $GroupName = $Licenses[$_].Group
                  if (Get-MsolGroupMember -All -GroupObjectId (Get-MsolGroup -All | Where-Object {$_.DisplayName -eq $GroupName}).ObjectId | Where-Object {$_.EmailAddress -eq $User}) {
                     [pscustomobject]@{
                        OldLicense = $OldLicense
                        NewLicense = $Licenses[$_].LicenseSKU
                     }
                  } 

              }

              if ($ChangeLicense) {
                    #The user were assigned to another group, switch license to the new one.
                    try {
                          Set-MsolUserLicense -UserPrincipalName $User -RemoveLicenses $ChangeLicense.OldLicense -AddLicenses $ChangeLicense.NewLicense -ErrorAction Stop -WarningAction Stop
                          Write-Output "SUCCESS: Changed license for user $User from $($ChangeLicense.OldLicense) to $($ChangeLicense.NewLicense)"
                    } catch {
                          Write-Warning "Error when changing license on $User`r`n$_"
                    }

              } else {  

                    #The user is no longer a member of any license group, remove license
                    Write-Warning "$User is not a member of any group, license will be removed... "
                    try {
                          Set-MsolUserLicense -UserPrincipalName $User -RemoveLicenses $OldLicense -ErrorAction Stop -WarningAction Stop
                          Write-Output "SUCCESS: Removed $OldLicense for $User"
                    } catch {
                          Write-Warning "Error when removing license on user`r`n$_"
                    }
              }
         }
    }
}

Hope this helps you if having this scenario, please let me know if you have features requests or other things that can improve the script!

/Johan

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

Office 365 PowerShell tip: Automatically assign licenses based on AD attribute

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! 

Using DirSync in combination with Office 365 / Windows Azure Active Directory is great.
It automates user creation and makes you able to master all user creation changes from on premises.
There is just one(or two) things you need to do manually, assign licenses…
This can be done both in the portal or with PowerShell.

Depending on how your license structure looks like and how large environment you have, you might want to automate this in a more convenient way. There is a Wiki article on TechNet with a few examples on how to automate it as well (both with Security Groups and AD attributes). http://social.technet.microsoft.com/wiki/contents/articles/15905.how-to-use-powershell-to-automatically-assign-licenses-to-your-office365-users.aspx

Until Microsoft has come up with an integrated solution for this in DirSync or something else, we have to stick with PowerShell…

The case:
In my case we want to assign Office 365 licenses based on a local AD attribute of your choice fully automated and minimal input.
We also want a bit of logging so we are able to find and fix errors as easy as possible.

In order to assign a license in Office 365, we need to assign two attributes on a user(of course the user must exist…):
UsageLocation and Licenses
Also, if a user has a valid license assigned, the boolean IsLicensed will be set to True.
2013-12-30 15-26-24

The ‘Licenses’ attribute contains “tenantname:LICENSESKU”, which in my case above is “mstlegacy:ENTERPRISEPACK” for an E3 license.
So, when assigning a license with PowerShell we need to know the SKUID of the particular license we are using.

We can also disable specific parts of a license, for example SharePoint when we assign the license. More details about ‘manual’ PowerShell assignment of licenses in Office 365 you’ll find here.

Solution

My script activates Office 365 users based on the AD attribute of your choise.
It requires you to populated the AD attribute with a string that identifies the license type for the particular user.
Default AD attribute used in the script is employeeType.

Supported license types with AD attributes as below (attribute to the left):
E1 – Office 365 for Enterprises E1
E3 – Office 365 for Enterprises E3
K1 – Deskless user without Office
E2 – Deskless user with Office
A1S – Office 365 for Education A1 (Students)
A2S – Office 365 for Education A2 (Students)
A3S – Office 365 for Education A3 (Students)
A1F – Office 365 for Education A1 (Faculty)
A2F – Office 365 for Education A2 (Faculty)
A3F – Office 365 for Education A3 (Faculty)
2014-01-01 15-31-22
In case the AD attribute Country is populated in your AD, it will automatically use that attribute to populate UsageLocation of the user in Office 365, otherwise it will default back to the parameter $DefaultCountry.

It will log all changes and errors to the logfile MSOL-UserActivation.log within the same folder you run the script.
Running the script
Prereqs:

Example – first time use:
As a preparation have to change the default value of $AdminUser parameter or use the parameter -AdminUser to an actual adminuser of your tenant.
On first use it’ll then ask you for the password and then store encrypted with DPAPI to a file in the same folder where you run the script. This so you can run without user interaction in the future.

.\ActivateMSOLUser.ps1 -AdminUser DirSync@mstlegacy.onmicrosoft.com

2013-12-30 16-31-16
(Hopefully you will type in the correct password… 🙂 )

After you’ve finished with the first time configuration, you are ready to actually start assigning licenses.
Example 1 – Activate all K1,K2 and E3 licenses with default AD attribute (employeeType)

.\ActivateMSOLUser.ps1 -AdminUser dirsync@mstlegacy.onmicrosoft.com -Licenses K1,K2,E3

2013-12-30 16-45-58
As seen above, 2 unlicensed users were found in Office 365, but only one of them had the required local AD attribute (employeeType in this case), set to ‘E3’.
I also go two errors since I didn’t have any K1 or K2 licenses in my tenant.

Example 2 – Activate all E3 licenses with custom AD attribute (msDS-cloudExtensionAttribute1) and MasterOnPremise

.\ActivateMSOLUser.ps1 -AdminUser dirsync@mstlegacy.onmicrosoft.com -Licenses E3 -LicenseAttribute msDS-cloudExtensionAttribute1 -MasterOnPremise

2013-12-30 16-57-28
In the above example we found one user to activate, but with the switch -MasterOnPremise we looked in to our local ad instead checking Office 365 for unlicensed users, and reported back to the attribute when the license was successfully assigned.
This can be useful if you for some reason have a lot of unlicensed users in Office 365 that you intend to keep that way.

Note: Since the -MasterOnPremise function writes back to your AD, the account that runs the script will in that case need write permissions to that AD attribute.

2013-12-30 17-03-59

Next Step
In order to make this fully automated, you will also need to schedule this as a task that runs (preferably) as often as your DirSync goes which by default is every 3 hours, an article on how to do that is here.

I’ve been running the script for a while and it works very well, of course some parts can be done more efficient. If you find any bugs or other issues, let me know!

The script can be downloaded from here, or cut’n’paste it from below…

Happy Licensing!
/Johan

ActivateMSOLUsers.ps1

<# .SYNOPSIS     The script automatically assigns licenses in Office 365 based on AD-attributes of your choice. .DESCRIPTION     Fetches your Office 365 tenant Account SKU's in order to assign licenses based on them.     Sets mandatory attribute UsageLocation for the user in Office 365 based on local AD attribute Country (or default)     If switch -MasterOnPremise has been used:     Assigns Office 365 licenses to the user based on an AD-attribute and reports back to the same attribute if a license was successfully assigned.     If not:     Looks after unlicensed users in Office365, checks if the unlicensed user has the right attribute in ad to be verified, otherwise not. .PARAMETER MasterOnPremise     Switch, If used, it  Assigns Office 365 licenses to the user based on an AD-attribute and reports back to the same attribute if a license was successfully assigned.     .PARAMETER Licenses     Array, defines the licenses used and to activate, specific set of licenses supported. "K1","K2","E1","E3","A1S","A2S","A3S","A1F","A2F","A3F" .PARAMETER LicenseAttribute     String, the attribute  used on premise to identify licenses .PARAMETER AdminUser     Adminuser in tenant .PARAMETER DefaultCountry     Defaultcountry for users if not defined in active directory              .NOTES     File Name: ActivateMSOLUsers.ps1     Author   : Johan Dahlbom, johan[at]dahlbom.eu     The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights.     #>
param(
[parameter(Mandatory=$false)]
[Switch]
$MasterOnPremise = $false,

[parameter(Mandatory=$false,HelpMessage="Please provide the SKU's you want to activate")]
[ValidateSet("K1","K2","E1","E3","A1S","A2S","A3S","A1F","A2F","A3F")]
[ValidateNotNullOrEmpty()]
[array]
$Licenses,

[parameter(Mandatory=$false)]
[string]
$LicenseAttribute = "employeeType",

[parameter(Mandatory=$false)]
[string]
$AdminUser = "admin@tenant.onmicrosoft.com",

[parameter(Mandatory=$false)]
[string]
$DefaultCountry = "SE"
)
#Define variables
$PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
$Logfile = ($PSScriptRoot + "\MSOL-UserActivation.log")
$TimeDate = Get-Date -Format "yyyy-MM-dd-HH:mm"
$SupportedSKUs = @{
                    "K1" = "DESKLESSPACK"
                    "K2" = "DESKLESSWOFFPACK"
                    "E1" = "STANDARDPACK"
                    "E3" = "ENTERPRISEPACK"
                    "A1S" = "STANDARDPACK_STUDENT"
                    "A2S" = "STANDARDWOFFPACK_STUDENT"
                    "A3S" = "ENTERPRISEPACK_STUDENT"
                    "A1F" = "STANDARDPACK_FACULTY"
                    "A2F" = "STANDARDWOFFPACK_FACULTY"
                    "A3F" = "ENTERPRISEPACK_FACULTY"

                    }

################################################
##### Functions

#Function to Import Modules with error handling
Function Import-MyModule
{
Param([string]$name)
    if(-not(Get-Module -name $name))
    {
        if(Get-Module -ListAvailable $name)
        {
            Import-Module -Name $name
            Write-Host "Imported module $name" -ForegroundColor Yellow
        }
        else
        {
            Throw "Module $name is not installed. Exiting..."
        }
    }
    else
    {
        Write-Host "Module $name is already loaded..." -ForegroundColor Yellow }
    }

#Function to log to file and write output to host
Function LogWrite
{
Param ([string]$Logstring)
Add-Content $Logfile -value $logstring -ErrorAction Stop
Write-Host $logstring
}
#Function to activate your users based on ad attribute
Function Activate-MsolUsers
{
Param([string]$SKU)

    begin {
        #Set counter to 0
        $i = 0
    }

        process {

            #Catch and log errors
            trap {
                $ErrorText = $_.ToString()
		        LogWrite "Error: $_"
                $error.Clear()
                Continue
            }

            #If the switch -MasterOnPremise has been used, start processing licenses from the AD-attribute

            if ($MasterOnPremise) {

		    $UsersToActivate = Get-ADUser -filter {$LicenseAttribute -eq $SKU} -Properties $LicenseAttribute,Country -ErrorAction Stop

                if ($UsersToActivate)
			    {
			    $NumUsers = ($UsersToActivate | Measure-Object).Count

			    LogWrite "Info: $NumUsers user(s) to activate with $SKU"
                foreach($user in $UsersToActivate) {

                          trap {
                                $ErrorText = $_.ToString()
		                        LogWrite "Error: $_"
                                $error.Clear()
                                Continue
                            }
                        $UPN = $user.userprincipalname
                        $Country = $user.Country
                        LogWrite "Info: Trying to assign licenses to: $UPN"
                                if (!($country)) {
                                    $Country = $DefaultCountry }

                        if ((Get-MsolUser -UserPrincipalName $UPN -ErrorAction Stop)) {

                                Set-MsolUser -UserPrincipalName $UPN -UsageLocation $country -Erroraction Stop
                                Set-MsolUserLicense -UserPrincipalName $UPN -AddLicenses $SKUID -Erroraction Stop
									#Verify License Assignment
									if (Get-MsolUser -UserPrincipalName $UPN | Where-Object {$_.IsLicensed -eq $true}) {
										Set-ADUser $user -Replace @{$LicenseAttribute=$SKU+' - Licensed at ' + $TimeDate}
										LogWrite "Info: $upn successfully licensed with $SKU"
                                        $i++;
									}
									else
									{
										LogWrite "Error: Failed to license $UPN with $SKU, please do further troubleshooting"

									}
                        }
				    }
			    }
            }
	#If no switch has been used, process users and licenses from MSOnline
            else {
			    $UsersToActivate = Get-MsolUser -UnlicensedUsersOnly -All
				    if ($Userstoactivate)
				    {
				    $NumUsers = $UsersToActivate.Count
				    LogWrite "Info: $NumUsers unlicensed user(s) in tenant: $($SKUID.ToLower().Split(':')[0]).onmicrosoft.com"
				    foreach ($user in $UsersToActivate) {
                                trap {
                                        $ErrorText = $_.ToString()
		                                LogWrite "Error: $_"
                                        $error.Clear()
                                        Continue
                                }

					        $UPN = $user.UserPrincipalName
					        $ADUser = Get-Aduser -Filter {userPrincipalName -eq $UPN} -Properties $LicenseAttribute,Country -ErrorAction Stop
					        $Country = $ADUser.Country
							    if (!($Country)) {
								$Country = $DefaultCountry
							    }
					        if ($ADUser.$LicenseAttribute -eq $SKU) {
						        LogWrite "Info: Trying to assign licenses to: $UPN"
						        Set-MsolUser -UserPrincipalName $UPN -UsageLocation $country -Erroraction Stop
						        Set-MsolUserLicense -UserPrincipalName $UPN -AddLicenses $SKUID -Erroraction Stop

						        #Verify License Assignment
						        if (Get-MsolUser -UserPrincipalName $UPN | Where-Object {$_.IsLicensed -eq $true}) {
							    LogWrite "Info: $upn successfully licensed with $SKU"
                                $i++;
						        }
						   else
						        {

                                LogWrite "Error: Failed to license $UPN with $SKU, please do further troubleshooting"

						        }
				        }
			        }
		        }
	        }
        }

    End{
    LogWrite "Info: $i user(s) was activated with $license ($SKUID)"
	}
}
################################################
#Import modules required for the script to run
Import-MyModule MsOnline
Import-MyModule ActiveDirectory

	#Start logging and check logfile access
	try
	{
		LogWrite -Logstring "**************************************************`r`nLicense activation job started at $timedate`r`n**************************************************"
	}
	catch
	{
		Throw "You don't have write permissions to $logfile, please start an elevated PowerShell prompt or change NTFS permissions"
	}

    #Connect to Azure Active Directory
	try
	{
		$PasswordFile = ($PSScriptRoot + "\$adminuser.txt")
		if (!(Test-Path  -Path $passwordfile))
			{
				Write-Host "You don't have an admin password assigned for $adminuser, please provide the password followed with enter below:" -Foregroundcolor Yellow
				Read-Host -assecurestring | convertfrom-securestring | out-file $passwordfile
			}
		$password = get-content $passwordfile | convertto-securestring -ErrorAction Stop
		$credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $adminuser,$password -ErrorAction Stop
		Connect-MsolService -credential $credentials -ErrorAction Stop
	}
	catch [system.exception]
	{
        $err = $_.Exception.Message
		LogWrite "Error: Could not Connect to Office 365, please check connection, username and password.`r`nError: $err"
        exit
	}

if (!$licenses) {
    LogWrite "Error: No licenses specified, please specify a supported license`r`nInfo: Supported licenses are: K1,K2,E1,E3,A1S,A2S,A3S,A1F,A2F,A3F!"
}
else
{

#Start processing license assignment
    foreach($license in $Licenses) {

        $SKUID = (Get-MsolAccountSku | Where-Object {$_.AccountSkuId -like "*:$($SupportedSKUs.Get_Item($license))"}).AccountSkuId

            if ($SKUID)
	        {
		        Activate-MsolUsers -SKU $license
	        }
	        else
	        {
		    LogWrite "Error: No $license licenses in your tenant!"
	        }
    }
}
LogWrite -Logstring "**************************************************"