PowerShell

Discovering Stale Computer Accounts with PowerShell

We all know that most test domains are the perfect breeding ground for non-standard practices.  This includes the lack of managing user accounts, computer accounts, DNS records and the like.

ADSI scripting has always been challenging, but I did do some of it back in my IT days when writing code in VBScript.  I wanted to try to tie in to a test domain to determine what computer accounts hadn’t had their password changed in the last 90 days.  By default, Windows machines will talk to the domain in which they have a computer account in and change their password every 30 days.  With that in mind, we can look for computer accounts who haven’t changed their computer account password in the last month.

We probably want to allow a little more than 30 days; perhaps computer accounts might be considered stale after 60 or 90 days.  That means that the computer hasn’t made network contact in the allotted amount of time.

Within PowerShell I tapped into the ADSI adapter and some of the .NET Framework objects that let me search Active Directory.  Really I was only interested in the computer name and the date of the last password change.  Both of those were easy to access.  Here is a copy of what my script looks like:

function Get-DomainComputerAccounts
{   
    # Use Directory Services object to attach to the domain
    $searcher = new-object DirectoryServices.DirectorySearcher([ADSI]"")
    
    # Filter down to computer accounts
    $searcher.filter = "(&(objectClass=computer))"
    
    # Cache the results
    $searcher.CacheResults = $true
    $searcher.SearchScope = “Subtree”
    $searcher.PageSize = 1000
    
    # Find anything you can that matches the definition of being a computer object
    $accounts = $searcher.FindAll()
    
    # Check to make sure we found some accounts
    if($accounts.Count -gt 0)
    {             
        foreach($account in $accounts)
        {
            # Property that contains the last password change in long integer format
            $pwdlastset = $account.Properties["pwdlastset"];
            
            # Convert the long integer to normal DateTime format
            $lastchange = [datetime]::FromFileTimeUTC($pwdlastset[0]);
            
            # Determine the timespan between the two dates
            $datediff = new-TimeSpan $lastchange $(Get-Date);
        
            # Create an output object for table formatting
            $obj = new-Object PSObject;
            
            # Add member properties with their name and value pair
            $obj | Add-Member NoteProperty ComputerName($account.Properties["name"][0]);
            $obj | Add-Member NoteProperty LastPasswordChange($lastchange);
            $obj | Add-Member NoteProperty DaysSinceChange($datediff.Days);
            
            # Write the output to the screen
            Write-Output $obj;
        }
    }
}
 
# Get computer accounts where a password change hasn't occurred in 60 days or more
# If nothing outputted, then there are no accounts that meet that criteria
Get-DomainComputerAccounts |Where-Object {$_.DaysSinceChange -gt 60}

This script could be modified to include functionality that would take the suspect computer accounts and disable them, then eventually delete them.