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
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.
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
Amazing work, thank you! How would I combine the “Assign individual parts” script with the advanced script that removes licenses?
Hi Jim,
Sorry for the late reply. It is of course possible, but would require you to export a list of all users including individual licenses and compare them with the Groups etc. So a bit complicated, and therefore I am not sure if I will publish a full version with the 2 combined.
Let me know if you have any other questions!
/Johan
Excellent work! The script runs perfectly.
My question is how do I add a plan after the fact? Since the script looks for unlicensed users and they are already licensed it won’t attempt to add plans?
Hi Jim,
Thanks for the feedback!
I’ll have a look into how to make that part more efficient.
/Johan
Pingback: Office 365: Assign licenses based on groups using PowerShell | Tailspintoys – 365lab.net
Hi Johan,
first of all thank you very much for your blog.
There are many amazing information.
I have spent a lot time to try modify your code but I’m not good coder.
I want create modifications
– enable some options of E3 according to group membership
– enable multiple SKU
example: user is member of groups “O365-E3-OfficeProPlus”, “O365-E3-Lync”, “O365-E3-Sharepoint” and “O365-Visio ”
and he will get only some options of E3SKU + VisioSKU
Could you try modify your script or advise me how to modify it?
Hi Richard,
Thanks for reading. I’ll see what I can do to help you. Will come back to you this weekend.
/Johan
Hi Johan,
Thanks for putting together these scripts. I have been testing this script and it works well, but as the others mentioned, it only applies to unlicensed users. If I move a user from one group to another, it doesn’t updated the assignment.
If there is a way to combine the Enabled Plans functionality you have in this script with the change/update functionality in your Advanced version, I think that would solve some riddles.
Thanks!
-Rob
Hi,
Thanks for Reading. I am currently working hard on a version to solve just that.
I’ll keep you posted!
/Johan
HI Johan, do you have any thoughts\update examples from the above requests regarding either user is a member of multiple security groups for the different services or moving a user between security groups that have different services licensed? (examples listed by Richard and Rob above).
Thanks
-Carl
Hi Johan, Great job with those scripts, THANKS!!!
As people has commented, they work great when users are unlicensed, but not if the users already have a license.
I seen that you were working on that and I was wondering if you have any update. That will be awesome.
Thanks
Hi Carlos,
Thanks for reading. Unfortunately I have been busy with lots of projects and have not had the time to publish this. I guess you have looked in to the script that adds/removes licenses that actually does this (but not with individual serviceparts).
However – I will do my best to give you guys an example on how to make this possible with individual serviceparts as soon as possible.
/Johan
Thanks for replying 🙂
I was looking at this article :Office 365: Assign individual parts of licenses based on groups using PowerShell: 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.
https://365lab.net/2014/12/17/office-365-assign-individual-parts-of-licenses-based-on-groups-using-powershell/#comment-5256
Basically I just need to update (to add) part of licenses to a group in which users have already something assigned.
If you can point me to some direction, that will be great.
Thanks for everything.
Hi,
If you check row 58, and remove “| Where-Object {$_.IsLicensed -eq $false}”, you will go through all users in the group, even if they already have licenses. That should work in your case. What would improve it even further is to put in an if statement in the foreach loop to check if the specific license/servicepart is present on the user. I will look in to a way to do it more efficient, but the above should solve your problem 🙂
I’ve tried that, but I get this error: “WARNING: Error when licensing User4@domain
Unable to assign this license because it is invalid. Use the Get-MsolAccountSku cmdlet to retrieve a list of valid licenses.”
If I remove the license for the user, the script works
OK, then I might need to have a look at it for myself before giving any further assistance.
Hi Carlos,
I have a version ready on 15 minutes. Are u ready to try it out or have you already solved the issue?
/Johan
I’m ready,. bring it on!..
I thought I answered yesterday but it seems it didn’t go through.
Thanks for all your help. So,, What do I do?
I would be interesting in obtaining your latest version of this script that Carlos mentioned about adding part of licenses to a group in which users have already something assigned.
Gary
Hello Johan,
do you already have the new version ready to test?
Thanks
VJ
I will make sure to publish it later today or tomorrow. 🙂 Busy days…
Thanks Johan.. We all exited and waiting 😀
I can hardly wait 🙂 Thanks
Hi Johan, do we have any update :$. I know you’re busy and I don’t want to bother you too much.
Hi,
Short status update. Working on it today. it was a bit more complex than I first realized…
/J
Carlos! And other readers. We have a new version available for testing at http://pastebin.com/JHT170rm. Please test it and get back to me with feedback. When I’ve tested it and are sure that things are working as intended, I’ll make sure to update the post as well.
/Johan
AWESOME!!!! it works perfectly !!! Thanks a lot. I really appreciate it!.
You rock!
Hi Johan, It’s me again 🙂
I wrote you on the other post: https://365lab.net/2014/04/22/office-365-assign-licenses-based-on-groups-using-powershell-advanced-version/
I wasn’t sure in which to write.
I just need to add the change/remove part from the other script to this one.. Which one should I take and include the other part?
Thanks
Hopefully soon!
Gary,
I’ve now created a “beta” version of this new one available at http://pastebin.com/JHT170rm. Please try it out and come back with feedback.
/Johan
Works as intended! Great job man!
One question that’s probably independent of the scope of this script, down in the script you have a section stating:
#Get all unlicensed group members – needs to be changed if a user should be able to have more than one license
What would need to be changed if I wanted to apply a second license that didn’t need any modifications?
Cheers
Johan,
I have ran your beta version of the script, and works as I wanted it. Able to apply 2 licenses (tenant:STANDARDWOFFPACK_STUDENT and tenant:OFFICESUBSCRIPTION_STUDENT) to users.
Thank you
Great work!
Happy to hear that! 🙂
Hi Johan,
i works awesome.
Any Idea with the Script for deactivate the “Enabled Plan” when i removed the User from the AD Group ?
We will control all Modules over the AD Groups.
In the another Script of this site, we can Only Control the complete Licence Plan
Excellent script.
I did however find an issue when the tenant had multiple SKU:s with in my case the MCOSTANDARD license available. Even if i had given the user a MCOSTANDARD licensen from the SKU i wanted, then the script failed to see it and tried to reapply a MCOSTANDARD license again.
I think i have solved it by replacing this line which found MCOSTANDARD from two SKU:s:
with this line which filters for the specified SKU:
On the other hand, this now returns an “error” if the MCOSTANDARD license has been given to the user from another SKU…
Gary, Thanks for the script. I have one question, my script was running fine for months but now I am getting this error “At C:\Users\Administrator\Desktop\scripts\o365userlicense.ps1:51 char:61
+ DisabledPlans = (Compare-Object -ReferenceObject <<<< $AccountSK
U.ServiceStatus.ServicePlan.ServiceName -DifferenceObject $EnabledPlans).InputO
bject
+ CategoryInfo : InvalidData: (:) [Compare-Object], ParameterBind
ingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,M
icrosoft.PowerShell.Commands.CompareObjectCommand
New-MsolLicenseOptions : A positional parameter cannot be found that accepts ar
gument '$null'.
My LicenseSKU is 'Tenant:STANDARDWOFFPACK_IW_FACULTy
Any help would be appreciated.
I love the beta script, did you ever do aversion which removes the licence when they are not in the group?
Hi Johan,
What needs to be changed here?
#Get all unlicensed group members – needs to be changed if a user should be able to have more than one license
Hi Johan,
I Have the same question pretty much. For example, if the user has an EMS license assigned to him previously (a different AccountSkuID) the script doesn’t add the Office365 license to the user. It simply ignores adding the licens since it all ready has an EMS license. What modifications do we need to do to get the script to work in this scenario?
Hey Johan,
Just in case, I’m referring to your new script (which is working great) not your older one:
http://pastebin.com/JHT170rm
#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 | Select-Object EmailAddress,@{Name=”Licenses”;Expression={(Get-MsolUser -UserPrincipalName $_.EmailAddress).Licenses }} | ForEach-Object -Process {
Stellar Effort! Thank you!!
Hi Johan,
Thank you for the scripts. They have been very helpful!
One issue we’ve noticed intermittently is the “Get-MsolGroup -All | Where-Object {$_.DisplayName -eq $GroupName}” method call sometimes does not return your group. It just silently returns an empty object. We’ve seen this happen 3 times in the past year, which works out to 3 times in ~5000 “Get-MsolGroup -All | Where-Object {$_.DisplayName -eq $GroupName}” calls. Not sure if this is an issue with Azure or our connection to Azure… In any case, we have adjusted our script to handle empty results from the “Get-MsolGroup -All | Where-Object {$_.DisplayName -eq $GroupName}” call. We essentially stop the script if the group is ever not found.
Hi,
I have later after this script was first developed changed the approach to “hard code” the guid of the group instead, to get rid of the issues with not finding the group. Look in to the Azure Automation post for that.
/Johan
the first script works with nested group members. Why does the second script for just assigning certain services not work for nested. It seems that you took that part out. Do you have a version that assign individual parts of licenses to nested groups.