Introduction
Active Directory (AD) is the backbone of identity and access management in most Windows-based organisations. Over time, as businesses grow, change providers, onboard and offboard staff, and adopt new technologies, the AD environment accumulates objects that are no longer actively used. Stale user accounts, outdated computer objects, and empty security groups are among the most common findings in any AD health review — and they represent a real and measurable security risk if left unaddressed.
This guide walks through a complete, real-world Active Directory security review engagement. It covers the methodology used to identify stale and inactive objects, the tools and scripts employed to extract the data, how the findings were classified and analysed, and the remediation decisions that followed. All domain names, organisation names, and personally identifiable information have been removed. The intent is to provide a reusable reference for IT professionals and managed service providers conducting similar reviews.
The Context
The engagement involved a Windows Server-based environment running an on-premises Active Directory domain. The organisation was in the process of transitioning to a new managed service provider (MSP), which made the timing of the review particularly valuable. A clean, well-documented AD environment is one of the most important things an outgoing provider can hand over. Undocumented stale accounts, orphaned groups, and unclear object ownership create risk and confusion for any incoming team.
The review focused on three primary areas:
- Stale and inactive user accounts
- Stale and inactive computer objects
- Empty security groups
Each area required a different approach to data extraction, classification, and remediation planning.
Phase 1: Extracting the Data
Tools Used
All data was extracted using PowerShell with the Active Directory module installed. The commands were run directly on the domain controller with administrative privileges.
Stale User Accounts
The first script targeted user accounts that had not logged in within a defined threshold. The organisation used a six-month inactivity window as the trigger for review.
Get-ADUser -Filter * -Properties LastLogonDate, Enabled |
Where-Object { $_.LastLogonDate -lt (Get-Date).AddDays(-180) -or $_.LastLogonDate -eq $null } |
Select-Object Name, LastLogonDate, Enabled |
Export-Csv stale_users.csv -NoTypeInformation
This produced a CSV file with three columns: the account name, the last recorded logon date, and whether the account was currently enabled.
Stale Computer Objects
A similar approach was applied to computer objects. The same six-month threshold was used.
Get-ADComputer -Filter * -Properties LastLogonDate, Enabled |
Where-Object { $_.LastLogonDate -lt (Get-Date).AddDays(-180) -or $_.LastLogonDate -eq $null } |
Select-Object Name, LastLogonDate, Enabled |
Export-Csv stale_computers.csv -NoTypeInformationEmpty Security Groups
The initial approach to extracting empty groups used a simple member count filter. However, during the review it was identified that this script had a significant flaw. When a group has no members, the Active Directory PowerShell module may return a null value for the Members property rather than an empty array. This means the .Count -eq 0 check can silently fail, causing empty groups to be missed entirely.
The original script was:
Get-ADGroup -Filter * -Properties Members |
Where-Object { $_.Members.Count -eq 0 } |
Select-Object Name |
Export-Csv empty_groups.csvThis was corrected to handle both null returns and empty collections, while also capturing additional context columns needed for the audit:
Get-ADGroup -Filter * -Properties Members, Description, GroupScope, GroupCategory |
Where-Object { -not $_.Members -or $_.Members.Count -eq 0 } |
Select-Object Name, GroupScope, GroupCategory, Description, DistinguishedName,
@{Name='OU'; Expression={ ($_.DistinguishedName -split ',', 2)[1] }} |
Export-Csv empty_groups.csv -NoTypeInformationThe corrected script returned six columns per group: Name, GroupScope, GroupCategory, Description, DistinguishedName, and OU. The OU field was derived by splitting the Distinguished Name, producing a human-readable location within the directory tree.
Phase 2: Analysing the Data
Stale Users — Findings
The stale users export returned 187 user objects. After filtering for the Enabled field, the breakdown was as follows:
- 132 accounts were disabled
- 55 accounts were enabled
The 132 disabled accounts were noted for the record but excluded from the active review. Disabled accounts present a lower immediate risk and were left in place in the domain controller per the organisation’s existing policy.
Of the 55 enabled accounts, further analysis separated them into two groups:
Group A — Accounts with no recorded logon date (32 accounts)
These accounts had never successfully authenticated against the domain controller. Upon further discussion with the client, it was established that these accounts belonged to business-to-business (B2B) contacts who were synced for email purposes but were not expected to authenticate against the on-premises domain. This was a known and intentional configuration. No action was required, and these accounts were formally documented and excluded from the remediation scope.
Group B — Accounts with historical login activity, now inactive (23 accounts)
These accounts had previously authenticated against the domain but had not done so within the six-month threshold. The accounts were sorted by inactivity age, oldest to newest, and classified by risk:
- Two accounts had been inactive for more than five years
- Several accounts had been inactive for two to three years
- The remainder fell within the one to two year range or just over the six-month threshold
These 23 accounts were the subject of a formal client communication requesting confirmation of employment status or business justification for each account. The communication was structured to allow the client to mark each account as active, to be disabled, to be deleted, or requiring further investigation.
Additionally, an internal management ticket was created to document the justification for any accounts that were ultimately disabled or removed. This ticket served as a formal record for audit purposes and included a six-part justification covering inactivity threshold enforcement, unauthorised access risk, evidence of offboarding gaps, least privilege principles, compliance obligations, and shared account risk.
Stale Computer Objects — Findings
The stale computers export returned 173 objects. The split was:
- 92 objects were disabled
- 81 objects were enabled
As with user accounts, the disabled computers were retained in the domain controller and excluded from the active review.
The 81 enabled computers were classified into age buckets based on the number of days since the last recorded logon:
- 7 enabled computers had last logged in between five and seven years ago — classified as critical priority
- 25 enabled computers had last logged in between three and five years ago — classified as high priority
- 45 enabled computers had last logged in between one and three years ago — classified as medium priority
- 2 enabled computers had last logged in within the past year — classified as low priority
- 2 enabled computer objects had no recorded logon date at all — identified as Azure AD-related objects requiring separate investigation
The recommended action varied by age bucket, ranging from immediate decommission for the oldest machines to a monitoring status for those just over the threshold.
Phase 3: Analysing the Empty Groups
The corrected PowerShell script returned 65 empty groups. This was higher than initially expected and confirmed that the original script had been missing groups due to the null member issue described earlier.
Classification Approach
Each group was classified into one of several categories based on its Distinguished Name, description, and name pattern. This classification determined whether the group required active review or could be left in place without action.
Windows OS Built-in Groups (CN=Builtin container) — 15 groups
These are groups that Windows Server creates by default and places in the Builtin container. Examples include Backup Operators, Hyper-V Administrators, Network Configuration Operators, and Storage Replica Administrators. These groups cannot be deleted and should never be removed. Being empty is not unusual for environments where the associated role is managed through Domain Admin accounts rather than delegated administration.
Active Directory Default Groups (CN=Users container) — 13 groups
These are groups that Active Directory creates automatically during domain provisioning. Examples include Domain Computers, Read-only Domain Controllers, DnsAdmins, DHCP Administrators, and the RODC Password Replication groups. These groups are part of the AD schema and should be retained. Whether or not they need to be populated depends on the specific administrative model the organisation uses.
SQL Server Service Groups — 13 groups
These groups were created automatically by SQL Server installations on two internal servers. The naming convention follows the pattern SQLServerMSSQLUser, SQLServerFDHostUser, SQLServerSQLAgentUser, and similar prefixes. Each group corresponds to a specific SQL Server instance and service component. Being empty may indicate that the SQL Server instances in question have been decommissioned or were never fully configured. The recommendation was to verify whether the associated servers were still active before deciding to remove these groups.
Azure AD Connect Operational Groups — 3 groups
Three groups were created by the Azure AD Connect installation: ADSyncOperators, ADSyncBrowse, and ADSyncPasswordSet. These groups are used internally by the sync engine and should not be deleted while Azure AD Connect remains active on the server. Their being empty is normal and expected — they operate through service-level permissions rather than explicit membership.
During the review, the organisation ran the following command to check whether Password Writeback was enabled, since ADSyncPasswordSet is specifically tied to that feature:
Get-ADSyncGlobalSettings | Select-Object -ExpandProperty Parameters |
Where-Object { $_.Name -like "*PasswordSync*" -or $_.Name -like "*Writeback*" }The output confirmed that all writeback features — DeviceWriteBack, UserWriteBack, GroupWriteBack — were set to False, and Password Writeback did not appear in the output at all, confirming it had never been configured. The ADSync groups were retained with a documented note that they should not be removed unless Azure AD Connect is being fully decommissioned.
SharePoint Service Group — 1 group
One group was identified with a naming pattern consistent with a SharePoint Office Web Apps installation. The group was flagged for confirmation as to whether the associated SharePoint environment was still active or had been migrated to SharePoint Online.
Custom and Business-Created Groups — remaining groups
The groups that did not match any of the above patterns were classified as custom groups created by the organisation or a previous IT provider. These fell into three sub-categories:
GPO-linked groups: Groups such as Local Admins, WG Filtered Users, WG Unfiltered Users, Naples Protected Files, and FSG_CBD_NAP were identified as likely referenced within existing Group Policy Objects. The critical point here is that an empty group linked to a Restricted Groups or Local Users and Groups GPO policy does not mean the policy is inactive — it means the policy is enforced but will affect no one until a member is added. Adding the wrong account to these groups could immediately grant unintended privileges across all targeted computers.
Legacy service groups: Groups associated with services such as WINS, Telnet, legacy Exchange, Terminal Services, and a legacy third-party email security product were flagged as likely no longer relevant. These were included in the handover documentation for the incoming provider to confirm before taking any removal action.
Backup and operational groups: A group named Backups was identified as likely tied to a backup solution. The recommendation was to identify which backup product was in use, locate its service account, and assign that account to the Backup Operators built-in group rather than to a custom distribution group.
Phase 4: Key Security Observations
The DnsAdmins Group
The DnsAdmins group deserves particular attention in any AD security review. This group grants its members the ability to load arbitrary DLL files into the DNS Server service, which runs as SYSTEM on a domain controller. This is a well-documented privilege escalation path. An empty DnsAdmins group is, from a security standpoint, a positive finding. The recommendation was to leave it empty if DNS management was being handled by Domain Admins directly, and to populate it only if a specific delegated DNS admin role was being introduced.
The Local Admins Group
The Local Admins group was a custom group placed in the organisation’s Security Groups organisational unit. The absence of members combined with its placement strongly suggested it was referenced in a GPO to push local administrator rights to workstations. This is a common pattern used in preparation for LAPS deployment, where the group is pre-staged in the GPO before LAPS is configured to manage the membership dynamically. The incoming provider was advised to check GPO references before making any changes to this group.
Get-GPO -All | ForEach-Object {
Get-GPOReport -Guid $_.Id -ReportType XML |
Select-String "Local Admins"
} | Select-Object -UniqueKey Admins and Enterprise Key Admins
These two groups are created by Active Directory during domain and forest functional level upgrades. They are part of the key credential management infrastructure used by LAPS version 2 and Windows Hello for Business. Both groups being empty is expected and correct in any environment where these features have not yet been deployed. The recommendation was to document their purpose, retain them, and populate them only when LAPS or Windows Hello for Business was introduced.
Phase 5: Remediation Actions and Handover Documentation
User Account Remediation
The 23 stale enabled user accounts were communicated to the client via a formal written request for confirmation. Each account was presented with a last logon date, an inactivity age calculation, and four possible actions: disable, delete, retain with justification, or investigate. A management ticket was raised to provide an auditable record of the decision-making process.
Computer Object Remediation
Enabled computer objects were prioritised by age. The seven machines aged between five and seven years were flagged for immediate decommission verification. A structured spreadsheet was produced containing the full list of enabled computers sorted by inactivity age, with a recommended action assigned to each object based on its age bucket.
Group Remediation
No groups were deleted during the review period. The approach taken was to classify, document, and communicate rather than to act unilaterally. The reasoning was straightforward: in an environment undergoing a provider transition, deleting groups without full confirmation of their purpose and dependencies carries significant risk. A single incorrectly removed group could silently break a GPO, revoke file share access, or disrupt a service dependency.
The groups were documented in a formal handover notice addressed to the client, with instructions to share it with the incoming provider. The document organised groups into four sections — GPO-linked groups, key admin groups, legacy service groups, and Azure AD Connect groups — with specific recommendations and suggested timelines for each.
Lessons Learned
The initial PowerShell script for empty groups was flawed. The use of .Count -eq 0 without accounting for null returns caused a significant number of empty groups to be excluded from the initial export. Always use -not $_.Members -or $_.Members.Count -eq 0 when checking for empty group membership in Active Directory.
Disabled accounts are not the same as resolved accounts. A disabled account still occupies space in the directory, may still appear in search results, and can be re-enabled by anyone with the appropriate permissions. A formal review of disabled accounts should be part of any complete AD health engagement.
Empty does not mean unused. Several of the groups identified in this review were actively referenced in GPO configurations despite having no members. The relationship between group membership and group policy enforcement is not immediately obvious to non-technical stakeholders, and clear communication on this point is essential.
Context matters more than count. Fifty empty groups sounds alarming until you understand that thirty-four of them are default Windows groups that will always exist in a healthy AD environment. Classification before communication prevents unnecessary concern and keeps remediation effort focused where it belongs.
Provider transitions are a high-risk moment. The period between outgoing and incoming managed service providers is one of the most likely times for undocumented configurations to cause problems. A structured handover document covering active objects, group dependencies, GPO references, and sync service requirements is not optional — it is a professional responsibility.
Conclusion
Active Directory security reviews are most effective when they are methodical, evidence-based, and clearly communicated. The process described in this guide — extract, classify, analyse, communicate, and document — provides a repeatable framework that can be applied to environments of any size. The tools required are built into Windows. The analysis can be performed with basic scripting knowledge. The real value lies in understanding what the data means and translating that understanding into actions that are proportionate, well-documented, and appropriate to the organisation’s context.
An AD environment that has been properly reviewed and handed over with clear documentation is a significantly more secure and manageable foundation for any incoming provider to build on.
This guide is intended for educational purposes for IT professionals and managed service providers. All references to specific environments, domain names, and organisations have been removed. No confidential information is disclosed.
