Issue

For many organizations, different classes of users will get different Office 365 licenses and access to different services within each license. For large and medium organizations, object management software is normally the best option for managing user licensing in Office 365. Microsoft Identity Manager (MIM) is an application that can maintain Office 365 account licensing. Two good articles outlining the process can be found by following the links below.

https://blog.kloud.com.au/2016/08/26/office365-licensing-management-agent-for-microsoft-identity-manager/

https://bobbradley1967.wordpress.com/2016/06/27/managing-office-365-licenses-with-mim2016-and-azman-part-2/

Solution

For organizations not implementing object management software or that need a solution until object management software is in place, we have written a script that will assign Office 365 licenses based on AD group membership.

When configuring the licensing script to work within your organization it is important to put the most restrictive AD group in the script first. By putting the most restrictive AD group first, if a user is a member of multiple security groups, that user would be assigned less restrictive licenses (more information can be found in the Test Results).

The following are requirements for script execution:

  • The path C:\temp\services\logs, needs to be created on the computer running the script
  • The first time running the script it will ask for an admin password. Once the password is provided it will store the password in a secure file
  • The user name needs to be changed to the admin account on line 3
  • Change the licenses information on lines 6 & 7
  • If we want to disable any other services, other than Yammer and Exchange, we would need to add them to line 10
  • To change groups, edit lines 20 & 21
  • The script will create a log file under C:\temp\services\Logs
  • The computer \ server must have the AD module installed

Results

Two Groups created within Active Directory. Each group only has one member, Christopher Crandall.

Since Christopher is a member of two groups, we want to place the most restrictive group in the script first. In our scripts, the E3-EMM-No-Yammer-Exchange group would be listed first in the script. This ensures that Yammer and Exchange will not be disabled for Christopher’s account.

Christopher’s account currently doesn’t have licenses assigned to his account within Office 365

Once the script is finished Christopher will have E3 and all the services within E3.

Script

Lines 3,  5, 6, 9, 16, & 17 need to changed to get the script working.

