10

How can I find all computer accounts in my Active Directory domain that have been inactive for x days using PowerShell?

Note that I do actually know how to do this. This is a self-answered question just to get the knowledge out there. If anyone else has a better way, feel free to post it!

MDMarra
  • 100,734
  • 32
  • 197
  • 329

4 Answers4

10

This would give you all computer accounts that have no activity for the last 365 Days.

Search-ADAccount -AccountInactive -ComputersOnly -TimeSpan 365.00:00:00

This would sort it for you by lastlogondate.

Search-ADAccount -AccountInactive -ComputersOnly -TimeSpan 365.00:00:00 | Sort-Object lastlogondate | Ft name,lastlogondate -auto

This would give you disabled computer accounts.

Search-ADAccount -AccountDisabled -ComputersOnly 
Mike
  • 828
  • 1
  • 7
  • 18
  • Interesting! I (obviously) didn't know about that cmdlet. What attribute is measured for "AccountInactive"? lastlogondate? passwordlastset? – MDMarra Aug 09 '12 at 14:03
  • I am going to have to look into to be 100% sure, but I know that lastlogondate is one of the attributes that is returned if you look at the object, passwordlastset is not. The technet article doesn't really detail which attribute it uses. – Mike Aug 09 '12 at 14:11
  • 1
    Looked into it a little more and lastlogondate looks like it is just the conversion of lastlogontimestamp. There is no attribute called lastlogondate in the schema. Hope that helps. – Mike Aug 10 '12 at 14:05
5

Computers change their account password every 30 days by default. If a computer hasn't changed its password in an extended period of time, it means that they are no longer connected to the network.

This PowerShell script will output 2 text files. One is for disabled computers, one is for orphaned computer account objects. You must have the Active Directory PowerShell module installed.

In this example, I exclude an "Encrypted Laptops" OU, since they're mobile laptops that are disconnected for extended periods of time. You can remove that section if you don't have a similar setup

Import-Module ActiveDirectory

$Date = [DateTime]::Today

#Sets the deadline for when computers should have last changed their password by.
$Deadline = $Date.AddDays(-365)   

#Makes the date string for file naming
$FileName = [string]$Date.month + [string]$Date.day + [string]$Date.year 


#Generates a list of computer accounts that are enabled and aren't in the Encrypted Computers OU, but haven't set their password since $Deadline
$OldList = Get-ADComputer -Filter {(PasswordLastSet -le $Deadline) -and (Enabled -eq $TRUE)} -Properties PasswordLastSet -ResultSetSize $NULL |
Where {$_.DistinguishedName -notlike "*Encrypted Laptops*"} | 
Sort-Object -property Name | FT Name,PasswordLastSet,Enabled -auto 

#Generates a list of computer accounts that are disabled and sorts by name.
$DisabledList = Get-ADComputer -Filter {(Enabled -eq $FALSE)} -Properties PasswordLastSet -ResultSetSize $null | 
Sort-Object -property Name | FT Name,PasswordLastSet,Enabled -auto

#Creates the two files, assuming they are not $NULL. If they are $NULL, the file will not be created.
if ($OldList -ne $NULL) {
    Out-File "C:\users\marra\desktop\Old$Filename.txt" -InputObject $OldList
}

if ($DisabledList -ne $NULL) {
    Out-File "C:\users\marra\desktop\Disabled$Filename.txt" -InputObject $DisabledList
}
MDMarra
  • 100,734
  • 32
  • 197
  • 329
0

A million thank you's! I wanted to add my tweak to this. I needed to find only servers that have either been disabled or not disabled and not in production. This is what I came up with and it seemed to work.

Import-Module ActiveDirectory

$Date = [DateTime]::Today

#Sets the deadline for when computers should have last changed their password by.
$Deadline = $Date.AddDays(-365)   

#Makes the date string for file naming
$FileName = [string]$Date.month + [string]$Date.day + [string]$Date.year 

#Generates a list of computer server accounts that are enabled, but haven't set their password since $Deadline
$OldList = Get-ADComputer -Filter {(PasswordLastSet -le $Deadline) -and (Enabled -eq $TRUE) -and (OperatingSystem -Like "Windows *Server*")} -Properties PasswordLastSet -ResultSetSize $NULL |
Sort-Object -property Name | FT Name,PasswordLastSet,Enabled -auto 

#Generates a list of computer server accounts that are disabled and sorts by name.
$DisabledList = Get-ADComputer -Filter {(Enabled -eq $FALSE) -and (OperatingSystem -Like "Windows *Server*")} -Properties PasswordLastSet -ResultSetSize $null | 
Sort-Object -property Name | FT Name,PasswordLastSet,Enabled -auto

#Creates the two files, assuming they are not $NULL. If they are $NULL, the file will not be created.
if ($OldList -ne $NULL) {
    Out-File "C:\temp\Old$Filename.txt" -InputObject $OldList
}

if ($DisabledList -ne $NULL) {
    Out-File "C:\temp\Disabled$Filename.txt" -InputObject $DisabledList
} 
Mark Henderson
  • 68,823
  • 31
  • 180
  • 259
Geekgal
  • 11
  • 2
0

I know the OP clearly asked for PowerShell but if you don't like it, don't have it, and don't want to learn yet another Microsoft syntax then the following Python snippet will give you a date in the correct format to use with an LDAP query.

import datetime, time
def w32todatetime(w32):
    return datetime.fromtimestamp((w32/10000000) - 11644473600)
def datetimetow32(dt):
    return int((time.mktime(dt.timetuple()) + 11644473600) * 10000000)

90daysago = datetime.datetime.now() - datetime.timedelta(days=90)
print datetimetow32(90daysago)

Which could then be used as follows to find all Windows computers which haven't changed their passwords in the last 90 days.

(&(objectCategory=computer)(objectClass=computer)(operatingSystem=Windows*)(pwdLastSet<=130604356890000000))

You probably only need 30 as the default period for Windows machines to change their password is 30 days but 90 seems safer in case you forgot about that PC which is sat underneath Bob's desk and never gets turned on.

EDIT: Oh also I've omitted time-zone support in this which probably doesn't matter in this use case but may in others.

Samuel Harmer
  • 294
  • 3
  • 9