Feb 22 2017
09:49 AM
- last edited on
Jan 14 2022
05:36 PM
by
TechCommunityAP
Feb 22 2017
09:49 AM
- last edited on
Jan 14 2022
05:36 PM
by
TechCommunityAP
This looks awesome - simplify licence management for Office 365, EMS, Dynamics 365 and more with the new group-based licensing preview in Azure AD:
Microsoft cloud services such as Office 365, Enterprise Mobility + Security, Dynamics CRM, and other similar products require licenses to be assigned to each user who needs access to these services. Until now, licenses could only be assigned at individual user level, which can male large-scale management difficult for our customers.
We have introduced a new capability of the Azure AD license management system: group-based licensing. It is now possible to assign one or more product licenses to a group. Azure AD will make sure that the licenses are assigned to all members of the group. Any new members joining the group will be assigned the appropriate licenses and when they leave the group those licenses will be removed. This eliminates the need for automating license management via PowerShell to reflect changes in the organization and departmental structure on a per-user basis.
Here is the documentation with the steps to get started - What is group-based licensing in Azure Active Directory?
Apr 11 2017 08:25 AM
Apr 11 2017 03:50 PM
Not a good idea as when you clear the membership GBL will trigger a remove of the license and then you would have to re-apply them and hope that your timing matches that of GBL updating the assignments in Office for example. You will likely get some very unpredictable results if you keep running this on your groups.
I understand that you are doing this as a simple version of dynamic groups which is an Azure AD Premium feature but you have to change the logic to not remove member unless he/she is really removed.
Brjann
Apr 11 2017 05:10 PM
Apr 12 2017 05:44 AM
Brent, we do something similar here, but we do delta changes to group membership using powershell, instead of a wipe and replace. It does rely on an extra step using MS Access or SQL Server to hold your combined AD/Azure data - for example, we have a scheduled task to powershell export the current Azure group listings/memberships and import into SQL Express. Another task to powershell export our local Active Directory info into same SQL Express. Then a query to find the new AD people, and another query to find the removed AD people. Export those 2 queries to a text file, and use those 2 to powershell the delta changes up to Azure. It sounds like a lot but once you get it built, it's very quick and easy to run, and it sounds like you're almost doing that now.
Apr 12 2017 07:51 AM
Jun 13 2017 11:07 AM
Jun 14 2017 05:45 AM
Would you be willing to share your PowerShell scripts, or the relevants parts with your personal info stripped out? I'm always looking for better/faster ways to do things, but I understand that some people may not want to provide that info due to potential security reasons.
Jun 14 2017 06:32 AM - edited Jun 14 2017 06:37 AM
Glad to share. Below is a sanitized version, the only thing you really have to do is set your AD domain (line 7), and then create your Groups as necessary.
May take a bit to disect the different scenarios I had to account for.
The main workhorse is the deltaSync function which adds and removes users as needed (instead of repopulating the license groups).
The getADGroupMembers function gets all users in an AD group and adds them to an array variable
What I am doing is basically building arrays of users:
I have one OU with Groups that our ID Administrators can update to account for specific scenarios.
Then I have another OU with Groups that are specifically for licenses (that will be used in AAD).
We are specifically applying licenses for E3's, E5's (with S4B phone), E5's (without S4B phone), Advanced Threat Protection (to E3 users), Project Online, Project Pro, Visio, PSTN Conferencing, EMS, Exchange Plan 2, and maybe one or two others.
Our AADConnect runs every 30 minutes, and this script runs every 30 minutes offset by 15 minutes from the AADConnect sync job.
$ScriptStart = (Get-Date) Add-Type -AssemblyName System.DirectoryServices.AccountManagement function getADGroupMembers($adGroupName){ $adGroupArray = @() $domain='' #Enter your AD domain here $pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Domain, $domain) $group2 = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($pc, [System.DirectoryServices.AccountManagement.IdentityType]::Name, $adGroupName) $group2.Members.GetEnumerator() | % { #Write-Host $_.DistinguishedName if($adGroupName -like "O365 License*"){ $adGroupArray += "$($_.DistinguishedName)" } else { if($_.DistinguishedName -notlike "*Disabled Objects*"){ $adGroupArray += "$($_.DistinguishedName)" } } } if($adGroupArray.Length -gt 0){ return $adGroupArray } else { return $null } } function checkMembership($user, $array){ return $array.contains($user) } function checkMembershipCount($checkGroup, $checkName){ $count = 0 foreach($checkGroupItem in $checkGroup){ if($checkGroupItem.contains($checkName)){ $count += 1 } } return $count } function removeArray($array1, $array2){ if($array2){ $array3 = @() foreach($item in $array1){ if(!$array2.Contains($item)){ $array3 += $item } } return $array3 } else { return $array1 } } function deltaSync($adGroupName, $replaceWith){ $replaceWith = $replaceWith | select -uniq Write-Host "`nProcessing Target Group:" $adGroupName -ForegroundColor Cyan $adGroupArray = getADGroupMembers -adGroupName "$adGroupName" if($replaceWith.Length -eq 0 -and $adGroupArray.Length -eq 0){ return $false } if($replaceWith.Length -eq 0 -and $adGroupArray.Length -ne 0){ Write-Host "Removing all users" Remove-ADGroupMember "$adGroupName" -Members $adGroupArray -Confirm:$false return $false } if($replaceWith.Length -ne 0 -and $adGroupArray.Length -eq 0){ Write-Host "Adding all users" Add-ADGroupMember "$adGroupName" -Members $replaceWith -Confirm:$false return $false } # Compare the differences between the two groups $arrayDiff = Compare-Object -ReferenceObject $adGroupArray -DifferenceObject $replaceWith # Iterate the differences and determine Adds / Removes $usersToAdd = @() $usersToRemove = @() foreach($arrayItem in $arrayDiff){ if($arrayItem.SideIndicator -eq "=>"){ Write-Host "Add to Array" $arrayItem.InputObject -ForegroundColor Yellow $usersToAdd += "$($arrayItem.InputObject)" } else { Write-Host "Remove from Group" $arrayItem.InputObject -ForegroundColor Red $usersToRemove += "$($arrayItem.InputObject)" } } # Add users to target Group if($usersToAdd.Length -gt 0){ Write-Host "`nAdd Users Now" -ForegroundColor Yellow Add-ADGroupMember "$adGroupName" -Members $usersToAdd -Confirm:$false } # Remove users from target Group if($usersToRemove.Length -gt 0){ Write-Host "`nRemove Users Now" -ForegroundColor Yellow Remove-ADGroupMember "$adGroupName" -Members $usersToRemove -Confirm:$false } return $true } # Define E5 Groups to Check $groups = getADGroupMembers -adGroupName "Groups with E5 Licenses (O365 Groups)" # Build array of Users that get E5's based on Group Membership $E5UserArray = @() foreach($group in $groups){ #$group | get-member $adGroup = Get-ADGroup $group #$zzz = Get-ADGroup $adGroup -Properties * #$zzz.DisplayName #Write-Host "Processing $($adGroup.DisplayName)" $members = getADGroupMembers -adGroupName "$($adGroup.Name)" foreach($member in $members){ #Write-Host " $member" $E5UserArray += "$($member)" } } $Users_S4BCloud = getADGroupMembers -adGroupName "Users with S4B Phone - Cloud" $Users_S4BOnPrem = getADGroupMembers -adGroupName "Users with S4B Phone - On Prem" $Devices_S4B = getADGroupMembers -adGroupName "Devices with S4B Conferencing" # Get all Users from AD $Users = Get-ADUser -Filter * -Properties userprincipalname,msRTCSIP-PrimaryUserAddress,Company,Created,displayName,employeeNumber,c,proxyAddresses,mail,sAMAccountType,userAccountControl,enabled $Users_E5 = @() $Users_E5_CloudPBX = @() $Users_E3 = @() $Users_EMS = @() $count = 0 foreach($user in $users){ if(($User.EmployeeNumber) -and ($User.DistinguishedName -like "*OU=Users*") -and ($User.DistinguishedName -notlike "*OU=_Disabled Objects*")){ $count += 1 if(checkMembership -array $E5UserArray -user "$user"){ if(checkMembership -array $Users_S4BCloud -user "$user"){ $Users_E5_CloudPBX += "$($user.DistinguishedName)" } else { $Users_E5 += "$($user.DistinguishedName)" } } else { $Users_E3 += "$($user.DistinguishedName)" } $Users_EMS += "$($user.DistinguishedName)" } } Write-Host "`nFound $count Users`n" # Build array of Users that will receive no license Write-Host "`n****`nExclusion List `n****" -ForegroundColor Green $ExclusionList = getADGroupMembers -adGroupName "Users with No License" Write-Host $ExclusionList Write-Host "`n****`nDevices with S4B Conferencing `n****" -ForegroundColor Green $Devices_S4B = getADGroupMembers -adGroupName "Devices with S4B Conferencing" deltaSync -adGroup "O365 License Users with E5 (Devices)" -replaceWith $Devices_S4B Write-Host "`n****`nUsers with Visio `n****" -ForegroundColor Green $Users_Visio = getADGroupMembers -adGroupName "Users with Visio" $Users_Visio = removeArray -array1 $Users_Visio -array2 $ExclusionList deltaSync -adGroup "O365 License Users with Visio" -replaceWith $Users_Visio Write-Host "`n****`nUsers and Devices with Exchange Only `n****" -ForegroundColor Green $Users_ExchangeOnly = getADGroupMembers -adGroupName "Service Accounts with Email Only" $Users_VM = getADGroupMembers -adGroupName "Devices with Voicemail" $Users_ExchangeOnly = $Users_ExchangeOnly + $Users_VM $Users_ExchangeOnly = removeArray -array1 $Users_ExchangeOnly -array2 $ExclusionList deltaSync -adGroup "O365 License Users with Exchange Only" -replaceWith $Users_ExchangeOnly Write-Host "`n****`nE5 (Regular) `n****" -ForegroundColor Green $Users_E5 = removeArray -array1 $Users_E5 -array2 $ExclusionList deltaSync -adGroup "O365 License Users with E5 (Regular)" -replaceWith $Users_E5 Write-Host "`n****`nE5 (Phone) `n****" -ForegroundColor Green $Users_E5_CloudPBX = $Users_E5_CloudPBX $Users_E5_CloudPBX = removeArray -array1 $Users_E5_CloudPBX -array2 $ExclusionList deltaSync -adGroup "O365 License Users with E5 (Phone)" -replaceWith $Users_E5_CloudPBX Write-Host "`n****`nE3 (Temporary) `n****" -ForegroundColor Green $Users_E3_Temporary = getADGroupMembers -adGroupName "Users with E3 Limited Licenses" deltaSync -adGroup "O365 License Users with E3 (Temporary)" -replaceWith $Users_E3_Temporary Write-Host "`n****`nE3 (Service Accounts) `n****" -ForegroundColor Green $Users_E3_ServiceAccounts = getADGroupMembers -adGroupName "Service Accounts with E3 Licenses" deltaSync -adGroup "O365 License Users with E3 (Service Accounts)" -replaceWith $Users_E3_ServiceAccounts $Users_E3_Manual = getADGroupMembers -adGroupName "Users (Non-Buckman) with E3 Licenses" $Users_E3 = $Users_E3 + $Users_E3_Manual $Users_E3 = removeArray -array1 $Users_E3 -array2 $ExclusionList $Users_E3 = removeArray -array1 $Users_E3 -array2 $Users_E3_Temporary Write-Host "`n****`nE3 / ATP `n****" -ForegroundColor Green deltaSync -adGroup "O365 License Users with E3" -replaceWith $Users_E3 Write-Host "`n****`nATP `n****" -ForegroundColor Green $Users_ATP = $Users_E3 + $Users_E3_Temporary deltaSync -adGroup "O365 License Users with ATP" -replaceWith $Users_ATP Write-Host "`n****`nEMS `n****" -ForegroundColor Green $Users_EMS = $Users_E3 + $Users_E5_CloudPBX + $Users_E5 $Users_EMS = removeArray -array1 $Users_EMS -array2 $Devices_S4B $Users_EMS = removeArray -array1 $Users_EMS -array2 $ExclusionList deltaSync -adGroup "O365 License Users with EMS" -replaceWith $Users_EMS Write-Host "`n****`nProject Pro `n****" -ForegroundColor Green $Users_ProjectPro = getADGroupMembers -adGroupName "Users with Project Pro" deltaSync -adGroup "O365 License Users with Project Pro" -replaceWith $Users_ProjectPro Write-Host "`n****`nProject Online `n****" -ForegroundColor Green $Users_ProjectOnline = getADGroupMembers -adGroupName "Users with Project Online" deltaSync -adGroup "O365 License Users with Project Online" -replaceWith $Users_ProjectOnline Write-Host "`n****`nUsers with PSTN Conferencing `n****" -ForegroundColor Green $Users_PSTN = getADGroupMembers -adGroupName "Users with PSTN Conferencing" $Users_PSTN = removeArray -array1 $Users_PSTN -array2 $ExclusionList deltaSync -adGroup "O365 License Users with PSTN Conferencing" -replaceWith $Users_PSTN $ALL_E5_1 = getADGroupMembers -adGroupName "O365 License Users with E5 (Phone)" $ALL_E5_2 = getADGroupMembers -adGroupName "O365 License Users with E5 (Regular)" $ALL_E5 = $ALL_E5_2 + $ALL_E5_1 $ALL_E3 = getADGroupMembers -adGroupName "O365 License Users with E3" $Users_PSTN_E3 = removeArray -array1 $Users_PSTN -array2 $ALL_E5 $Users_PSTN_E3 = removeArray -array1 $Users_PSTN_E3 -array2 $ExclusionList deltaSync -adGroup "O365 License Users with PSTN Conferencing (E3)" -replaceWith $Users_PSTN_E3 $Users_PSTN_E5 = removeArray -array1 $Users_PSTN -array2 $ALL_E3 $Users_PSTN_E5 = removeArray -array1 $Users_PSTN_E5 -array2 $ExclusionList deltaSync -adGroup "O365 License Users with PSTN Conferencing (E5)" -replaceWith $Users_PSTN_E5 $ScriptEnd = (Get-Date) $RunTime = New-Timespan -Start $ScriptStart -End $ScriptEnd "`nElapsed Time: {0}:{1}:{2}" -f $RunTime.Hours,$Runtime.Minutes,$RunTime.Seconds
Jun 14 2017 06:58 AM
Sep 22 2017 05:10 AM
Is it also possible to get an export from for example all the users with the E3 license?
Oct 30 2017 01:55 AM
Hello,
as I understand it is still in public preview. So my question, do you have a timeline when group-based license management will be GA? And how quick will it be available (GA) in the German Cloud?
Regards Thomas
Jan 10 2018 08:04 AM
Jan 15 2018 08:32 AM
I concur, when is this going GA?
May 01 2018 02:38 PM
We have just changed our licensing to Office 365 E3 to Office 365 E5.
And Kiosk to F1 licensing is there any reason not to use group based licensing?
This would help flip all my users properly and also remove the services that we didn't want to go live quite yet.
Jun 01 2018 06:50 AM
When is this going GA?
Jun 11 2018 12:30 PM
We found that the “Azure AD group-based license management” (in public preview) is not currently smart enough to recognize a single user license between E3 and E5. It “double dips”, so a user who has an E5 license (direct or inherited) and an E3 license (direct or inherited) takes up two license; one E3 and one E5. This scenario did not create any warning or alert from the system. Is there a UserVoice style area to communicate with folks evaluating what will be GA?
Jun 11 2018 05:35 PM
@Deleted, here's where you could add in to Azure AD ideas on UserVoice: https://feedback.azure.com/forums/169401-azure-active-directory
There's some Group Based Licensing requests in there already.
Jun 12 2018 02:15 AM
The problem here isn't the AD Group based implementation. it honours whatever licensing rules are applied by the platform. Therefore if you can apply the two license templates in the Office 365 UI, then you can do the same in the Group Based templates.
In this instance, it's a viable solution to apply elements from both E3 and E5 to a single user (Note I said viable.. not sensible!). You'll find that you can tick both E3 and E5 in the Office 365 UI. If you tried to do the same using and F1 and E3 or F1 and E5 it would throw an error in the UI and also in the Group Based licensing interfaces.
Jun 14 2018 10:36 AM
@Paul Hunt - Cimares I like your quantifier "(Note I said viable.. not sensible!)"
The problem, of course is, if a thing is not sensible, someone will still try to do it at the expense of others around them.
I do understand what you are saying though.
We - large scale corporate implementation - will need a reasonable way of reporting on it or preventing it.
Pulling the data per user per license per service down from the tenant via PowerShell then republishing it via PowerBI is also viable but not sensible. ;)
My tests of the group-based license management is going well. Its value is clear especially given Microsoft's gross propensity to force service plans out as "Enabled by default". (another viable not sensible example)