It happens all to often, I’ll be in Active Directory looking for one thing and the name of a computer account catches my eye. Perhaps it’s using an old naming convention or maybe it’s a server that I know what decommissioned years earlier, but either way it shouldn’t be there.
We all know we should remove AD Computer accounts when a machine is no longer in server, but we’re not loving in a perfect world and sometimes this step gets missed.
Luckily, Active Directory stores the date a computer account last logged into the domain. The below script takes advantage of this by finding any computer that hasn’t contacted a Domain Controller in the past 90+ days and moving it to a Disabled Computer OU where it is then disabled. It will also update the description of the account with the date it was disabled and which OU it came from in case it needs to be re-enabled again.
############################################################################ # Script Name : ADCleanup.ps1 # Author : Chris Dwyer # Date : 12/03/2019 # Last Edited : 12/03/2019 # Description : Disable ADComputer accounts not used in X days ############################################################################ # Purpose: # - To cleanup AD by disabling old computer accounts and move # them to a seperate OU. # Method: # - Run this scrit on a regular baisis to disable old accounts. # - # Notes: # - ############################################################################ # Set threshold for number of days inactive before disabling $DaysInactive = 90 $time = (Get-Date).Adddays(-($DaysInactive)) # Get current date - this is used to flag the account with the date it was disabled $Date = Get-Date $DateStr = '{0:yyyyMMdd}' -f $Date # Location of where stale Server/Computer accounts will be moved $StaleServersOU = Get-ADOrganizationalUnit -Filter 'name -like "*StaleServers*"' $StaleComputersOU = Get-ADOrganizationalUnit -Filter 'name -like "*StaleComputers*"' # OU for comptuer accounts with no access - will need to exist already $CompNoAccessOU = Get-ADOrganizationalUnit -Filter 'name -like "*Computers-no-access*"' # Check if Computers-No-Access OU exists - exit if not present If (!($CompNoAccessOU)){ Write-host "Computer-No-Access OU not found - please create before running this script again." -ForegroundColor Yellow Read-Host -Prompt “Press Enter to exit” Exit } # Check for Stale Servers OU - Create if not pressent If (!($StaleServersOU)){ New-ADOrganizationalUnit -Name "StaleServers" -Path $CompNoAccessOU $StaleServersOU = Get-ADOrganizationalUnit -Filter 'name -like "*StaleServers*"' } # Check for Stale Computers OU - Create if not present If (!($StaleComputersOU)){ New-ADOrganizationalUnit -Name "StaleComputers" -Path $CompNoAccessOU $StaleComputersOU = Get-ADOrganizationalUnit -Filter 'name -like "*StaleComputers*"' } # Get all AD servers/computers with lastLogonTimestamp less than our time $Servers = Get-ADComputer -Filter {LastLogonTimeStamp -lt $time -and OperatingSystem -like "*server*"} -Properties LastLogonTimeStamp, OperatingSystem, description, enabled, DistinguishedName | select-object Name,DistinguishedName,OperatingSystem,description,enabled,@{Name="Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}} | sort name $Computers = Get-ADComputer -Filter {LastLogonTimeStamp -lt $time -and OperatingSystem -notlike "*server*"} -Properties LastLogonTimeStamp, OperatingSystem, description, enabled, DistinguishedName | select-object Name,DistinguishedName,OperatingSystem,description,enabled,@{Name="Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}} | sort name # Processing old Server accounts Foreach ($Server in $Servers){ If ($server.DistinguishedName -notlike "*OU=StaleServers*"){ # Dont bother with accounts already in the Stale OU Try { # Just to be sure the server isnt online and something weird has happened Write-host "Testing " $Server.name Test-Connection $Server.name -Count 1 -ErrorAction Stop } Catch { # Disable computer account Disable-ADAccount -identity $Server.DistinguishedName # Update description with Date and old location - Current description is appended to the end $NewDescription = "Disabled $DateStr. Moved from " + $Server.DistinguishedName + " (" + $Server.description + ")" Set-ADComputer -Identity $Server.DistinguishedName -Description $NewDescription # Move to Stale Servers OU Write-Host "Moving " $Server.Name Get-ADComputer $Server.Name | Move-ADObject -TargetPath $StaleServersOU } } } # Processing old Computer accounts Foreach ($Computer in $Computers){ If ($Computer.DistinguishedName -notlike "*OU=StaleComputers*"){ # Dont bother with accounts already in the Stale OU # Disable computer account Disable-ADAccount -identity $Computer.DistinguishedName # Update description with Date and old location - Current description is appended to the end $NewDescription = "Disabled $DateStr. Moved from " + $Computer.DistinguishedName + " (" + $Computer.description + ")" Set-ADComputer -Identity $Computer.DistinguishedName -Description $NewDescription # Move to Stale Computers OU Write-Host "Moving " $Computer.Name Get-ADComputer $Computer.Name | Move-ADObject -TargetPath $StaleComputersOU } }