Tutorials › PowerShell
Find and disable inactive Active Directory users with PowerShell
Accounts belonging to people who left months ago are an easy way in for an attacker. This tutorial uses PowerShell to find user accounts that haven't signed in for a while, check them, disable them safely, and only delete them after a waiting period.
Before you start
- You need an account that can modify users in Active Directory, and the Active Directory module for PowerShell. It is installed on domain controllers, and on other machines with the RSAT Active Directory tools.
- Agree a cut-off with whoever owns the accounts. 90 days is common. Microsoft's own guidance uses six months for password age.
- Have a list of service accounts and people on long leave. Microsoft warns that both may not sign in for long periods, so they will show up as "inactive" even though they are in use.
Steps
- Sign in to a domain controller or a management server with RSAT installed.
- Right-click Start and select Windows PowerShell (Admin) or Terminal (Admin).
- Load the module:
Import-Module ActiveDirectory - List user accounts that haven't signed in for 90 days.
-TimeSpanuses the format D.H:M:S, so90.00:00:00means 90 days:Search-ADAccount -AccountInactive -UsersOnly -TimeSpan 90.00:00:00 | Where-Object { $_.Enabled -eq $true } | Select-Object Name, SamAccountName, LastLogonDate, DistinguishedName | Sort-Object LastLogonDate - To check one OU only, add
-SearchBasewith the OU's distinguished name, for example:Search-ADAccount -AccountInactive -UsersOnly -TimeSpan 90.00:00:00 -SearchBase "OU=Staff,DC=contoso,DC=local" - Export the list so you have a record and can share it for sign-off:
CreateSearch-ADAccount -AccountInactive -UsersOnly -TimeSpan 90.00:00:00 | Where-Object { $_.Enabled -eq $true } | Select-Object Name, SamAccountName, LastLogonDate, DistinguishedName | Export-Csv C:\Temp\inactive-users.csv -NoTypeInformationC:\Tempfirst if it doesn't exist. - For a second opinion, run Microsoft's check for accounts where the password or last logon is older than 180 days:
$d = [DateTime]::Today.AddDays(-180) Get-ADUser -Filter '(PasswordLastSet -lt $d) -or (LastLogonTimestamp -lt $d)' -Properties PasswordLastSet,LastLogonTimestamp | Format-Table Name,PasswordLastSet,@{N="LastLogonTimestamp";E={[datetime]::FromFileTime($_.LastLogonTimestamp)}} - Open the CSV and remove anything that must stay enabled: service accounts, break-glass admin accounts, people on leave, and anything you don't recognise. Ask before you act on an account you aren't sure about.
- Save the cleaned list as
C:\Temp\to-disable.csv, keeping theSamAccountNamecolumn. - Do a dry run.
-WhatIfshows what would happen without changing anything:Import-Csv C:\Temp\to-disable.csv | ForEach-Object { Disable-ADAccount -Identity $_.SamAccountName -WhatIf } - When the output looks right, run it for real by removing
-WhatIf:Import-Csv C:\Temp\to-disable.csv | ForEach-Object { Disable-ADAccount -Identity $_.SamAccountName } - Add a note to each account's description with the date and reason, so the next engineer knows why it is disabled:
Import-Csv C:\Temp\to-disable.csv | ForEach-Object { Set-ADUser -Identity $_.SamAccountName -Description "Disabled $(Get-Date -Format yyyy-MM-dd) - inactive 90 days" } - Wait several weeks. Microsoft recommends disabling first, waiting, and only deleting once nobody has reported a problem.
Disabling an account stops that person or service from signing in straight away. If a service account is on your list by mistake, whatever runs under it will stop. Always do the
-WhatIf dry run first and get the list signed off.Deleting an account is permanent unless the AD Recycle Bin is turned on. Only delete after the waiting period, and check you have a working backup of Active Directory first.
Check it worked
- Confirm the accounts are now disabled:
Every line should showImport-Csv C:\Temp\to-disable.csv | ForEach-Object { Get-ADUser -Identity $_.SamAccountName | Select-Object SamAccountName, Enabled }EnabledasFalse. - Run the search from step 4 again. The accounts you disabled should no longer appear, because the filter only shows enabled accounts.
- In Active Directory Users and Computers, browse to one of the accounts. Its icon should show a small down arrow, which means it is disabled.
The inactivity check relies on the last logon timestamp, which Microsoft notes is not replicated every time someone signs in. Treat it as approximate, and use a cut-off well beyond a couple of weeks.
Sources
- Microsoft Learn: Regularly check for and remove inactive user accounts in Active Directory
- Microsoft Learn: Search-ADAccount
- Microsoft Learn: Disable-ADAccount