Powershell - Add users from groups to assign group with group exceptions

Olívio MouraOlívio Moura
4 min read
# Ensure the Microsoft.Graph module is imported
# Import-Module Microsoft.Graph

# Authenticate using the managed identity
Connect-MgGraph -Identity -NoWelcome
#Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All" -NoWelcome

# Control variable to enable/disable output
$EnableOutput = $true # Set to $false to disable output, $true to enable

# Function to control output based on the $EnableOutput flag
function ConditionalWrite-Output {
    param (
        [string]$Message
    )
    if ($EnableOutput) {
        Write-Output $Message
    }
}

# Define the group configurations
$groupConfigs = @(
###################### ZOOM ######################
    @{
        IdentitySource = @("SourceGroup1","SourceGroup2","SourceGroup3")
        IdentityAssignGroup = "AssignGroup"
        IdentityAssignGroupLimit = 1850
        IdentityAssignSoftLimitNew = 10
        IdentityAssignSoftLimitRemove = 5
        IdentityAssignHardLimitRemove = 50
        IdentityExclusion = @("ExclusionGroup1")
    }
)

foreach ($config in $groupConfigs) {
    # Extract group-specific values
    $IdentityAssignGroup = $config.IdentityAssignGroup
    $IdentityAssignGroupLimit = $config.IdentityAssignGroupLimit
    $IdentityAssignSoftLimitNew = $config.IdentityAssignSoftLimitNew
    $IdentityAssignSoftLimitRemove = $config.IdentityAssignSoftLimitRemove
    $IdentityAssignHardLimitRemove = $config.IdentityAssignHardLimitRemove
    $IdentityExclusion = $config.IdentityExclusion
    $IdentitySource = $config.IdentitySource

    # Retrieve the assign group by its display name
    $groupIdentityAssign = Get-MgGroup -Filter "displayName eq '$IdentityAssignGroup'"
    if ($null -eq $groupIdentityAssign) {
        throw "Group '$IdentityAssignGroup' not found."
    }

    # Retrieve members of the assign group
    $membersIdentityAssign = Get-MgGroupMember -GroupId $groupIdentityAssign.Id -All:$true | Select-Object -Property Id

    # Create hash set for fast lookup of assign group members
    $assignMemberIds = @{}
    $membersIdentityAssign | ForEach-Object { $assignMemberIds[$_.Id] = $true }

    # Initialize current group size
    $currentGroupSize = $assignMemberIds.Count

    # Combine members from all exclusion groups
    $exclusionMemberIds = @{}
    foreach ($exclusionGroup in $IdentityExclusion) {
        $groupIdentityExclusion = Get-MgGroup -Filter "displayName eq '$exclusionGroup'"
        if ($null -eq $groupIdentityExclusion) {
            throw "Exclusion group '$exclusionGroup' not found."
        }

        $membersIdentityExclusion = Get-MgGroupMember -GroupId $groupIdentityExclusion.Id -All:$true | Select-Object -Property Id
        $membersIdentityExclusion | ForEach-Object { $exclusionMemberIds[$_.Id] = $true }

    }

    # Identify unique members to remove (intersection of assign group and exclusion group)
    $membersToRemove = $assignMemberIds.Keys | Where-Object { $exclusionMemberIds[$_] } | Select-Object -Unique

    # Check if the number of members to remove will exceed the hard limit
    if ($membersToRemove.Count -gt $IdentityAssignHardLimitRemove -and $IdentityAssignHardLimitRemove -ne 0) {
        ConditionalWrite-Output "The number of members to remove ($($membersToRemove.Count)) exceeds the hard limit of $IdentityAssignHardLimitRemove. No members will be removed from group '$IdentityAssignGroup'."
    } else {
        # Remove members until the soft limit is reached
        $removalCount = 0
        foreach ($memberId in $membersToRemove) {
            if ($currentGroupSize -le $IdentityAssignSoftLimitRemove -and $IdentityAssignSoftLimitRemove -ne 0) {
                ConditionalWrite-Output "Reached the soft limit of $IdentityAssignSoftLimitRemove members for group '$IdentityAssignGroup'. No more members will be removed."
                break
            }

            Remove-MgGroupMemberByRef -GroupId $groupIdentityAssign.Id -DirectoryObjectId $memberId
            ConditionalWrite-Output "Removed member with Id '$((Get-MgUser -UserId $memberId).UserPrincipalName)' from group '$IdentityAssignGroup'"


            # Update hash table and current group size
            $assignMemberIds.Remove($memberId)
            $currentGroupSize -= 1
            $removalCount += 1
        }

        ConditionalWrite-Output "Completed removal of excluded members for group '$IdentityAssignGroup'."
    }

    # Initialize a collection for the combined members from all source groups
    $membersIdentitySourceCombined = @()

    # Retrieve and combine members from each source group
    foreach ($sourceGroup in $IdentitySource) {
        $groupIdentitySource = Get-MgGroup -Filter "displayName eq '$sourceGroup'"
        if ($null -eq $groupIdentitySource) {
            throw "Source group '$sourceGroup' not found."
        }

        $membersIdentitySource = Get-MgGroupMember -GroupId $groupIdentitySource.Id -All:$true | Select-Object -Property Id
        $membersIdentitySourceCombined += $membersIdentitySource
    }

    # Ensure membersIdentitySourceCombined is unique before shuffling
    $membersIdentitySourceCombined = $membersIdentitySourceCombined | Select-Object -Unique -Property Id

    # Shuffle the combined list of unique source members to ensure randomness
    $membersIdentitySourceCombined = $membersIdentitySourceCombined | Get-Random -Count $membersIdentitySourceCombined.Count

    # Add matching users from the combined source groups to $groupIdentityAssign until the limit is reached
    $additionCount = 0
    foreach ($user in $membersIdentitySourceCombined) {
        if ($IdentityAssignGroupLimit -ne 0 -and $currentGroupSize -ge $IdentityAssignGroupLimit) {
            ConditionalWrite-Output "Reached the overall limit of $IdentityAssignGroupLimit members for group '$IdentityAssignGroup'."
            break
        }

        if ($IdentityAssignSoftLimitNew -ne 0 -and $additionCount -ge $IdentityAssignSoftLimitNew) {
            ConditionalWrite-Output "Reached the addition limit of $IdentityAssignSoftLimitNew members for group '$IdentityAssignGroup'."
            break
        }

        # Skip if the user is in the exclusion group
        if ($exclusionMemberIds.ContainsKey($user.Id)) {
            #ConditionalWrite-Output "Skipped user '$((Get-MgUser -UserId $user.Id).UserPrincipalName)' because they are in the exclusion group(s): $($IdentityExclusion -join ', ')."
            continue
        }

        # Add user to the group if not already present
        if (-not $assignMemberIds.ContainsKey($user.Id)) {
            New-MgGroupMember -GroupId $groupIdentityAssign.Id -DirectoryObjectId $user.Id
            ConditionalWrite-Output "Added user '$((Get-MgUser -UserId $user.Id).UserPrincipalName)' to group '$IdentityAssignGroup'"

            # Update hash table and current group size
            $assignMemberIds[$user.Id] = $true
            $currentGroupSize += 1
            $additionCount += 1
        }
    }

    ConditionalWrite-Output "Script execution completed for group '$IdentityAssignGroup'."
}

# Disconnect from Microsoft Graph
Disconnect-MgGraph | Out-Null
0
Subscribe to my newsletter

Read articles from Olívio Moura directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Olívio Moura
Olívio Moura