@@ -19,54 +19,196 @@ function Invoke-ExecBECRemediate {
1919 $Username = $Request.Body.username
2020 Write-Host $TenantFilter
2121 Write-Host $SuspectUser
22+
2223 $Results = try {
24+ $AllResults = [System.Collections.Generic.List [object ]]::new()
25+
26+ # Step 1: Reset Password
2327 $Step = ' Reset Password'
24- Set-CIPPResetPassword - UserID $Username - tenantFilter $TenantFilter - APIName $APIName - Headers $Headers
28+ try {
29+ $PasswordResult = Set-CIPPResetPassword - UserID $Username - tenantFilter $TenantFilter - APIName $APIName - Headers $Headers
30+ $AllResults.Add ($PasswordResult )
31+ } catch {
32+ $AllResults.Add ([pscustomobject ]@ {
33+ resultText = " Failed to reset password: $ ( $_.Exception.Message ) "
34+ state = ' error'
35+ })
36+ }
37+
38+ # Step 2: Disable Account
2539 $Step = ' Disable Account'
26- Set-CIPPSignInState - userid $Username - AccountEnabled $false - tenantFilter $TenantFilter - APIName $APIName - Headers $Headers
40+ try {
41+ $DisableResult = Set-CIPPSignInState - userid $Username - AccountEnabled $false - tenantFilter $TenantFilter - APIName $APIName - Headers $Headers
42+ $AllResults.Add ([pscustomobject ]@ {
43+ resultText = $DisableResult
44+ state = if ($DisableResult -like " *WARNING*" ) { ' warning' } else { ' success' }
45+ })
46+ } catch {
47+ $AllResults.Add ([pscustomobject ]@ {
48+ resultText = " Failed to disable account: $ ( $_.Exception.Message ) "
49+ state = ' error'
50+ })
51+ }
52+
53+ # Step 3: Revoke Sessions
2754 $Step = ' Revoke Sessions'
28- Revoke-CIPPSessions - userid $SuspectUser - username $Username - Headers $Headers - APIName $APIName - tenantFilter $TenantFilter
55+ try {
56+ $SessionResult = Revoke-CIPPSessions - userid $SuspectUser - username $Username - Headers $Headers - APIName $APIName - tenantFilter $TenantFilter
57+ $AllResults.Add ([pscustomobject ]@ {
58+ resultText = $SessionResult
59+ state = if ($SessionResult -like " *Failed*" ) { ' error' } else { ' success' }
60+ })
61+ } catch {
62+ $AllResults.Add ([pscustomobject ]@ {
63+ resultText = " Failed to revoke sessions: $ ( $_.Exception.Message ) "
64+ state = ' error'
65+ })
66+ }
67+
68+ # Step 4: Remove MFA methods
2969 $Step = ' Remove MFA methods'
30- Remove-CIPPUserMFA - UserPrincipalName $Username - TenantFilter $TenantFilter - Headers $Headers
70+ try {
71+ $MFAResult = Remove-CIPPUserMFA - UserPrincipalName $Username - TenantFilter $TenantFilter - Headers $Headers
72+ $AllResults.Add ([pscustomobject ]@ {
73+ resultText = $MFAResult
74+ state = if ($MFAResult -like " *No MFA methods*" ) { ' info' } elseif ($MFAResult -like " *Successfully*" ) { ' success' } else { ' error' }
75+ })
76+ } catch {
77+ $AllResults.Add ([pscustomobject ]@ {
78+ resultText = " Failed to remove MFA methods: $ ( $_.Exception.Message ) "
79+ state = ' error'
80+ })
81+ }
82+
83+ # Step 5: Disable Inbox Rules
3184 $Step = ' Disable Inbox Rules'
32- $Rules = New-ExoRequest - anchor $Username - tenantid $TenantFilter - cmdlet ' Get-InboxRule' - cmdParams @ {Mailbox = $Username ; IncludeHidden = $true }
33- $RuleDisabled = 0
34- $RuleFailed = 0
35- if (($Rules | Measure-Object ).Count -gt 0 ) {
36- $Rules | Where-Object { $_.Name -ne ' Junk E-Mail Rule' -and $_.Name -notlike ' Microsoft.Exchange.OOF.*' } | ForEach-Object {
37- try {
38- Set-CIPPMailboxRule - Username $Username - TenantFilter $TenantFilter - RuleId $_.Identity - RuleName $_.Name - Disable - APIName $APIName - Headers $Headers
39- $RuleDisabled ++
40- } catch {
41- $_.Exception.Message
42- $RuleFailed ++
85+ try {
86+ Write-LogMessage - headers $Headers - API $APIName - message " Starting inbox rules processing for user: $Username " - Sev ' Info' - tenant $TenantFilter
87+ $Rules = New-ExoRequest - anchor $Username - tenantid $TenantFilter - cmdlet ' Get-InboxRule' - cmdParams @ {Mailbox = $Username ; IncludeHidden = $true }
88+ Write-LogMessage - headers $Headers - API $APIName - message " Retrieved $ ( ($Rules | Measure-Object ).Count) total rules for $Username " - Sev ' Info' - tenant $TenantFilter
89+ $RuleDisabled = 0
90+ $RuleFailed = 0
91+ $DelegateRulesSkipped = 0
92+ $RuleMessages = [System.Collections.Generic.List [string ]]::new()
93+
94+ if (($Rules | Measure-Object ).Count -eq 0 ) {
95+ # No rules exist at all
96+ $AllResults.Add ([pscustomobject ]@ {
97+ resultText = " No Inbox Rules found for $Username ."
98+ state = ' info'
99+ })
100+ } else {
101+ # Rules exist, filter and process them
102+ $ProcessableRules = $Rules | Where-Object {
103+ $_.Name -ne ' Junk E-Mail Rule' -and
104+ $_.Name -notlike ' Microsoft.Exchange.OOF.*'
105+ }
106+
107+ if (($ProcessableRules | Measure-Object ).Count -eq 0 ) {
108+ # Rules exist but none are processable after filtering
109+ $SystemRulesCount = ($Rules | Measure-Object ).Count - $DelegateRulesSkipped
110+ if ($SystemRulesCount -gt 0 ) {
111+ $AllResults.Add ([pscustomobject ]@ {
112+ resultText = " Found $ ( ($Rules | Measure-Object ).Count) inbox rules for $Username , but none require disabling (only system rules found)."
113+ state = ' info'
114+ })
115+ }
116+ } else {
117+ # Process the filterable rules
118+ $ProcessableRules | ForEach-Object {
119+ $CurrentRule = $_
120+ Write-LogMessage - headers $Headers - API $APIName - message " Processing rule: Name='$ ( $CurrentRule.Name ) ', Identity='$ ( $CurrentRule.Identity ) '" - Sev ' Info' - tenant $TenantFilter
121+
122+ try {
123+ Set-CIPPMailboxRule - Username $Username - TenantFilter $TenantFilter - RuleId $CurrentRule.Identity - RuleName $CurrentRule.Name - Disable - APIName $APIName - Headers $Headers
124+
125+ Write-LogMessage - headers $Headers - API $APIName - message " Successfully disabled rule: $ ( $CurrentRule.Name ) " - Sev ' Info' - tenant $TenantFilter
126+ $RuleDisabled ++
127+ } catch {
128+ # Check if this is a system delegate rule, if so we can ignore the error
129+ if ($CurrentRule.Name -match ' ^Delegate Rule -\d+$' ) {
130+ Write-LogMessage - headers $Headers - API $APIName - message " Skipping delegate rule '$ ( $CurrentRule.Name ) ' - unable to disable (expected behavior)" - Sev ' Info' - tenant $TenantFilter
131+ $DelegateRulesSkipped ++
132+ } else {
133+ # Handle as normal error
134+ $ErrorMsg = " Could not disable rule '$ ( $CurrentRule.Name ) ': $ ( $_.Exception.Message ) "
135+ Write-LogMessage - headers $Headers - API $APIName - message $ErrorMsg - Sev ' Error' - tenant $TenantFilter
136+ $RuleMessages.Add ($ErrorMsg )
137+ $RuleFailed ++
138+ }
139+ }
140+ }
141+
142+ # Report results
143+ if ($RuleDisabled -gt 0 ) {
144+ $AllResults.Add ([pscustomobject ]@ {
145+ resultText = " Successfully disabled $RuleDisabled inbox rules for $Username "
146+ state = ' success'
147+ })
148+ } elseif ($DelegateRulesSkipped -gt 0 -and $RuleDisabled -eq 0 -and $RuleFailed -eq 0 ) {
149+ # Only system rules were found, report as no processable rules
150+ $AllResults.Add ([pscustomobject ]@ {
151+ resultText = " No processable inbox rules found for $Username "
152+ state = ' info'
153+ })
154+ }
155+
156+ if ($RuleFailed -gt 0 ) {
157+ $AllResults.Add ([pscustomobject ]@ {
158+ resultText = " Failed to process $RuleFailed inbox rules for $Username "
159+ state = ' warning'
160+ })
161+
162+ # Add individual rule failure messages as objects
163+ foreach ($RuleMessage in $RuleMessages ) {
164+ $AllResults.Add ([pscustomobject ]@ {
165+ resultText = $RuleMessage
166+ state = ' error'
167+ })
168+ }
169+ }
43170 }
44171 }
45- }
46- if ($RuleDisabled -gt 0 ) {
47- " Disabled $RuleDisabled Inbox Rules for $Username "
48- } else {
49- " No Inbox Rules found for $Username . We have not disabled any rules."
50- }
51172
52- if ($RuleFailed -gt 0 ) {
53- " Failed to disable $RuleFailed Inbox Rules for $Username "
173+ $TotalProcessed = $RuleDisabled + $RuleFailed + $DelegateRulesSkipped
174+ Write-LogMessage - headers $Headers - API $APIName - message " Completed inbox rules processing for $Username . Total rules: $ ( ($Rules | Measure-Object ).Count) , Processed: $TotalProcessed , Disabled: $RuleDisabled , Failed: $RuleFailed , Delegate rules skipped: $DelegateRulesSkipped " - Sev ' Info' - tenant $TenantFilter
175+
176+ } catch {
177+ $ErrorMsg = " Failed to process inbox rules: $ ( $_.Exception.Message ) "
178+ Write-LogMessage - headers $Headers - API $APIName - message $ErrorMsg - Sev ' Error' - tenant $TenantFilter
179+ $AllResults.Add ([pscustomobject ]@ {
180+ resultText = $ErrorMsg
181+ state = ' error'
182+ })
54183 }
184+
55185 $StatusCode = [HttpStatusCode ]::OK
56- Write-LogMessage - API ' BECRemediate' - tenant $TenantFilter - message " Executed Remediation for $Username " - sev ' Info' - LogData @ ($Results )
186+ Write-LogMessage - API ' BECRemediate' - tenant $TenantFilter - message " Executed Remediation for $Username " - sev ' Info' - LogData @ ($AllResults )
187+
188+ # Return the results array
189+ $AllResults.ToArray ()
57190
58191 } catch {
59192 $ErrorMessage = Get-CippException - Exception $_
60- $Results = [pscustomobject ]@ {' Results' = " Failed to execute remediation. $ ( $ErrorMessage.NormalizedError ) " }
193+ $ErrorList = [System.Collections.Generic.List [object ]]::new()
194+ $ErrorList.Add ([pscustomobject ]@ {
195+ resultText = " Failed to execute remediation at step '$Step '. $ ( $ErrorMessage.NormalizedError ) "
196+ state = ' error'
197+ })
61198 Write-LogMessage - API ' BECRemediate' - tenant $TenantFilter - message " Executed Remediation for $Username failed at the $Step step" - sev ' Error' - LogData $ErrorMessage
62199 $StatusCode = [HttpStatusCode ]::InternalServerError
200+
201+ # Return the error array
202+ $ErrorList.ToArray ()
63203 }
64- $Results = [pscustomobject ]@ {' Results' = @ ($Results ) }
65204
66- # Associate values to output bindings by calling 'Push-OutputBinding'.
205+ # Create the final response structure
206+ $ResponseBody = [pscustomobject ]@ {' Results' = @ ($Results ) }
207+
208+ # Associate values to output bindings
67209 Push-OutputBinding - Name Response - Value ([HttpResponseContext ]@ {
68210 StatusCode = $StatusCode
69- Body = $Results
211+ Body = $ResponseBody
70212 })
71213
72214}
0 commit comments