internal/functions/EPO_Invoke-EasyPIMCleanup.ps1
function Invoke-EasyPIMCleanup { [CmdletBinding(SupportsShouldProcess=$true)] param( [Parameter(Mandatory=$true)] [pscustomobject]$Config, [Parameter(Mandatory=$true)] [ValidateSet('delta','initial')] [string]$Mode, [Parameter(Mandatory=$false)] [string]$TenantId, [Parameter(Mandatory=$false)] [string]$SubscriptionId, [Parameter(Mandatory=$false)] [string]$WouldRemoveExportPath ) Write-Verbose "[Cleanup] Starting cleanup (mode=$Mode)" if ($PSCmdlet.ShouldProcess('Cleanup operations', 'Invoke EasyPIM cleanup')) { # Orchestrator-only cleanup fallback (no dependency on core module) $results = [pscustomobject]@{ Kept=0; Removed=0; Skipped=0; Protected=0; WouldRemoveCount=0 AnalysisCompleted=$false; DesiredAssignments=0; Mode=$Mode CleanupStatus="Cleanup not performed" } $desired = @{} if ($Config.Assignments) { if ($Config.Assignments.EntraRoles) { foreach ($r in $Config.Assignments.EntraRoles) { foreach ($a in @($r.assignments)) { if ($a) { $key = "entra::$($r.roleName)::/::$($a.principalId)"; $desired[$key] = $true } } } } if ($Config.Assignments.AzureRoles) { foreach ($r in $Config.Assignments.AzureRoles) { $rn = $r.RoleName; if (-not $rn) { $rn=$r.roleName } $sc = $r.Scope; if (-not $sc) { $sc=$r.scope } foreach ($a in @($r.assignments)) { if ($a) { $key = "azure::$rn::$sc::$($a.principalId)"; $desired[$key] = $true } } } } if ($Config.Assignments.Groups) { foreach ($g in $Config.Assignments.Groups) { foreach ($a in @($g.assignments)) { if ($a) { $key = "group::member::$($g.groupId)::$($a.principalId)"; $desired[$key] = $true } } } } } Write-Verbose "[Cleanup] Fallback: analyzed desired set size=$($desired.Keys.Count). No removals executed." # Update analysis details in results for better user feedback $results.AnalysisCompleted = $true $results.DesiredAssignments = $desired.Keys.Count if ($Mode -eq 'delta') { $results.CleanupStatus = "Analyzed $($desired.Keys.Count) desired assignments. Cleanup operations require core EasyPIM module." } else { $results.CleanupStatus = "Initial mode - no cleanup analysis performed in orchestrator-only mode." } return $results } # Orchestrator-only, non-destructive cleanup summary (no cross-module calls) $results = [pscustomobject]@{ Kept=0; Removed=0; Skipped=0; Protected=0; WouldRemoveCount=0 AnalysisCompleted=$false; DesiredAssignments=0; Mode=$Mode CleanupStatus="Cleanup not performed" } # Only analyze in delta mode; initial mode is intentionally a no-op without explicit rules if ($Mode -eq 'delta' -and $Config -and $Config.PSObject.Properties.Name -contains 'Assignments' -and $Config.Assignments) { $desired = @{} if ($Config.Assignments.EntraRoles) { foreach ($r in $Config.Assignments.EntraRoles) { foreach ($a in @($r.assignments)) { if ($a) { $key = "entra::$($r.roleName)::/::$($a.principalId)"; $desired[$key] = $true } } } } if ($Config.Assignments.AzureRoles) { foreach ($r in $Config.Assignments.AzureRoles) { $rn = $r.RoleName; if (-not $rn) { $rn=$r.roleName } $sc = $r.Scope; if (-not $sc) { $sc=$r.scope } foreach ($a in @($r.assignments)) { if ($a) { $key = "azure::$rn::$sc::$($a.principalId)"; $desired[$key] = $true } } } } if ($Config.Assignments.Groups) { foreach ($g in $Config.Assignments.Groups) { foreach ($a in @($g.assignments)) { if ($a) { $key = "group::member::$($g.groupId)::$($a.principalId)"; $desired[$key] = $true } } } } $results.AnalysisCompleted = $true $results.DesiredAssignments = $desired.Keys.Count $results.CleanupStatus = "Analyzed $($desired.Keys.Count) desired assignments. Full cleanup requires core EasyPIM module." Write-Verbose "[Cleanup] Orchestrator analysis complete. Desired entries=$($desired.Keys.Count). No removals executed." } else { if ($Mode -eq 'initial') { $results.CleanupStatus = "Initial mode - comprehensive cleanup requires core EasyPIM module for safety." } else { $results.CleanupStatus = "No assignments configured for cleanup analysis." } } return $results } |