The Active Directory administrator must periodically find and disable inactivate objects in AD. In this article, we will show how to get the last logon time for the AD domain user and find accounts that have been inactive for more than 90 days.
[ez-toc]
How to Get a User’s Last Logon Time Using ADUC?
You can find the domain user’s last logon time with the Active Directory snap-in (ADUC) graphical console (Active Directory Users and Computers):
- Run the console dsa.msc;
- In the top menu, enable the option View > Advanced Features;
- Find the user in the AD tree and open its properties;
- Click on the tab Attribute Editor;
- In the list of attributes, find lastLogon. This attribute contains the time the user was last logged in to the domain.
Note. You can see two similar attributes on the screenshot above — lastLogon and lastLogonTimestamp. What’s the difference between them?
- lastLogon attribute is updated when the user logs on to the domain. But it only changes on the domain controller that authenticated the user and is not replicated to other domain controllers. Therefore, if there are multiple domain controllers at different Active Directory sites and subnets, you will have to check this attribute on each of them and then compare the resulting data. The value of this attribute on different DCs for the user can be different or even zero (if the user has never been authenticated on this DC);
- lastLogonTimeStamp attribute is also changed when the user logs on to the domain controller and is replicated to other DCs. However, replication of this attribute takes a long time (this attribute is replicated only if its value is 14 days or older than the previous one). Therefore, the data in this attribute on a specific DC may not be relevant.
Starting with the AD schema version (check if you need to update Active directory schema) in Windows Server 2008 (AD Schema objectVersion = 44), you can use several alternate login-related attributes:
- msDS-LastFailedInteractiveLogonTime — time of the last failed login attempt;
- msDS-LastSuccessfulInteractiveLogonTime — the time of the last successful login attempt.
These attributes are normally replicated between AD domain controllers and can be used to track user interactive logon attempts. However, they are enabled by default (do not collect any data on user properties).
To enable these attributes, you need to enable the GPO option Provide information about previous logons to client computers for domain controllers (Computer Configuration > Administrative Templates > System > KDC). Create a GPO with this parameter and assign it to the Domain Controllers container.
You can use LDAP query to display a list of users who have not logged into the domain for a long time in the Active Directory graphical console.
- First, you need to convert the date you need to the ToFileTime format. For example, if you want to find users who haven’t logged in to a domain for more than 90 days, you can get that date’s value with a simple PowerShell command:
(Get-Date).AddDays(-90).ToFileTime()
- In our example, the date (Saturday, June 4, 2022 9:56:23 AM) is converted to the value:
132988354159396418
- Substitute your FileTimeDate value into the next LDAP query:
(&(objectCategory=person)(objectClass=user)(lastLogon<=FileTimeDate))
- Open the ADUC console, right-click on the Saved Queries node and select New > Query;
- Specify the name of your query and click the Define Query button;
- Select Custom Search from the drop-down list and go to the Advanced tab;
- Copy your code to the Enter LDAP Query field;
- Save your query by clicking OK > OK;
- Select your query in Saved Queries and press F5 to refresh the object list. As a result, a flat list of users who have not logged into the domain for more than 90 days will appear in the ADUC console.
- You can disable or remove inactive domain user accounts directly from the Active Directory console.
Find Last Logon Time Using CMD
You can find out the time the user last logged into the domain from the command line using the net or dsquery tools.
Open a command prompt (you don’t need domain administrator privileges to get AD user info), and run the command:
net user administrator /domain| findstr "Last"
You got the user’s last logon time: 08.08.2019 11:14:13.
If you want to get the last login time of a local user, you need to remove the /domain parameter:
net user User | findstr "Last"
You can also get the last logon time using dsquery. For example:
dsquery * domainroot -filter "(&(objectCategory=Person)(objectClass=User)(sAMAccountName=administrator))" -attr distinguishedName lastLogon lastLogonTimestamp -limit 0
The main problem is that the attributes lastLogon and lastLogonTimestamp are stored in timestamp format in AD, and you need to additionally convert it to a normal time format.
You can also use this command to find all users who are inactive, for example, for 10 weeks:
dsquery user domainroot -inactive 10
Find Last Logon Time Using PowerShell
You can also use PowerShell to get the user’s last domain logon time. For this, you need to use the PowerShell Active Directory module. Install this module and import it into your PowerShell session:
Import-Module ActiveDirectory
To find the last logon time for the domain administrator account, run the command:
Get-ADUser -Identity administrator -Properties LastLogon
The cmdlet returned the time in Timestamp format. To convert it to a normal time, use the following command:
Get-ADUser -Filter {Name -eq "administrator"} -Properties * | Select-Object Name, @{N='LastLogon'; E={[DateTime]::FromFileTime($_.LastLogon)}}
Using PowerShell, you can display the last logon time for all enabled domain users:
Get-ADUser -filter {enabled -eq $true} -Properties * | Select-Object Name, @{N='LastLogon'; E={[DateTime]::FromFileTime($_.LastLogon)}}|Sort-Object LastLogon -Descending
Or you can find users who are inactive for more than 90 days:
$date1= (Get-Date).AddDays(-90) Get-ADUser -Properties LastLogonDate -Filter {LastLogonDate -lt $date1} | ft
After identifying inactive accounts, we recommend you disable those users’ accounts, wait a few weeks, and then delete the accounts if no problems have been reported. You can disable inactive users using the Disable-ADAccount cmdlet:
Get-ADUser -Properties LastLogonDate -Filter {LastLogonDate -lt $date1} | Disable-ADAccount
Similarly, you can get the last logon time for computer objects in a domain. The following command will list all computers that have been inactive for more than 90 days:
Get-ADComputer -Properties LastLogonDate -Filter {LastLogonDate -lt $date1} | Sort LastLogonDate | FT Name, LastLogonDate -Autosize
Hint. You can get the detailed user login history only from the security event logs of domain controllers.
You can also use the Search-ADAccount cmdlet to search for inactive users and computers. To do this, use the -AccountInactive [-DateTime DateTime] [-TimeSpan TimeSpan] parameter:
$timespan = New-Timespan –Days 90 Search-ADAccount –UsersOnly –AccountInactive –TimeSpan $timespan | ?{$_.Enabled –eq $True}
You can use this cmdlet to search for inactive users (-UsersOnly parameter) or computers (-ComputersOnly):
Search-ADAccount -AccountInactive -ComputersOnly -DateTime ‘1/1/2022’|Select Name,LastLogonDate | Export-Csv "c:\ps\incative_computers.csv"
In the last example, we exported the list of inactive computers to a CSV file.
Get Last Logon for User across All Domain Controllers
As we said earlier, if there are several domain controllers in your domain, then the lastlogon value on them may differ. If a user has been inactive for more than 14 days, the easiest way is to get the value of the lastLogonTimeStamp attribute from any domain controller. However, if you don’t know which site or DC the user was last authenticated on, you will have to query all domain controllers in the AD to get the user’s last logon date.
The following PowerShell script loops through all domain controllers in the domain and gets the value of the lastLogonTime attribute from each of them. The result is exported to a CSV file:
$userlogonname='bjackson' $csvoutputfile='c:\ps\lastlogon_from_all_dcs.csv' $resultlogonhistory=@() Import-Module ActiveDirectory $DCs=(Get-ADDomainController -Filter *).Name foreach ($DC in $DCs) { Try { $aduser=Get-ADUser $userlogonname -Server $DC -Properties lastlogon -ErrorAction Stop $resultlogonhistory +=New-Object -TypeName PSObject -Property ([ordered]@{ 'User' = $userlogonname 'DC' = $dc 'LastLogon' = [datetime]::FromFileTime($aduser.'lastLogon') }) } Catch { Write-host "Can’t connect DC $($dc)!" } } $resultlogonhistory|Export-CSV -path $csvoutputfile -NoTypeInformation -Delimiter "," -Encoding UTF8
If you need to quickly find the maximum user LastLogon value from all DCs, use the following one-liner:
[datetime]::FromFileTime((Get-ADDomainController -Filter * | foreach {Get-ADUser 'bjackson' -Properties LastLogon -Server $_.Name | select LastLogon} | Measure-Object -Property LastLogon -Maximum).Maximum)