You can leverage PowerShell to get last logon information such as the last successful or failed interactive logon timestamps and the number of failed interactive logons of users to Active Directory. In this post, I explain a couple of examples for the Get-ADUser cmdlet.
Latest posts by Michael Pietroforte (see all)

In a previous post, I explained how you can enable interactive logon logging in Active Directory. Today, I’ll show you how to use PowerShell to retrieve the information from the corresponding Active Directory attributes.

If you want to try the examples in this article on your desktop, you’ll have to install the Active Directory module for Windows PowerShell. This module is already available on every domain controller in an Active Directory domain with a functional level of Windows Server 2008 R2 or higher.

Note that I will only discuss the last interactive logon attributes in this article. However, you can also use the examples in this post for the lastLogon and lastLogontimeStamp attributes, which are useful for listing inactive accounts if you replace the attributes in the commands accordingly.

As discussed in my previous article, you can use the interactive logon attributes for gathering real-time information about the last successful (msDS-LastSuccessfulInteractiveLogonTime) and unsuccessful (msDS-LastFailedInteractiveLogonTime) user logon times. In addition, you can retrieve the number of failed logons (msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon) of a user account since the last successful logon, as well as the failed logons since the feature was enabled (msDS-FailedInteractiveLogonCount).

Note: After I finished this post, I noticed that the msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon attribute does not store the correct value. Even though the information is correctly displayed on the logon screen, msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon always has the same value as msDS-FailedInteractiveLogonCount. This appears to be a bug in Windows Server 2012 R2. It is not a PowerShell issue because I also see the wrong values in ADUC. Please let me know if you get the same results in your tests.

The cmdlet we need to gather the information is Get-ADUser, which enables you to query information about Active Directory user objects. The easiest case would be if you want to know the number of failed logons since the last successful logon for a particular user. For example:

Get-ADUser -Filter {Name -eq "Administrator"} -Properties * | Select-Object Name, msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon

The number of failed logons since the last successful logon for a particular user

You can use the Filter parameter to search for user objects that have a certain attribute value. In the example, we restrict the output to the Administrator account. The Properties parameter is required because the interactive logon attributes are not included in the default set of properties (attributes) that the Get-ADUser cmdlet retrieves. By using the asterisk, we display all of the attributes that are set on the user object. We then pipe the output to the Select-Object cmdlet, which restricts the output to the name of the user account and the number of failed logons at the last successful logon.

If you want to find out what account logout threshold you should configure in your network, you could create a list that is sorted according to the number of failed logons at the last successful logon:

Get-ADUser -Filter * -Properties * | Select-Object Name, msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon | Sort-Object -Descending msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon

The number of failed logons since the last successful logon

If you run the above command every day for a week or so, you will get a feeling for how often users mistype their passwords.

Or perhaps you just want to know how many of your users would fall prey to your account logout threshold. The command below counts the number of users who mistyped their password more than three times since the last successful logon:

Get-ADUser -Filter * -Properties * | Where-Object msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon -gt 3 | Measure-Object | Select-Object Count

The number of users who mistyped their password more than three times since the last successful logon.

Things get a bit trickier if you want to know the time of the last failed logon. The problem is that the attribute stores this information in the Windows file time format, a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601. If you don’t happen to be Rain Man, you have to let the computer convert the value into a human-readable format. For this, we use the .NET method DateTime.FromFileTime, which converts the Windows file time to an equivalent local time. This is how you could display the last failed interactive logon time for the Administrator account:

Get-ADUser -Filter {Name -eq "Administrator"} -Properties * | Select-Object Name, @{Name="Last failed logon time";Expression={[datetime]::FromFileTime($_.'msDS-LastFailedInteractiveLogonTime')}}

The last failed interactive logon time for the Administrator account

The @{} syntax creates a hash table, which is just a collection of key-value pairs. In our case, we have two pairs: the Name key, which has the value “Last failed logon time,” and the Expression key, for which we calculate the value with the above-mentioned .NET method. “$_” stands for the user object that we pipe to the Select-Object cmdlet. We use this hash table as a calculated property that allows us to select the property and convert it into a human-readable format.

If you suspect that someone is trying to hack accounts in your network by guessing passwords, you might want to create a list of all user accounts with all four interactive logon attributes. If you notice that some accounts have unusually high numbers of failed logons since you activated the feature, but those accounts were never locked, someone might be aware of your password account threshold and patiently tries just a few passwords every day. Of course, another explanation would be that your users really need new keyboards. 😉

