Skip to content

Commit 8ecaf98

Browse files
committed
chore: improve remove-cippgroups performance
switch to bulk requests check properties for groups that cannot be managed
1 parent dc0b936 commit 8ecaf98

File tree

1 file changed

+113
-29
lines changed

1 file changed

+113
-29
lines changed

Modules/CIPPCore/Public/Remove-CIPPGroups.ps1

Lines changed: 113 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,127 @@ function Remove-CIPPGroups {
1111
if (-not $userid) {
1212
$UserID = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($Username)" -tenantid $TenantFilter).id
1313
}
14-
$AllGroups = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/?`$select=displayName,mailEnabled,id,groupTypes,assignedLicenses&`$top=999" -tenantid $TenantFilter)
14+
$AllGroups = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/?`$select=displayName,mailEnabled,id,groupTypes,assignedLicenses,onPremisesSyncEnabled,membershipRule&`$top=999" -tenantid $TenantFilter)
1515

16-
$Returnval = (New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserID)/GetMemberGroups" -tenantid $TenantFilter -type POST -body '{"securityEnabledOnly": false}').value | ForEach-Object -Parallel {
17-
Import-Module '.\Modules\AzBobbyTables'
18-
Import-Module '.\Modules\CIPPCore'
19-
$Group = $_
16+
# Get user's groups
17+
$UserGroups = (New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserID)/GetMemberGroups" -tenantid $TenantFilter -type POST -body '{"securityEnabledOnly": false}').value
2018

21-
try {
22-
$GroupName = ($using:AllGroups | Where-Object -Property id -EQ $Group).displayName
23-
$IsMailEnabled = ($using:AllGroups | Where-Object -Property id -EQ $Group).mailEnabled
24-
$IsM365Group = $null -ne ($using:AllGroups | Where-Object { $_.id -eq $Group -and $_.groupTypes -contains 'Unified' })
25-
$IsLicensed = ($using:AllGroups | Where-Object -Property id -EQ $Group).assignedLicenses.Count -gt 0
26-
27-
if ($IsLicensed) {
28-
"Could not remove $($using:Username) from $GroupName. This is because the group has licenses assigned to it."
29-
} else {
30-
if ($IsM365Group) {
31-
$null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$_/members/$($using:UserID)/`$ref" -tenantid $using:TenantFilter -type DELETE -body '' -Verbose
32-
} elseif (-not $IsMailEnabled) {
33-
$null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$_/members/$($using:UserID)/`$ref" -tenantid $using:TenantFilter -type DELETE -body '' -Verbose
34-
} elseif ($IsMailEnabled) {
35-
$Params = @{ Identity = $GroupName; Member = $using:UserID ; BypassSecurityGroupManagerCheck = $true }
36-
New-ExoRequest -tenantid $using:tenantFilter -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true
19+
if (-not $UserGroups) {
20+
$Returnval = "$($Username) is not a member of any groups."
21+
Write-LogMessage -headers $Headers -API $APIName -message "$($Username) is not a member of any groups" -Sev 'Info' -tenant $TenantFilter
22+
return $Returnval
23+
}
24+
25+
# Initialize bulk request arrays and results
26+
$BulkRequests = [System.Collections.Generic.List[object]]::new()
27+
$ExoBulkRequests = [System.Collections.Generic.List[object]]::new()
28+
$GraphLogs = [System.Collections.Generic.List[object]]::new()
29+
$ExoLogs = [System.Collections.Generic.List[object]]::new()
30+
$Results = [System.Collections.Generic.List[string]]::new()
31+
32+
# Process each group and prepare bulk requests
33+
foreach ($Group in $UserGroups) {
34+
$GroupInfo = $AllGroups | Where-Object -Property id -EQ $Group
35+
$GroupName = $GroupInfo.displayName
36+
$IsMailEnabled = $GroupInfo.mailEnabled
37+
$IsM365Group = $null -ne ($AllGroups | Where-Object { $_.id -eq $Group -and $_.groupTypes -contains 'Unified' })
38+
$IsLicensed = $GroupInfo.assignedLicenses.Count -gt 0
39+
$IsDynamic = -not [string]::IsNullOrWhiteSpace($GroupInfo.membershipRule)
40+
41+
if ($IsLicensed) {
42+
$Results.Add("Could not remove $Username from group '$GroupName' because it has assigned licenses. These groups are removed during the license removal step.")
43+
Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$GroupName' because it has assigned licenses. These groups are removed during the license removal step." -Sev 'Warning' -tenant $TenantFilter
44+
} elseif ($IsDynamic) {
45+
$Results.Add("Error: Could not remove $Username from group '$GroupName' because it is a Dynamic Group.")
46+
Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$GroupName' because it is a Dynamic Group." -Sev 'Warning' -tenant $TenantFilter
47+
} elseif ($GroupInfo.onPremisesSyncEnabled) {
48+
$Results.Add("Error: Could not remove $Username from group '$GroupName' because it is synced with Active Directory.")
49+
Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$GroupName' because it is synced with Active Directory." -Sev 'Warning' -tenant $TenantFilter
50+
} else {
51+
if ($IsM365Group -or (-not $IsMailEnabled)) {
52+
# Use Graph API for M365 Groups and Security Groups
53+
$BulkRequests.Add(@{
54+
id = "removeFromGroup-$Group"
55+
method = 'DELETE'
56+
url = "groups/$Group/members/$UserID/`$ref"
57+
})
58+
$GraphLogs.Add(@{
59+
message = "Removed $Username from $GroupName"
60+
id = "removeFromGroup-$Group"
61+
groupName = $GroupName
62+
})
63+
} elseif ($IsMailEnabled) {
64+
# Use Exchange Online for Distribution Lists
65+
$Params = @{
66+
Identity = $GroupName
67+
Member = $UserID
68+
BypassSecurityGroupManagerCheck = $true
3769
}
70+
$ExoBulkRequests.Add(@{
71+
CmdletInput = @{
72+
CmdletName = 'Remove-DistributionGroupMember'
73+
Parameters = $Params
74+
}
75+
})
76+
$ExoLogs.Add(@{
77+
message = "Removed $Username from $GroupName"
78+
target = $UserID
79+
groupName = $GroupName
80+
})
81+
}
82+
}
83+
}
3884

39-
Write-LogMessage -headers $using:Headers -API $($using:APIName) -message "Removed $($using:Username) from $GroupName" -Sev 'Info' -tenant $using:TenantFilter
40-
"Successfully removed $($using:Username) from group $GroupName"
85+
# Execute Graph bulk requests
86+
if ($BulkRequests.Count -gt 0) {
87+
try {
88+
$RawGraphRequest = New-GraphBulkRequest -tenantid $TenantFilter -scope 'https://graph.microsoft.com/.default' -Requests @($BulkRequests) -asapp $true
89+
90+
foreach ($GraphLog in $GraphLogs) {
91+
$GraphError = $RawGraphRequest | Where-Object { $_.id -eq $GraphLog.id -and $_.status -notmatch '^2[0-9]+' }
92+
if ($GraphError) {
93+
$Message = Get-NormalizedError -message $GraphError.body.error
94+
$Results.Add("Could not remove $Username from group '$($GraphLog.groupName)': $Message. This is likely because it's a Dynamic Group or synced with Active Directory")
95+
Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$($GraphLog.groupName)': $Message" -Sev 'Error' -tenant $TenantFilter
96+
} else {
97+
$Results.Add("Successfully removed $Username from group '$($GraphLog.groupName)'")
98+
Write-LogMessage -headers $Headers -API $APIName -message $GraphLog.message -Sev 'Info' -tenant $TenantFilter
99+
}
41100
}
42101
} catch {
43102
$ErrorMessage = Get-CippException -Exception $_
44-
Write-LogMessage -headers $using:Headers -API $($using:APIName) -message "Could not remove $($using:Username) from group $GroupName : $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $using:TenantFilter -LogData $ErrorMessage
45-
"Could not remove $($using:Username) from group $($GroupName): $($ErrorMessage.NormalizedError). This is likely because its a Dynamic Group or synched with active directory"
103+
Write-LogMessage -headers $Headers -API $APIName -message "Error executing Graph bulk requests: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage
104+
$Results.Add("Error executing bulk removal requests: $($ErrorMessage.NormalizedError)")
46105
}
47106
}
48-
if (-not $Returnval) {
49-
$Returnval = "$($Username) is not a member of any groups."
50-
Write-LogMessage -headers $Headers -API $APIName -message "$($Username) is not a member of any groups" -Sev 'Info' -tenant $TenantFilter
107+
108+
# Execute Exchange Online bulk requests
109+
if ($ExoBulkRequests.Count -gt 0) {
110+
try {
111+
$RawExoRequest = New-ExoBulkRequest -tenantid $TenantFilter -cmdletArray @($ExoBulkRequests)
112+
$LastError = $RawExoRequest | Select-Object -Last 1
113+
114+
foreach ($ExoError in $LastError.error) {
115+
$Results.Add("Error - $ExoError")
116+
Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $ExoError -Sev 'Error'
117+
}
118+
119+
foreach ($ExoLog in $ExoLogs) {
120+
$ExoError = $LastError | Where-Object { $ExoLog.target -in $_.target -and $_.error }
121+
if (!$LastError -or ($LastError.error -and $LastError.target -notcontains $ExoLog.target)) {
122+
$Results.Add("Successfully removed $Username from group $($ExoLog.groupName)")
123+
Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $ExoLog.message -Sev 'Info'
124+
} else {
125+
$Results.Add("Could not remove $Username from $($ExoLog.groupName). This is likely because its a Dynamic Group or synched with active directory")
126+
Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from $($ExoLog.groupName)" -Sev 'Error' -tenant $TenantFilter
127+
}
128+
}
129+
} catch {
130+
$ErrorMessage = Get-CippException -Exception $_
131+
Write-LogMessage -headers $Headers -API $APIName -message "Error executing Exchange bulk requests: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage
132+
$Results.Add("Error executing bulk Exchange requests: $($ErrorMessage.NormalizedError)")
133+
}
51134
}
52-
return $Returnval
135+
136+
return $Results
53137
}

0 commit comments

Comments
 (0)