$logfile = ("C:\temp\services\Logs\Services.log")
$PasswordFile = "C:\temp\Services\cred.txt"
$AdminAccount = "admin account UPN"
#E3 and EMS
$E3 = "CB5Lab:ENTERPRISEPACK"
$EMM = "CB5Lab:EMS"
$UsageLocation = 'US'
#E3 - No Exchange and Yammer
$DisableServices = "YAMMER_ENTERPRISE", "EXCHANGE_S_ENTERPRISE"
$PolicyE3NoExchangeYammer =  New-MsolLicenseOptions -AccountSkuId $E3 -DisabledPlans $DisableServices
#E3 - All services
$PolicyE3 =  New-MsolLicenseOptions -AccountSkuId $E3 -DisabledPlans $Null
#EMM - All services
$PolicyEMM = New-MsolLicenseOptions -AccountSkuId $EMM -DisabledPlans $Null
#Groups
$Group1 = "E3-Emm-No-Yammer-Exchange"
$Group2 = "E3-EMM"
#GroupManagement
$Group1MemberShip = Get-ADGroupMember -identity $Group1 -Recursive | select SamAccountName
$Group2MemberShip = Get-ADGroupMember -identity $Group2 -Recursive | select SamAccountName
function log{
param (
[String]$text,
[Switch]$fout
)
ac $logfile $text
if($showConsoleOutput){
if($fout){
Write-Host $text -ForegroundColor Red
}else{
Write-Host $text -ForegroundColor Green
}
}
}
log -text "-----$(Get-Date) Services - $($env:USERNAME) on $($env:COMPUTERNAME) starting-----"
$PasswordFileCheck = Test-Path $PasswordFile
If($PasswordFileCheck -eq $False){
Read-Host -Prompt "<text>" -AsSecureString | ConvertFrom-SecureString | Out-File "C:\temp\services\cred.txt"
log -text "Created a password file under C:\temp\services"
}
Else{
log -text "Password file already created under C:\temp\services"
}
$Pass = Get-Content $PasswordFile | ConvertTo-SecureString
$Cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $AdminAccount, $Pass
Import-Module MSOnline
$Connect = Connect-MsolService -Credential $cred -ErrorAction SilentlyContinue -ErrorVariable ProcessError | ft '1' -HideTableHeaders
If ($ProcessError) {
log -text "------ Didn't Connect to Office 365 services"
}
Else{
log -text "Connect to Office 365 Services"
}
Foreach ($Member in $Group1MemberShip){
$UPN = Get-ADUser -Identity $Member.SamAccountName | select UserPrincipalName
Foreach ($User in $UPN){
$strUser = $user.UserPrincipalName | Out-String
$strUser = $strUser.trim()
#Write-host "This is the user account that will be changed $struser"
Try{
Set-MsolUser -UserPrincipalName $UPN.UserPrincipalName -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $EMM -LicenseOptions $PolicyEMM -ErrorAction Stop
log -text "User $strUser ------ License $EMM"
}
Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyEMM
log -text "User $strUser ------ License Option $EMM"
}
Try{
Set-MsolUser -UserPrincipalName $UPN.UserPrincipalName -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $E3 -LicenseOptions $PolicyE3NoExchangeYammer -ErrorAction Stop
log -text "User $strUser ------ License $E3 ------- License Option $DisableServices"
}
Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyE3NoExchangeYammer
log -text "User $strUser ------ License Option $DisableServices"
}
}
}
Foreach ($Member in $Group2MemberShip){
$UPN = Get-ADUser -Identity $Member.SamAccountName | select UserPrincipalName
Foreach ($User in $UPN){
$strUser = $user.UserPrincipalName | Out-String
$strUser = $strUser.trim()
#Write-host "This is the user account that will be changed $struser"
Try{
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $EMM -LicenseOptions $PolicyEMM -ErrorAction Stop
log -text "User $strUser ------ License $EMM"
}
Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyEMM
log -text "User $strUser ------ License Option $EMM"
}
Try{
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $E3 -LicenseOptions $PolicyE3 -ErrorAction Stop
log -text "User $strUser ------ License $E3 ------- License Option $DisableServices"
}
 Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyE3
log -text "User $strUser ------ License Option $DisableServices"
}
}

 

}

Secondary Option

Another request we have gotten is described here. After the user is assigned Office 365 permissions, remove the user from the AD group. Using this method would ensure the user would not be in multiple AD groups that assign permissions. The user would be added to an AD group, the licensing script would run, the user would be assigned Office 365 licenses, and the user would be removed from the AD group. The secondary script can be found below.

Added lines 104 & 105

Secondary Script

