7

I am trying to do a PowerShell search of AD to find computers only (not servers or others) that have been logged into within the last 30 days. I have most of the script written except for the limiting of 30 days part. Any help would be greatly appreciated.

Get-ADComputer -Filter * -Properties * | FT Name, OperatingSystem, LastLogonDate -Autosize | Out-File C:\Temp\ComputerLastLogonDate.csv

1
  • Please clarify the question or what it is you are trying to accomplish. Are you trying to find the last logon time of the AD computer account? Or the last time a user logged into the computer? Your PowerShell command suggests the former, but your statement suggests the latter. The solution would be completely different for each scenario.
    – twconnell
    Oct 5, 2017 at 9:09

4 Answers 4

15

Get-ADComputer -Filter * -Properties *

Only get the properties that you intend to use... it's more efficient. Retrieving all the properties of all computers in the domain when you don't really need all the properties is unnecessarily demanding on your domain controller. It's wasteful.

Get-ADComputer -Filter * -Properties OperatingSystem, LastLogonDate is better, since you don't need all the properties. (The 'Name' property is always included.)

| FT Name, OperatingSystem, LastLogonDate -Autosize

Don't format output until the very end. In other words, Format-Table and Format-List should be the very final cmdlets in the entire chain of cmdlets that data is piped to.

Get-ADComputer -Filter * -Properties OperatingSystem, LastLogonDate | Where { $_.LastLogonDate -GT (Get-Date).AddDays(-30) }

This is a little better, but there's still some inefficiency, since you are still retrieving a data set of all computers... you could let the domain controller do the filtering for you.

$LastMonth = $(((Get-Date).AddDays(-30)).ToFileTime())

Get-ADComputer -LDAPFilter "(lastLogonTimeStamp>=$LastMonth)" -Properties OperatingSystem,LastLogonDate

The reason why I used the lastLogonTimeStamp there (which is a "file time," not a .NET DateTime,) is because "LastLogonDate" is not a real LDAP attribute. LastLogonDate is simply PowerShell's helpful way of automatically converting the lastLogonTimestamp attribute for you. lastLogonTimestamp is the "real" LDAP attribute.

Allowing the domain controller to return a filtered set to you, instead of the full set of ALL computers, means there is less data going over the wire and less data for PowerShell to process.

Also note that you are going to have to deal with computers that:

  • Have a (null) LastLogonDate
  • Have a LastLogonDate of 1/1/1601, or the beginning of the epoch.
3
  • So I would do something along the lines of. Get-ADComputer -Filter * -Properties OperatingSystem, LastLogonDate | Where { $_.LastLogonDate -GT (Get-Date).AddDays(-30) } | FT Name, OperatingSystem, LastLogonDate How than with this would I limit it to just computers and not servers as well?
    – Norrec
    Oct 4, 2017 at 15:17
  • If you need to filter on OperatingSystem then add that inside the brackets of the Where clause... "-AND $_.OperatingSystem -Like 'Server'" etc. etc.
    – Ryan Ries
    Oct 4, 2017 at 15:24
  • so would this be the correct way? The only issue I seem to be getting is I can not figure out how to get it to look at the DC's and pull the time of the most recent for every machine. 'floobits.com/PoshCode/PowerShell.Slack.com/file/…'
    – Norrec
    Oct 16, 2017 at 18:38
2

Your command doesn't filter for only workstations at all.

You need to use the LastLogonTimeStamp field so that you can easily filter on it then convert it to a DateTime for export.

This information is also readily available online. Like this example here, that I slightly modified to return only workstations. Notice they query only the properties needed. It is more efficient. Also, I have no idea why they have a $domain variable in this script. It appears completely useless.

# Gets time stamps for all computers in the domain that have NOT logged in since after specified date 
# Mod by Tilo 2013-08-27 
import-module activedirectory  
$domain = "domain.mydom.com"  
$DaysInactive = 90  
$time = (Get-Date).Adddays(-($DaysInactive)) 

# Get all AD computers with lastLogonTimestamp less than our time 
Get-ADComputer -Filter {LastLogonTimeStamp -lt $time -and OperatingSystem -notlike "*server*"} -Properties LastLogonTimeStamp,OperatingSystem | 

# Output hostname and lastLogonTimestamp into CSV 
select-object Name,@{Name="Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}} | export-csv OLD_Computer.csv -notypeinformation

Referenced from here: https://gallery.technet.microsoft.com/scriptcenter/Get-Inactive-Computer-in-54feafde

Also see the following references in regard to this:

The LastLogonTimeStamp attribute / what it was designed for

Converting TimeStamp to DateTime

0

This should get you started in the direction you want to go..

Get-ADComputer -Properties * -Filter {
     Enabled -eq $True -and
     OperatingSystem -like 'Windows*' -and
     OperatingSystem -notlike "Windows Server*" -and
     OperatingSystem -notlike "Windows 7*"
} -SearchBase "DC=hhmtx,DC=org" | FT Name, OperatingSystem, LastLogonDate -Autosize | Out-File C:\Temp\ComputerLastLogonDate.csv
0

Keep in mind that LastLogonDate is a converted version of LastLogonTimeStamp. LastLogonTimeStamp is not the most accurate representation of actual computer last logon time. By default, it could be off by 14 days. More info - https://social.technet.microsoft.com/wiki/contents/articles/22461.understanding-the-ad-account-attributes-lastlogon-lastlogontimestamp-and-lastlogondate.aspx

If you want to get more precise last logon time you have to use lastLogon attribute, but it is not replicated to all domain controllers so you have to iterate all your domain controllers to get the latest value. You have to calculate the last logon time and only then you can limit it to "last 30/60/90 days".

Here you can find example how this algorithm is realized for getting user's last logon time:

Import-Module ActiveDirectory

function Get-ADUserLastLogon([string]$userName)
{
$dcs = Get-ADDomainController -Filter {Name -like "*"}
$time = 0
foreach($dc in $dcs)
{
$hostname = $dc.HostName
$user = Get-ADUser $userName | Get-ADObject -Properties lastLogon
if($user.LastLogon -gt $time)
{
$time = $user.LastLogon
}
}
$dt = [DateTime]::FromFileTime($time)
Write-Host $username "last logged on at:" $dt }
Get-ADUserLastLogon -UserName username

There are alternative ways to get the same result easier and faster. You can try active directory reporting tool - AD FastReporter Free. It will do the precise last logon calculation for you. Just install it, go to Computers tab and select - "Computers who logged on last 30 days", press Generate. The result will include DC servers too, but you can easily remove them after export to .csv, .xlsx files. P.S. I am the owner and developer of this tool.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .