UPDATE: If you are reading this in 2023, be advised that Microsoft has since deprecated the cmdlets used in the sample below. Instead, use the Graph SDK for PowerShell: Remove all Office 365 licenses for a group of users from CSV file via Graph – Blog (michev.info)
A recent question over at the Spiceworks community asked for a PowerShell sample that will go over a list of Office 365 users imported via CSV file and remove all licenses for each user. Since this is a question I’ve seen asked previously, I decided to write a quick blog post about it and add some additional notes besides the actual code.
The first step is to make sure we have a proper input file. You can easily prepare such by using the Get-MsolUser cmdlet and filtering out users based on specific criteria, or you can just populate it manually via Excel. The important thing is that you have at least one column that designates users unambiguously. The UserPrincipalName or ObjectId properties should do. You can use other properties as necessary, but make sure to adjust the code below to account for that, as it expects to see a column named UserPrincipalName in the input CSV file.
Once we have the list of users, the task of removing licenses is a simple one. The only tricky part is that we actually need to have a list of licenses to remove, as there is no -RemoveAllLicenses switch or similar. Thus, for each user we will first run the Get-MsolUser cmdlet and gather the list of currently assigned SKUs and store them in the $SKUs variable. If said variable is empty, say because the user has no licenses assigned or no matching user was found, we skip to the next user. Then, for each individual license we can go ahead and run the Set-MsolUserLicense cmdlet.
One last remark is due here – licenses can also be assigned by using the group-based licensing feature. If that’s the case, using the Set-MsolUserLicense cmdlet will throw an error, so we can add a simple check in the script to avoid that. Instead, you should use the Azure AD blade in the Azure portal to adjust the group-based license.
Without further ado, here’s the code that does the trick. Make sure to update it to reflect the path to the CSV file and make sure that the CSV file has a column named UserPrincipalName (or adjust that in the code below):
$users = Import-Csv .\Users-to-disable.csv foreach ($user in $users) { Write-Verbose "Processing licenses for user $($user.UserPrincipalName)" try { $user = Get-MsolUser -UserPrincipalName $user.UserPrincipalName -ErrorAction Stop } catch { continue } $SKUs = @($user.Licenses) if (!$SKUs) { Write-Verbose "No Licenses found for user $($user.UserPrincipalName), skipping..." ; continue } foreach ($SKU in $SKUs) { if (($SKU.GroupsAssigningLicense.Guid -ieq $user.ObjectId.Guid) -or (!$SKU.GroupsAssigningLicense.Guid)) { Write-Verbose "Removing license $($Sku.AccountSkuId) from user $($user.UserPrincipalName)" Set-MsolUserLicense -UserPrincipalName $user.UserPrincipalName -RemoveLicenses $SKU.AccountSkuId } else { Write-Verbose "License $($Sku.AccountSkuId) is assigned via Group, use the Azure AD blade to remove it!" continue } } }
Some final remarks. The script can produce some information output via the Write-Verbose statements, if you want to see this info make sure to set the value of the $VerbosePreference variable to “Continue”. If you want additional output, such as detailed logging or producing a list of users for which licenses could not be removed, feel free to adjust the code. And you might want to expand on the error handling of the script 🙂
UPDATE: the script had some logic issues which Tony Redmond was able to catch, so thank him for the updated version 🙂
I am unable to remove the licenses. Is there something missing in the script? connect to account 365? Does anyone have an excel csv model?
This method no longer works, as Microsoft deprecated the MSOL licensing cmdlets. Use this instead: https://www.michev.info/blog/post/3490/remove-all-office-365-licenses-for-a-group-of-users-from-csv-file-via-graph
I am trying to find one similar to this but have it also remove the disabled users from distribution lists as well. We have over 3,000 shared mailboxes and distribution lists so it would take forever for one person to go through each of those to find and remove a user.
How about this one: https://www.michev.info/Blog/Post/2161/script-to-remove-users-from-all-groups-in-office-365
Would there be a way to make this attack on one type of directly assigned license?
Sure, just put another check inside the
foreach ($SKU in $SKUs)
loop. For example:
if ($SKU.AccountSkuId -ne “TENANT:LICENSE_YOU_WANT_REMOVED”) { continue }
Awesome, so (bear with me I am a very novice powershell user so learning as I go) would need to replace the first if statement?:
if (($SKU.GroupAssigningLicense.Guid -ieq $user.ObjectId.Guid) to:
if (($SKU.AccountSKUId -ne “DOMAIN:STUDENTWOFFPACK_IW_STUDENT” -ieq $user.ObjectId.Guid)
I used this to remove any license before and it worked beautifully, but now I fear I have to target just two license types.
No need to replace anything, just add the additional line (insert it after the foreach statement, so line 12). That way the script will ignore any license apart from the one you specify in the if statement.
I got it to work! Woo hoo. It doesn’t seem to want to attack two licenses, just one at a time, but it does work only on the specified I ask for.
Hi Vasil,
Just wanted to thank you for this, I was trying to figure out how to remove all licenses from a group of users and then add a specific licenses after all the licenses have been removed. I was able to built out and test a working script based on this blog.
Best Regards!
B
Hi, Great script! I was wondering how this will change with the newer Azure Active Directory PowerShell for Graph module. We have a need to do this with the newer module as it supports MFA for Admin Accounts and also have use cases where we would only Remove Licenses from a list of users. Thank you!
Reference:
https://docs.microsoft.com/en-us/microsoft-365/enterprise/remove-licenses-from-user-accounts-with-microsoft-365-powershell?view=o365-worldwide
I’ll put together a version that uses Azure AD cmdlets when I get some free time…
Thank you!