$logfile = ("C:\temp\services\Logs\Services.log")
$PasswordFile =  "C:\temp\Services\cred.txt"
$AdminAccount = "Admin Account"
#E3 and EMS
$E3 = "CB5Lab:ENTERPRISEPACK"
$EMM = "CB5Lab:EMS"
$UsageLocation = 'US'
#E3 - No Exchange and Yammer
$DisableServices = "YAMMER_ENTERPRISE", "EXCHANGE_S_ENTERPRISE"
$PolicyE3NoExchangeYammer =  New-MsolLicenseOptions -AccountSkuId $E3 -DisabledPlans $DisableServices
#E3 - All services
$PolicyE3 =  New-MsolLicenseOptions -AccountSkuId $E3 -DisabledPlans $Null
#EMM - All services
$PolicyEMM = New-MsolLicenseOptions -AccountSkuId $EMM -DisabledPlans $Null
#Groups
$Group1 = "E3-Emm-No-Yammer-Exchange"
$Group2 = "E3-EMM"
#GroupManagement
$Group1MemberShip = Get-ADGroupMember -identity $Group1 -Recursive | select SamAccountName
$Group2MemberShip = Get-ADGroupMember -identity $Group2 -Recursive | select SamAccountName
function log{
param (
[String]$text,
[Switch]$fout
)
ac $logfile $text
if($showConsoleOutput){
if($fout){
Write-Host $text -ForegroundColor Red
}else{
Write-Host $text -ForegroundColor Green
}
}
}
log -text "-----$(Get-Date) Services - $($env:USERNAME) on $($env:COMPUTERNAME) starting-----"
$PasswordFileCheck = Test-Path $PasswordFile
If($PasswordFileCheck -eq $False){
Read-Host -Prompt "<text>" -AsSecureString | ConvertFrom-SecureString | Out-File "C:\temp\services\cred.txt"
log -text "Created a password file under C:\temp\services"
}
Else{
log -text "Password file already created under C:\temp\services"
}
$Pass = Get-Content $PasswordFile | ConvertTo-SecureString
$Cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $AdminAccount, $Pass
Import-Module MSOnline
$Connect = Connect-MsolService -Credential $cred -ErrorAction SilentlyContinue -ErrorVariable ProcessError | ft '1' -HideTableHeaders
If ($ProcessError) {
log -text "------ Didn't Connect to Office 365 services"
}
Else{
log -text "Connect to Office 365 Services"
}
Foreach ($Member in $Group1MemberShip){
$UPN = Get-ADUser -Identity $Member.SamAccountName | select UserPrincipalName
Foreach ($User in $UPN){
$strUser = $user.UserPrincipalName | Out-String
$strUser = $strUser.trim()
#Write-host "This is the user account that will be changed $struser"
Try{
Set-MsolUser -UserPrincipalName $UPN.UserPrincipalName -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $EMM -LicenseOptions $PolicyEMM -ErrorAction Stop
log -text "User $strUser ------ License $EMM"
}
Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyEMM
log -text "User $strUser ------ License Option $EMM"
}
Try{
Set-MsolUser -UserPrincipalName $UPN.UserPrincipalName -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $E3 -LicenseOptions $PolicyE3NoExchangeYammer -ErrorAction Stop
log -text "User $strUser ------ License $E3 ------- License Option $DisableServices"
}
Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyE3NoExchangeYammer
log -text "User $strUser ------ License Option $DisableServices"
}
}
Remove-ADGroupMember -Identity $Group1 -Members strUser -Confirm:$False
log -text "User $Member.SamAccountName ------was removed from group $Group1"
}
Foreach ($Member in $Group2MemberShip){
$UPN = Get-ADUser -Identity $Member.SamAccountName | select UserPrincipalName
Foreach ($User in $UPN){
$strUser = $user.UserPrincipalName | Out-String
$strUser = $strUser.trim()
#Write-host "This is the user account that will be changed $struser"
Try{
Set-MsolUser -UserPrincipalName $UPN.UserPrincipalName -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $EMM -LicenseOptions $PolicyEMM -ErrorAction Stop
log -text "User $strUser ------ License $EMM"
}
Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyEMM
log -text "User $strUser ------ License Option $EMM"
}
Try{
Set-MsolUser -UserPrincipalName $UPN.UserPrincipalName -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $E3 -LicenseOptions $PolicyE3 -ErrorAction Stop
log -text "User $strUser ------ License $E3 ------- License Option $DisableServices"
}
Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyE3
log -text "User $strUser ------ License Option $DisableServices"
}
}
Remove-ADGroupMember -Identity $Group2 -Members $Member.SamAccountName -Confirm:$False
log -text "User strUser ------was removed from group $Group2"

}

Third Option

The third request we have received concerns using Office 365 groups to assign Office 365 licensing. To accomplish this task we added lines  62 – 70.

Third Script

