Find Computers Not Logged In for 30 Days Using PowerShell

To find computers not logged in for 30 days with PowerShell, run Search-ADAccount with -AccountInactive, -ComputersOnly and a 30-day time span:

Search-ADAccount -AccountInactive -ComputersOnly -TimeSpan 30.00:00:00 |
    Where-Object Enabled |
    Select-Object -Property Name, LastLogonDate

It needs the ActiveDirectory module. Below I set that up, show the Get-ADComputer alternative, explain why the dates can be off by up to two weeks, and cover Microsoft Entra ID devices.

My test PC isn’t on a domain, so I ran the filtering and date logic on sample computers, with today set to October 4, 2026. The AD commands are shown as code.

Install the ActiveDirectory module

The module comes with RSAT, the Remote Server Administration Tools. Check whether you have it:

"ActiveDirectory module installed: $([bool](Get-Module -ListAvailable -Name ActiveDirectory))"

Output:

ActiveDirectory module installed: False
PowerShell check ActiveDirectory module installed
The AD module isn’t on this PC yet (PowerShell 7)

On Windows 11, install it as an optional feature from an elevated window:

Add-WindowsCapability -Online -Name 'Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0'

Domain controllers already have it. For other features, see listing Windows features with PowerShell.

Find inactive computers with Search-ADAccount

-TimeSpan 30.00:00:00 means 30 days, 0 hours. Search-ADAccount compares it with each computer’s last logon and returns the ones that haven’t signed in since:

$inactive = Search-ADAccount -AccountInactive -ComputersOnly -TimeSpan 30.00:00:00 |
    Where-Object Enabled
$inactive | Sort-Object -Property LastLogonDate | Select-Object -Property Name, LastLogonDate, DistinguishedName

Where-Object Enabled skips computers that are already disabled. Add -SearchBase ‘OU=Workstations,DC=contoso,DC=com’ to search one OU. More filters are in PowerShell Where-Object.

Use Get-ADComputer for more control

Get-ADComputer lets you choose the properties and filter on the server, which is faster in large domains:

$cutoff = (Get-Date).AddDays(-30)
Get-ADComputer -Filter 'Enabled -eq $true -and LastLogonDate -lt $cutoff' -Properties LastLogonDate, OperatingSystem |
    Select-Object -Property Name, LastLogonDate, OperatingSystem

Computers that never signed in have no LastLogonDate, so this filter misses them. The next section shows how to include them. To see where a computer sits, see finding a computer’s OU.

The filtering logic, tested on sample data

These sample objects have the same properties Get-ADComputer returns. The filter keeps enabled computers that were last seen before the cutoff, or never seen at all:

$today = Get-Date -Date '2026-10-04'
$computers = @(
    [pscustomobject]@{ Name = 'NYC-PC014'; Enabled = $true;  LastLogonDate = [datetime]'2026-10-01 14:20' }
    [pscustomobject]@{ Name = 'DAL-PC022'; Enabled = $true;  LastLogonDate = [datetime]'2026-08-20 09:05' }
    [pscustomobject]@{ Name = 'SEA-PC031'; Enabled = $true;  LastLogonDate = [datetime]'2026-07-02 16:45' }
    [pscustomobject]@{ Name = 'NYC-PC040'; Enabled = $false; LastLogonDate = [datetime]'2026-05-11 08:30' }
    [pscustomobject]@{ Name = 'LAB-PC007'; Enabled = $true;  LastLogonDate = $null }
)

$cutoff = $today.AddDays(-30)
$computers |
    Where-Object { $_.Enabled -and ($null -eq $_.LastLogonDate -or $_.LastLogonDate -lt $cutoff) } |
    Select-Object -Property Name,
        @{ Name = 'LastLogon';    Expression = { if ($_.LastLogonDate) { $_.LastLogonDate.ToString('yyyy-MM-dd') } else { 'Never' } } },
        @{ Name = 'DaysInactive'; Expression = { if ($_.LastLogonDate) { ($today - $_.LastLogonDate).Days } else { '-' } } }

Output:

Name      LastLogon  DaysInactive
----      ---------  ------------
DAL-PC022 2026-08-20           44
SEA-PC031 2026-07-02           93
LAB-PC007 Never                 -
PowerShell find computers not logged in for 30 days
Two stale computers and one that never signed in (PowerShell 7)

NYC-PC014 signed in three days ago, and NYC-PC040 is already disabled, so both are left out. LAB-PC007 has never signed in, which often means it was set up and never used. The cutoff works like any date comparison.

Why LastLogonDate can be two weeks behind

LastLogonDate comes from the lastLogonTimestamp attribute. Domain controllers only update it when the stored value is older than a sync interval, so it can lag behind the real last logon by up to about two weeks.

That’s on purpose, to keep replication traffic low. Use 45 or 60 days for cleanup jobs, not exactly 30.

Convert the raw lastLogonTimestamp

If you read the raw attribute, it’s a FILETIME number. Convert it with FromFileTimeUtc:

$raw = 134353380000000000, 134316903000000000, 134274843000000000
foreach ($value in $raw) {
    [datetime]::FromFileTimeUtc($value).ToString('yyyy-MM-dd HH:mm') + ' UTC'
}

Output:

2026-10-01 14:20 UTC
2026-08-20 09:05 UTC
2026-07-02 16:45 UTC
PowerShell convert lastLogonTimestamp to a date
Raw lastLogonTimestamp values as UTC dates (Windows PowerShell 5.1)

LastLogonDate is the same value already converted for you. For other date tricks, see checking password expiration dates.

Export a report and disable stale computers

Send the list to CSV for review first, as shown in PowerShell Expor