Public/Remove-NSPADDisabledUserGroupMembership.ps1
|
function Remove-NSPADDisabledUserGroupMembership { <# .SYNOPSIS Parks disabled user accounts: adds each to a holding group, makes that their primary group, and removes them from every other group. Returns one row per change. .DESCRIPTION For each disabled user (optionally only under -SearchBase): 1. add it to -HoldingGroup (which must exist) if it isn't a member; 2. set its primary group to -HoldingGroup (so it can leave Domain Users); 3. remove it from every other group it is a direct member of. ConfirmImpact is High - expect a confirmation prompt per change unless -Confirm:$false; -WhatIf shows everything it would do. Rows: User, Action (AddToHoldingGroup / SetPrimaryGroup / RemoveFromGroup), Group, Result (Done / AlreadyDone / WhatIf / Failed: ...). One failed change doesn't stop the rest. .PARAMETER HoldingGroup The group disabled accounts are parked in, e.g. 'DisabledUsers'. .PARAMETER SearchBase Only users under this OU / container. .PARAMETER KeepGroup Groups to leave the user in (name or sAMAccountName), besides the holding group. .EXAMPLE Remove-NSPADDisabledUserGroupMembership -HoldingGroup DisabledUsers -WhatIf .EXAMPLE Remove-NSPADDisabledUserGroupMembership -HoldingGroup DisabledUsers -Confirm:$false | Export-Csv C:\Admin\DisabledUserCleanup.csv -NoTypeInformation #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] [OutputType([pscustomobject])] param( [Parameter(Mandatory)][string]$HoldingGroup, [string]$SearchBase, [string[]]$KeepGroup = @() ) Assert-NSPADCommand Get-ADPrincipalGroupMembership -ModuleHint 'ActiveDirectory (RSAT)' $holding = Get-ADGroup -Identity $HoldingGroup -Properties primaryGroupToken -ErrorAction Stop $holdingMembers = @(Get-ADGroupMember -Identity $holding -ErrorAction Stop | ForEach-Object { "$($_.DistinguishedName)" }) $query = @{ Filter = 'Enabled -eq $false'; Properties = @('PrimaryGroupID'); ErrorAction = 'Stop' } if ($SearchBase) { $query.SearchBase = $SearchBase } function Step($user, $action, $group, [scriptblock]$change, [bool]$done) { $result = if ($done) { 'AlreadyDone' } elseif (-not $PSCmdlet.ShouldProcess("$($user.SamAccountName)", "$action $group")) { 'WhatIf' } else { try { & $change; 'Done' } catch { "Failed: $($_.Exception.Message)" } } [pscustomobject]@{ PSTypeName = 'NSP.ActiveDirectory.MembershipChange'; User = "$($user.SamAccountName)"; Action = $action; Group = $group; Result = $result } } foreach ($user in @(Get-ADUser @query)) { Step $user 'AddToHoldingGroup' "$($holding.Name)" { Add-ADGroupMember -Identity $holding -Members $user -ErrorAction Stop } ($holdingMembers -contains "$($user.DistinguishedName)") Step $user 'SetPrimaryGroup' "$($holding.Name)" { Set-ADUser -Identity $user -Replace @{ primaryGroupID = $holding.primaryGroupToken } -ErrorAction Stop } ("$($user.PrimaryGroupID)" -eq "$($holding.primaryGroupToken)") foreach ($g in @(Get-ADPrincipalGroupMembership -Identity $user -ErrorAction Stop)) { if ("$($g.DistinguishedName)" -eq "$($holding.DistinguishedName)") { continue } if ($KeepGroup -contains "$($g.Name)" -or $KeepGroup -contains "$($g.SamAccountName)") { continue } $grp = $g Step $user 'RemoveFromGroup' "$($g.Name)" { Remove-ADGroupMember -Identity $grp -Members $user -Confirm:$false -ErrorAction Stop } $false } } } |