Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save neil-sabol/250d43047c6c061067fca274588a4ce8 to your computer and use it in GitHub Desktop.
Save neil-sabol/250d43047c6c061067fca274588a4ce8 to your computer and use it in GitHub Desktop.
Remove in bulk direct assigned license to users who have group assigned license with the Microsoft Graph (MgGraph) PowerShell module
<#
Modified version of mrik23's MSOL-BulkRemoveDirectAssignedLicense.ps1 (https://gist.github.com/mrik23/2ed37ce0c7c4a79605bdcf052e29b391)
MSOL-BulkRemoveDirectAssignedLicense.ps1 was a modified version of a script from Microsoft Documentation.
Ref: https://docs.microsoft.com/en-us/azure/active-directory/active-directory-licensing-ps-examples
Removed the part that checks if the users is assigned more products than the group assigned license.
Added connection part and help to find Sku and Group Object ID.
This script requires the Microsoft Graph (MgGraph) PowerShell module.
#>
Import-Module Microsoft.Graph.Users
Import-Module Microsoft.Graph.Groups
Import-Module Microsoft.Graph.Identity.DirectoryManagement
Connect-MgGraph -Scopes "User.ReadWrite.All", "Group.Read.All", "Organization.Read.All"
# Get License SKUs (SkuIds) for the tenant
Get-MgSubscribedSku -Property SkuPartNumber,SkuId | Select SkuPartNumber,SkuId
# The license SkuId to be removed (from output of Get-MgSubscribedSku above)
$skuId = "e82ae890-b2d5-4d77-8d30-7c6e01e3022e"
# The NAME of the Azure AD group with license assignment to be processed
$LicensedGroup = "Licensed_Group"
# Get the group Object ID
$groupId = (Get-MgGroup -Filter "DisplayName eq `'$LicensedGroup`'").Id
# Helper functions used by the script
# Returns TRUE if the user has the license assigned directly
function UserHasLicenseAssignedDirectly {
Param($user, $skuId)
$license = GetUserLicense $user $skuId
if ($license -ne $null) {
# GroupsAssigningLicense contains a collection of IDs of objects assigning the license
# This could be a group object or a user object (contrary to what the name suggests)
# If the collection is empty, this means the license is assigned directly - this is the case for users who have never been licensed via groups in the past
if (@($license.AssignedByGroup).Count -ne @($license.AssignedByGroup | ?{$_ -ne $null}).Count) {
return $true
}
# If the collection contains the ID of the user object, this means the license is assigned directly
# Note: the license may also be assigned through one or more groups in addition to being assigned directly
foreach ($assignmentSource in $license.AssignedByGroup) {
if ($assignmentSource -ieq $user.Id) {
return $true
}
}
return $false
}
return $false
}
# Returns TRUE if the user is inheriting the license from a specific group
function UserHasLicenseAssignedFromThisGroup {
Param($user, $skuId, $groupId)
$license = GetUserLicense $user $skuId
if ($license -ne $null) {
# GroupsAssigningLicense contains a collection of IDs of objects assigning the license
# This could be a group object or a user object (contrary to what the name suggests)
foreach ($assignmentSource in $license.AssignedByGroup) {
# If the collection contains at least one ID not matching the user ID this means that the license is inherited from a group.
# Note: the license may also be assigned directly in addition to being inherited
if ($assignmentSource -ieq $groupId) {
return $true
}
}
return $false
}
return $false
}
# Returns the license object corresponding to the skuId. Returns NULL if not found
function GetUserLicense {
Param($user, $skuId)
# We look for the specific license SKU in all licenses assigned to the user
foreach($license in $user.AssignedLicenses) {
if ($license.SkuId -ieq $skuId) {
return $user.LicenseAssignmentStates | ?{ $_.SkuId -eq $skuId }
}
}
return $null
}
# Process staging removal for only 20 members in the group first
# You can then process all members in the group if the result of staging is OK - replace "-Top 20" with "-All"
$groupMembers = Get-MgGroupMember -Top 20 -GroupId $groupId | %{ Get-MgUser -UserId $_.Id -Property UserPrincipalName,Id,AssignedLicenses,LicenseAssignmentStates }
$groupMembers |
Foreach {
$user = $_;
$operationResult = "";
# Check if Direct license exists on the user
if (UserHasLicenseAssignedDirectly $user $skuId)
{
# Check if the license is assigned from this group, as expected
if (UserHasLicenseAssignedFromThisGroup $user $skuId $groupId)
{
# Remove the direct license from user
Set-MgUserLicense -UserId $user.UserPrincipalName -AddLicenses @{} -RemoveLicenses $skuId | Out-Null
$operationResult = "Removed direct license from user."
}
else
{
$operationResult = "User does not inherit this license from this group. License removal was skipped."
}
}
else
{
$operationResult = "User has no direct license to remove. Skipping."
}
# Format output
New-Object Object |
Add-Member -NotePropertyName UserId -NotePropertyValue $user.Id -PassThru |
Add-Member -NotePropertyName OperationResult -NotePropertyValue $operationResult -PassThru
} | Format-Table
@vikjoh
Copy link

vikjoh commented Feb 1, 2024

Works like a charm!
The script works excellent when changing license assignment from direct to group.

We also used the script when changing from direct to group and upgraded the user licenses from Standard to Premium SKU.
But for that to work we had to remove the part where the if-statement checks to see if the license is assigned from this group, since they are not assigned the same license as before.

Part removed:

            # Check if the license is assigned from this group, as expected
            if (UserHasLicenseAssignedFromThisGroup $user $skuId $groupId)
            {

  

            }
            else
            {
                $operationResult = "User does not inherit this license from this group. License removal was skipped."
            }

New foreach-loop

    Foreach { 
        $user = $_;
        $operationResult = "";

        # Check if Direct license exists on the user
        if (UserHasLicenseAssignedDirectly $user $skuId)
        {
            # Remove the direct license from user
            Set-MgUserLicense -UserId $user.UserPrincipalName -AddLicenses @{} -RemoveLicenses $skuId | Out-Null
            $operationResult = "Removed direct license from user."   
        }
        else
        {
            $operationResult = "User has no direct license to remove. Skipping."
        }

        # Format output
        New-Object Object | 
                    Add-Member -NotePropertyName UserId -NotePropertyValue $user.Id -PassThru |
                    Add-Member -NotePropertyName OperationResult -NotePropertyValue $operationResult -PassThru 
    } | Format-Table

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment