Discovering Stale User Accounts with PowerShell

Back in December I wrote a posting on “Discovering Stale Computer Accounts with PowerShell”.  Today I received an email from one of my readers (Thanks Matt for writing!) trying to adjust the script to query for stale user accounts.  The script that I created in the previous entry is a good starting point, but requires some modifications to work properly for user accounts.

The biggest change in the script is that the DirectorySearcher filter has to be modified to look for user accounts.  Simply changing  the filter to “user” from “computer” doesn’t quite work as for some reason ADSI will retrieve both the user accounts as well as the computer accounts.  We can further limit the search by adding the ObjectCategory in addition to the ObjectClass.

This particular example will query on the last password change date.

function Get-StaleUserAccounts
    # Use Directory Services object to attach to the domain
    $searcher = new-object DirectoryServices.DirectorySearcher([ADSI]"")
    # Filter down to user accounts
    #when you query for objectClass=User, you will not only get user accounts but also computer accounts. 
    #To limit the search to true user accounts, you would have to also include the objectCategory
    $searcher.filter = "(&(objectCategory=person)(objectClass=User))"
    # Cache the results
    $searcher.CacheResults = $true
    $searcher.SearchScope = “Subtree”
    $searcher.PageSize = 1000
    # Find anything you can that matches the definition of being a user object
    $accounts = $searcher.FindAll()
    # Check to make sure we found some accounts
    if($accounts.Count -gt 0)
        foreach($account in $accounts)
            $LastPassChange = [datetime]::FromFileTimeUTC($account.Properties["pwdlastset"][0]);    
            # Determine the timespan between the two dates
            $datediff = new-TimeSpan $LastPassChange $(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 AccountName($account.Properties["name"][0]);
            $obj | Add-Member NoteProperty LastPasswordChange($LastPassChange);
            $obj | Add-Member NoteProperty DaysSinceChange($datediff.Days);
            # Write the output to the screen
            Write-Output $obj;
# Get user 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-StaleUserAccounts |Where-Object {$_.DaysSinceChange -gt 60}