Get-ADUser -Filter * -Properties * | Select-Object -Property Name, @{Name="Total failed logons";Expression="msDS-FailedInteractiveLogonCount"}, @{Name="Recent failed logons";Expression="msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon"}, @{"Name"="Last failed logon";Expression={[datetime]::FromFileTime($_.'msDS-LastFailedInteractiveLogonTime')}}, @{"Name"="Last successful logon";Expression={[datetime]::FromFileTime($_.'msDS-LastSuccessfulInteractiveLogonTime')}} | Sort-Object Name | Format-Table

List of all users with all their interactive logon attributes

If you see “31/12/1600” as a date, it doesn’t mean that one of your users possesses a time machine. This user just never logged in interactively.

Another piece of interesting information could be the time difference between the last successful logon and the last unsuccessful one.

foreach ($User in Get-ADUser -Filter * -Properties *)
    $TimeSpan = "{0:dd\:hh\:mm\:ss}" -f ([timespan]::fromticks($User.'msDS-LastSuccessfulInteractiveLogonTime' - $User.'msDS-LastFailedInteractiveLogonTime'))
    $LastFailedLogon= [datetime]::FromFileTime($User.'msDS-LastFailedInteractiveLogonTime')
    $LastSuccessfulLogon= [datetime]::FromFileTime($User.'msDS-LastSuccessfulInteractiveLogonTime')   
    @{"User" = $User.Name; "Last failed logon" = $LastFailedLogon; "Last successfull logon" = $LastSuccessfulLogon; "Time span" = $TimeSpan }.GetEnumerator() | Sort -Descending -Property Name | Format-Table

The time difference between the last successful logon and the last unsuccessful one

The first line calculates the time difference using a .NET function and then formats the value in human-readable format (days, hours, minutes, seconds). In the last line, we again use a hash table to display the result. We need the GetEnumerator() method so we can sort our hash table.

