CleanupMonster
This module provides an easy way to cleanup Active Directory from dead/old objects based on various criteria. It can also disable, move or delete objects. It can utilize Azure AD, Intune and Jamf to get additional information about objects before deleting them.
Install / Use
/learn @EvotecIT/CleanupMonsterREADME
CleanupMonster - PowerShell Module
<p align="center"> <a href="https://www.powershellgallery.com/packages/CleanupMonster"><img src="https://img.shields.io/powershellgallery/v/CleanupMonster.svg?style=flat-square"></a> <a href="https://www.powershellgallery.com/packages/CleanupMonster"><img src="https://img.shields.io/powershellgallery/v/CleanupMonster.svg?label=powershell%20gallery%20preview&colorB=yellow&style=flat-square&include_prereleases"></a> <a href="https://github.com/EvotecIT/CleanupMonster"><img src="https://img.shields.io/github/license/EvotecIT/CleanupMonster.svg?style=flat-square"></a> </p> <p align="center"> <a href="https://www.powershellgallery.com/packages/CleanupMonster"><img src="https://img.shields.io/powershellgallery/p/CleanupMonster.svg?style=flat-square"></a> <a href="https://github.com/EvotecIT/CleanupMonster"><img src="https://img.shields.io/github/languages/top/evotecit/CleanupMonster.svg?style=flat-square"></a> <a href="https://github.com/EvotecIT/CleanupMonster"><img src="https://img.shields.io/github/languages/code-size/evotecit/CleanupMonster.svg?style=flat-square"></a> <a href="https://www.powershellgallery.com/packages/CleanupMonster"><img src="https://img.shields.io/powershellgallery/dt/CleanupMonster.svg?style=flat-square"></a> </p> <p align="center"> <a href="https://twitter.com/PrzemyslawKlys"><img src="https://img.shields.io/twitter/follow/PrzemyslawKlys.svg?label=Twitter%20%40PrzemyslawKlys&style=flat-square&logo=twitter"></a> <a href="https://evotec.xyz/hub"><img src="https://img.shields.io/badge/Blog-evotec.xyz-2A6496.svg?style=flat-square"></a> <a href="https://www.linkedin.com/in/pklys"><img src="https://img.shields.io/badge/LinkedIn-pklys-0077B5.svg?logo=LinkedIn&style=flat-square"></a> <a href="https://evo.yt/discord"><img alt="Discord" src="https://img.shields.io/discord/508328927853281280?style=flat-square&label=discord%20chat"></a> </p>CleanupMonster is a PowerShell module to that helps you clean up Active Directory.
It has multiple functionalities currently & planned:
- [x] Cleanup stale Computer objects from Active Directory
- [x] Cleanup SID History from Active Directory
- [ ] Cleanup stale User objects from Active Directory
- [ ] Cleanup stale Group objects from Active Directory
- [x] Cleanup GMSA/MSA objects from Active Directory
There are 2 blog posts that explain how to use the module:
- Mastering Active Directory Hygiene: Automating Stale Computer Cleanup with CleanupMonster
- Mastering Active Directory Hygiene: Automating SID History Cleanup with CleanupMonster
The solution is really thought through and has many options to customize it to your needs. It's a complete solution for cleaning up Active Directory. Please make sure to run this module with proper permissions or you may get wrong results. By default Active Directory domain allows a standard user to read LastLogonDate and LastPasswordSet attributes. If you have changed those settings you may need to run the module with elevated permissions even for reporting needs.
Support This Project
If you find this project helpful, please consider supporting its development. Your sponsorship will help the maintainers dedicate more time to maintenance and new feature development for everyone.
It takes a lot of time and effort to create and maintain this project. By becoming a sponsor, you can help ensure that it stays free and accessible to everyone who needs it.
To become a sponsor, you can choose from the following options:
Your sponsorship is completely optional and not required for using this project. We want this project to remain open-source and available for anyone to use for free, regardless of whether they choose to sponsor it or not.
If you work for a company that uses our .NET libraries or PowerShell Modules, please consider asking your manager or marketing team if your company would be interested in supporting this project. Your company's support can help us continue to maintain and improve this project for the benefit of everyone.
Thank you for considering supporting this project!
Installation
Install-Module -Name CleanupMonster -Force -Verbose
Introduction ✨
CleanupMonster is built for teams that want Active Directory cleanup to feel deliberate, staged, and reviewable instead of risky and opaque. Every cleanup path starts with discovery, can generate HTML output for review, and can be wrapped in limits, pending lists, and WhatIf controls before anything destructive happens.
Whether you are retiring stale computers, pruning unused MSA / gMSA objects, or removing legacy SID history after migrations, the module is designed to help you choose the right cleanup track for the problem in front of you.
[!WARNING] Run the module with the permissions required to read the attributes you rely on. In a default AD configuration that often includes
LastLogonDateandPasswordLastSet, but hardened environments may require elevated rights even for reporting-only runs.
Overview 🧭
CleanupMonster is easiest to understand as three end-to-end cleanup paths. They all start with discovery and reporting, but each one is optimized for a different cleanup problem.
[!TIP] If you are new to the module, start with
-ReportOnlyand-WhatIf, keep limits low, and validate the generated HTML output before enabling destructive actions.
flowchart LR
classDef computer fill:#D9F2E6,stroke:#1F7A4D,stroke-width:2px,color:#123524;
classDef service fill:#FFF0CC,stroke:#B7791F,stroke-width:2px,color:#5B3A00;
classDef sid fill:#DCEBFF,stroke:#2B6CB0,stroke-width:2px,color:#153E75;
classDef action fill:#F7FAFC,stroke:#4A5568,stroke-width:1px,color:#1A202C;
A["CleanupMonster"] --> B["Computer cleanup"]
A --> C["Service-account cleanup"]
A --> D["SID history cleanup"]
B --> B1["Disable"]
B --> B2["Move"]
B --> B3["DisableAndMove"]
B --> B4["Delete after pending age"]
C --> C1["Disable"]
C --> C2["Delete"]
C --> C3["Explicit selectors and low limits"]
D --> D1["Discover SID history"]
D --> D2["Filter by OU / object type / SID domain"]
D --> D3["Remove with small limits"]
class B,B1,B2,B3,B4 computer;
class C,C1,C2,C3 service;
class D,D1,D2,D3 sid;
class A action;
| Area | Cmdlet | Best for | Typical actions | Recommended mindset |
| --- | --- | --- | --- | --- |
| Computer cleanup | Invoke-ADComputersCleanup | Stale computer lifecycle management in AD, optionally cross-checked against Azure AD, Intune, and Jamf | Disable, move, disable-and-move, delete | Stage changes across multiple runs |
| Service-account cleanup | Invoke-ADServiceAccountsCleanup | Reviewing and cleaning stale MSA / gMSA objects with stronger destructive-run guardrails | Disable, delete | Start narrow and require explicit selectors |
| SID history cleanup | Invoke-ADSIDHistoryCleanup | Removing legacy SID history entries with detailed before/after reporting | Report, selective remove | Start with discovery and tiny limits |
Quick Start 🚀
Recommended first commands for each path:
# Computer cleanup preview
Invoke-ADComputersCleanup -Disable -ReportOnly -WhatIf -ShowHTML
# Service-account cleanup preview
Invoke-ADServiceAccountsCleanup -Disable -ReportOnly -WhatIf -IncludeAccounts 'gmsa-*'
# SID history cleanup preview
Invoke-ADSIDHistoryCleanup -ReportOnly -WhatIf
Cleanup Paths 🧰
Computer Cleanup 🖥️
Computer cleanup is the richest workflow in the module. It is built for staged remediation of stale computer objects rather than one immediate destructive pass.
Use it when you want to:
- find stale AD computer objects
- optionally require Azure AD, Intune, or Jamf inactivity before actioning AD
- disable first and delete later
- move devices to a quarantine OU before final deletion
- keep a pending list as a safety buffer across multiple runs
Typical lifecycle:
flowchart LR
classDef stage fill:#D9F2E6,stroke:#1F7A4D,stroke-width:2px,color:#123524;
classDef gate fill:#FFF7E6,stroke:#B7791F,stroke-width:2px,color:#5B3A00;
classDef outcome fill:#EDF2F7,stroke:#4A5568,stroke-width:1px,color:#1A202C;
A["Discover stale computers"] --> B{"Matches disable filters?"}
B -- "No" --> Z["Remain untouched"]
B -- "Yes" --> C["Disable"]
C --> D{"DisableAndMove enabled?"}
D -- "Yes" --> E["Move to quarantine OU"]
D -- "No" --> F["Add to pending list"]
E --> F
F --> G{"Later matches move or delete gates?"}
G -- "Move path" --> H["Move-only follow-up"]
G -- "Delete path" --> I["Delete after pending-age threshold"]
class A,C,E,F,H,I stage;
class B,D,G gate;
class Z outcome;
What matters most:
-WhatIfnow flows to move actions as well as disable/delete actions-Moveis a first-class path, not just a side effect of disable-DisableAndMovebehaves like a disable workflow during discovery and then performs the move during execution- pending-list timing in the datastore lets you separate disable, move, and delete into different operational windows
Good starter profiles:
- pilot:
-ReportOnly -WhatIf -Disable - staged remediation:
-Disablenow, then-DeleteListProcessedMoreThanlater - quarantine-first:
-DisableAndMove -DisableMoveTargetOrganizationalUnit ... - cloud-aware cleanup: add Azure AD / Intune / Jamf inactivity thresholds and safety limits
Relevant examples:
Examples/DeleteComputers.ps1Examples/DeleteComputersWithMoveAndEmail.ps1- `Ex
