Active Directory Computer Account Cleanup

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
        }
    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s