Please let me know if you could confirm the bug regarding the failed logon counts I mentioned above.

  1. Avatar

    All I got for results were { }. Maybe it’s because I’m still running 2000 Native?

  2. Avatar

    Marc, are you serious? Domain functional level Windows 2000 native? You are telling me that you didn’t upgrade your Active Directory in 15 years? You need functional level Windows Server 2008 R2 or higher and you have to enable the feature first with Group Policy.

  3. Avatar

    Michael, boy do I feel sheepish! In my defence, I’ve only been here for 7 years (and a sysadmin for 3)… It’s actually on my project plan this year! Still trying to decide on whether or not to virtualize the DC’s. If going physical and we can get some new hardware I’d like to do 2012 but if not then 2008 R2.

  4. Avatar

    Marc, don’t move to 2008 R2. This is yesterday’s technology. If you are going to virtualize your domain controllers you will want to have latest OS that is adapted to this environment.

  5. Avatar


    Is there anywhere I can ask you a few questions other than these comments?

  6. Avatar

    Marc, you can ask questions in the forum.

  7. Avatar
    Adam Hamilton 9 years ago

    It would be better to retrieve only the 2 extra properties you need rather than all of them. In a large AD environment performance could be awful.

  8. Avatar

    Adam, that’s a good point!

  9. Avatar
    matt 9 years ago

    I got all dates as 12/31/1600 and i’m on DFL 08 R2…strange stuff.

  10. Avatar
    Nick 8 years ago

    I too got all dates as 12/31/1600 and i’m on DFL 2012.

  11. Avatar
    Peter 8 years ago

    Same here – all showing 01/01/1601, DFL 2008R2



  12. Avatar
    Marcos Pinto 8 years ago

    This is what worked for me:

    Get-ADUser -Filter * -Properties * | Select-Object Name, @{Name=”Last Successful Logon”;Expression={[datetime]::FromFileTime($_.’lastLogonTimeStamp’)}} | Sort-Object “Last Successful Logon”

  13. Avatar
    lenin 7 years ago

    I also want to get who/which account made this logon. For example:

    Computer    Lastlogon            User                                                   
    --------    ------------------   ----                                                         
    DC1         6/06/2013 16:38:24   user2                                                
    DC2         6/06/2013 16:30:40   user1

  14. Avatar
    roarke christian 7 years ago

    I need to have 2  reports (csv or txt):

    one that includes “Active users” and their “last login date”

    another that included “de-active users” and their “last login date”.


    I know I can use “get-aduser -filter ‘enabled -eq $false’ to generate a listing in powershell, but that only shows users without last login date, and is not exported to (csv or txt).

  15. Avatar
    Anbu 6 years ago


  16. Avatar
    Mike Coleman 5 years ago

    Get-ADUser -Filter * -Properties * | Select-Object Name, @{Name=”Last Successful Logon”;Expression={[datetime]::FromFileTime($_.’lastLogonTimeStamp’)}} | Sort-Object “Last Successful Logon”  | Write-output c:\temp\lastloggedon.csv

    That is what worked for me to get all the last logons so I could see accounts that have not logged in for over a year so I could disable them.

  17. Avatar
    Tyson Cooper 4 years ago

    Hello Michael, This might be a dumb question, but since I can't seem to find the answer elsewhere I thought I would ask you directly. By means of background, I am analysing an estate with a massive amount of service accounts… and over time a lot of these have been used by IT staff to login interactively to the servers running the services the service accounts are being used for. Lazy practice and definitely not good security policy for sure…  but we are cleaning this up. We are now denying interactive logons via group policy but only after thorough investigation of each active service account. To summarise, when I pull the attribute msDS-LastSuccessfulInteractiveLogonTime, I am still seeing a very large number of my service accounts with a value being set every few minutes….  and this value is matching the 'LastLogon' attribute. It's as if 'Lastlogon' is being set as 'msDS-LastSuccessfulInteractiveLogonTime' as well. I've confirmed this isn't just in Powershell…  it's reflected in the ADUC Attribute Editor tab too for these accounts. And yes, I have confirmed there is literally no way all of these are in fact being used for interactive logons… in fact most are in the deny policy.

    So I guess the question from all of the above is…  what else OTHER than an actual interactive logon to the console or via RDP would result in the 'msDS-LastSuccessfulInteractiveLogonTime' attribute being set?

    • Avatar Author

      As far as I know, the attribute exactly stores the info that its name suggests. Maybe there is something wrong with your deny policy?

  18. Avatar
    Lee Andrews 3 years ago

    I tested your theory about the bug with ‘msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon’ and it’s not a bug, it just looks like one.  ‘msDS-FailedInteractiveLogonCount’ will always be the same as long as the user has succesfully logged on.  The logon screen is showing you the difference between the two attributes but as soon as you click OK AD updates the ‘msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon’ to the same value – you can see this by entering a bad password on a user object one or more times but DO NOT Logon – then you can use this powershell to see that the two attributes values are different.

    $properties = @(
    $outProperties = @(
     @{n='last interactive logon';e={if ( $([datetime]::FromFileTime($_.'msDS-LastSuccessfulInteractiveLogonTime')) -eq $(get-date '01/01/1601 00:00:00') ) { 'Never' } else { [datetime]::FromFileTime($_.'msDS-LastSuccessfulInteractiveLogonTime')}} }
     @{n='last failed logon';e={if ( $([datetime]::FromFileTime($_.'msDS-LastFailedInteractiveLogonTime')) -eq $(get-date '01/01/1601 00:00:00') ) { 'Never' } else { [datetime]::FromFileTime($_.'msDS-LastFailedInteractiveLogonTime')}} }
     #@{n='last failed logon';e={[datetime]::FromFileTime($_.'msDS-LastFailedInteractiveLogonTime')}}
     @{n='failed logon Count';e={$_.'msDS-FailedInteractiveLogonCount'}}
     @{n='failed logon Count since last succesfull logon';e={$_.'msDS-FailedInteractiveLogonCountAtLastSuccessfulLogon'}}
     @{n='Password expires';e={if ( $_.'msDS-UserPasswordExpiryTimeComputed' -eq '9223372036854775807' ) { 'Never' } else { [datetime]::FromFileTime($_.'msDS-UserPasswordExpiryTimeComputed')}} }
    $searchBase = 'OU=User Accounts,DC=YOUR,DC=DOMAIN,DC=HERE,DC=com'
    Get-ADUser  -Properties $properties  | select $outProperties  | ft

Leave a reply to Tyson Cooper Click here to cancel the reply

Please enclose code in pre tags: <pre></pre>

Your email address will not be published. Required fields are marked *


© 4sysops 2006 - 2023


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account