$logfile = ("C:\temp\services\Logs\Services.log")
$PasswordFile =  "C:\temp\Services\cred.txt"
$AdminAccount = "Admin Account"
#E3 and EMS
$E3 = "CB5Lab:ENTERPRISEPACK"
$EMM = "CB5Lab:EMS"
$UsageLocation = 'US'
#E3 - No Exchange and Yammer
$DisableServices = "YAMMER_ENTERPRISE", "EXCHANGE_S_ENTERPRISE"
$PolicyE3NoExchangeYammer =  New-MsolLicenseOptions -AccountSkuId $E3 -DisabledPlans $DisableServices
#E3 - All services
$PolicyE3 =  New-MsolLicenseOptions -AccountSkuId $E3 -DisabledPlans $Null
#EMM - All services
$PolicyEMM = New-MsolLicenseOptions -AccountSkuId $EMM -DisabledPlans $Null
#Groups
$Group1 = "E3-Emm-No-Yammer-Exchange"
$Group2 = "E3-EMM"
function log{
param (
[String]$text,
[Switch]$fout
)
ac $logfile $text
if($showConsoleOutput){
if($fout){
Write-Host $text -ForegroundColor Red
}else{
Write-Host $text -ForegroundColor Green
}
}
}
log -text "-----$(Get-Date) Services - $($env:USERNAME) on $($env:COMPUTERNAME) starting-----"
$PasswordFileCheck = Test-Path $PasswordFile
If($PasswordFileCheck -eq $False){
Read-Host -Prompt "<text>" -AsSecureString | ConvertFrom-SecureString | Out-File "C:\temp\services\cred.txt"
log -text "Created a password file under C:\temp\services"
}
Else{
log -text "Password file already created under C:\temp\services"
}
$Pass = Get-Content $PasswordFile | ConvertTo-SecureString
$Cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $AdminAccount, $Pass
Import-Module MSOnline
$Connect = Connect-MsolService -Credential $cred -ErrorAction SilentlyContinue -ErrorVariable ProcessError | ft '1' -HideTableHeaders
If ($ProcessError) {
log -text "------ Didn't Connect to Office 365 services"
}
Else{
log -text "Connect to Office 365 Services"
}
#GroupManagement
# Testing GROUP1Membership = get-aduser a-mariondg| select Samaccountname
$Group1ObjectID = Get-MsolGroup -SearchString $Group1 | Select ObjectId
$Group2ObjectID = Get-MsolGroup -SearchString $Group2 | Select ObjectId
#$Group3MemberShip = Get-ADGroupMember -identity $Group3 -Recursive | select SamAccountName
$Group1MemberShip = Get-MsolGroupMember -GroupObjectId $Group1ObjectID.ObjectID
$Group2MemberShip = Get-MsolGroupMember -GroupObjectId $Group2ObjectID.ObjectID
Foreach ($Member in $Group1MemberShip){
$UPN = Get-MsolUser -ObjectID $Member.objectID | select UserPrincipalName
Foreach ($User in $UPN){
$strUser = $user.UserPrincipalName | Out-String
$strUser = $strUser.trim()
#Write-host "This is the user account that will be changed $struser"
Try{
Set-MsolUser -UserPrincipalName $UPN.UserPrincipalName -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $E3 -LicenseOptions $PolicyE3NoExchangeYammer -ErrorAction Stop
log -text "User $strUser ------ License $E3 ------- License Option $DisableServices"
}
Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyE3NoExchangeYammer
log -text "User $strUser ------ License Option $DisableServices"
}
}
}
Foreach ($Member in $Group2MemberShip){
$UPN = Get-MsolUser -ObjectID $Member.objectID | select UserPrincipalName
Foreach ($User in $UPN){
$strUser = $user.UserPrincipalName | Out-String
$strUser = $strUser.trim()
#Write-host "This is the user account that will be changed $struser"
Try{
Set-MsolUser -UserPrincipalName $UPN.UserPrincipalName -UsageLocation $UsageLocation -ErrorAction Stop -WarningAction Stop
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $EMM -LicenseOptions $PolicyEMM -ErrorAction Stop
log -text "User $strUser ------ License $EMM"
}
Catch {
Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $PolicyEMM
log -text "User $strUser ------ License Option $EMM"
}
}
}