PowerShell AD Query: Find Computers in Active Directory

How many Windows 10 machines remain in your domain before the end-of-life deadline? Which computers in the Servers OU have not checked in for 90 days and might be decommissioned candidates? These are questions that take minutes to answer with PowerShell active directory computers queries using Get-ADComputer. This post covers filtering by OS version, OU scope, last logon date, identifying stale accounts, and exporting a full computer inventory to CSV for hardware refresh planning.
Get All Computers in AD
Import the Active Directory module and retrieve all computer objects. Be explicit about which properties you need — not all properties are returned by default:
Import-Module ActiveDirectory
# Basic computer list
Get-ADComputer -Filter * | Select-Object Name, DNSHostName, Enabled | Format-Table -AutoSize
# Count computers by enabled status
Get-ADComputer -Filter * | Group-Object Enabled | Select-Object Name, Count
Name Count
---- -----
True 1842
False 93
Filter by Operating System
Use the -Filter parameter with LDAP-style attribute queries, or -LDAPFilter for complex filters. Combine with -Properties to return the OS attributes:
# Find Windows 10 computers
Get-ADComputer -Filter { OperatingSystem -like "*Windows 10*" } `
-Properties OperatingSystem, OperatingSystemVersion |
Select-Object Name, OperatingSystem, OperatingSystemVersion |
Sort-Object Name
# Count by OS version — upgrade planning dashboard
Get-ADComputer -Filter * -Properties OperatingSystem |
Group-Object OperatingSystem |
Select-Object Count, Name |
Sort-Object Count -Descending |
Format-Table -AutoSize
Count Name
----- ----
1234 Windows 10 Enterprise
421 Windows 11 Enterprise
187 Windows Server 2019 Standard
Get Computers in a Specific OU
Use -SearchBase with the OU’s distinguished name to scope the query. Use -SearchScope Subtree (default) for all nested OUs, or OneLevel for direct children only:
$ou = "OU=Servers,OU=Corporate,DC=corp,DC=local"
Get-ADComputer -Filter * -SearchBase $ou -SearchScope Subtree `
-Properties OperatingSystem, OperatingSystemVersion, LastLogonDate |
Select-Object Name, OperatingSystem, LastLogonDate |
Sort-Object LastLogonDate -Descending
Find Stale Computer Accounts
Computers that have not authenticated against the domain for an extended period are candidates for cleanup. Use LastLogonDate (which is replicated) rather than LastLogon (which is not):
$cutoffDate = (Get-Date).AddDays(-90)
$staleComputers = Get-ADComputer -Filter { Enabled -eq $true } `
-Properties LastLogonDate, OperatingSystem |
Where-Object { $_.LastLogonDate -lt $cutoffDate -or $_.LastLogonDate -eq $null }
Write-Host "Stale computers (no logon in 90+ days): $($staleComputers.Count)"
$staleComputers | Select-Object Name, LastLogonDate, OperatingSystem |
Sort-Object LastLogonDate | Format-Table -AutoSize
Get Computer Last Login
The most accurate last-logon time requires querying every domain controller and taking the most recent value. The LastLogonDate attribute is a replicated approximation (replicated every 14 days):
function Get-ComputerLastLogon {
param([string]$ComputerName)
$domainControllers = Get-ADDomainController -Filter *
$logonTimes = foreach ($dc in $domainControllers) {
$comp = Get-ADComputer -Identity $ComputerName -Server $dc.Hostname `
-Properties LastLogon -ErrorAction SilentlyContinue
if ($comp.LastLogon) {
[DateTime]::FromFileTime($comp.LastLogon)
}
}
$logonTimes | Sort-Object -Descending | Select-Object -First 1
}
$lastLogon = Get-ComputerLastLogon -ComputerName "PC001"
Write-Host "PC001 last authenticated: $lastLogon"
Export Computer Inventory to CSV
Build a comprehensive computer inventory report for asset management or upgrade planning:
$reportPath = "C:\Reports\ComputerInventory_$(Get-Date -Format 'yyyyMMdd').csv"
Get-ADComputer -Filter * -Properties Name, DNSHostName, OperatingSystem,
OperatingSystemVersion, LastLogonDate, Enabled, Description,
'msDS-LastSuccessfulInteractiveLogonTime' |
Select-Object Name, DNSHostName, OperatingSystem, OperatingSystemVersion,
LastLogonDate, Enabled, Description,
@{N='OU'; E={ ($_.DistinguishedName -split ',',2)[1] }} |
Export-Csv -Path $reportPath -NoTypeInformation
Write-Host "Inventory exported: $reportPath ($( (Import-Csv $reportPath).Count ) records)"
Common Errors and Fixes
-
Properties like OperatingSystem not returned by default — use -Properties.
Get-ADComputer -Filter *only returns a subset of attributes by default (Name,DistinguishedName,Enabled, etc.). RequestingOperatingSystem,LastLogonDate, or any other attribute requires explicitly listing it in-Properties. Use-Properties *to return everything, but note this is much slower on large domains. -
LastLogonDate replication delay gives stale results.
LastLogonDateis replicated across DCs every 14 days by default, so a computer that logged in yesterday may show a logon date from two weeks ago. For accurate last-logon data, query all domain controllers and take the maximum value as shown in theGet-ComputerLastLogonfunction above.
Related Cmdlets / See Also
Wrapping Up
Get-ADComputer with targeted -Filter expressions and explicit -Properties lists is your tool for AD computer inventory, stale account cleanup, and OS-based upgrade planning. Always request only the properties you need for performance, use LastLogonDate for day-to-day checks, and query all DCs for precise last-authentication times.


