Monitoring Active Directory users is an essential task for system administrators and IT security. In many organizations, Active Directory is the only way you can authenticate and gain authorization to access resources. Some resources are not so, yet some are highly sensitive. Using PowerShell, we can build a report that allows us to monitor Active Directory activity across our environment.

To get started, let's first define what we mean by a "user activity report" because this could mean a few different things. For this article, I'm going to define this report as a way to find out the last time all Active Directory users logged in.

We first need to figure out merely how to pull the user login information for all users. One way to do this is to use the Active Directory module's Get-AdUser command. This command lets you query Active Directory users using different filtering methods. For this article, we'd like to query all Active Directory users who have logged in before. The LastLogonDate property is the best way to do this, but unfortunately, it does not replicate to all domain controllers (DCs). We'll need to pull this attribute from all of our DCs.

First, I'll query all DCs in my environment with Get-AdDomainController. The command below will return the fully qualified domain names (FQDNs) of every DC.

$dcs = Get-ADDomainController | Select-Object -ExpandProperty HostName

Next, I'll need to query each DC for every user who has a LastLogonDate. To do this, I'll use Get-AdUser and filter on users having a last logon date attribute.

$users = @()
foreach ($dc in $dcs) {
    $users += Get-ADUser -Filter "lastLogonDate -like '*'" -Properties LastLogonDate -Server $dc | Select-Object -Property samAccountName,LastLogonDate

Once I have all of the users with a last logon date, I can now build a report on this activity. I can create reports in PowerShell lots of different ways.

First, I can pipe the results of my query to the Out-GridView command. This returns an interactive GUI allowing you to sort, filter, and view results in many different ways.

$users | Out-GridView

Using Out-Gridview is nice, but it doesn't let you save the results. Another way to return this output is by creating a CSV file. We can output objects in PowerShell to a CSV file by using the Export-Csv command. Below I'm piping all the users I've queried to Export-Csv, which then creates a CSV file with each row containing the SamAccountName and LastLogonDate attributes for each user.

PS> $users | Export-Csv -Path 'C:\UserActivity.csv' -NoTypeInformation
PS> import-csv C:\UserActivity.csv

samaccountname lastlogondate
-------------- -------------
techsnips      3/21/2019 10:24:22 PM
jdoe           3/5/2019 6:43:07 PM
jjones         3/14/2019 8:27:20 AM
Microsoft.NET  3/19/2019 1:02:03 AM

Finally, we can return these results to an HTML file. Since we're working with HTML, we have an infinite number of ways to do this, but I've chosen to use an example of creating an HTML table.

$htmlHeader = @"
<!doctype html>
<html lang='en'>

$body = ""
foreach ($user in $users) {
    $body += "<tr><td>$($user.samAccountName)</td><td>$($user.LastLogonDate)</td></tr>"

$footer = "</tbody></table></body></html>"

$html = $htmlHeader + $body + $footer
$html | Out-File -FilePath 'C:\UserActivity.html' -Force

After running this code, you'll then get a nicely formatted HTML table.

Subscribe to 4sysops newsletter!

The HTML report

The HTML report

  1. Avatar
    Justin 5 years ago

    Put that script in Scheduled tasks, add a logo title, timestamp, CSS and you get something nice 🙂


  2. Avatar
    Justin 5 years ago

    Adam, I think there may be an issue with your second code snippet. You've created a foreach loop but are not referencing the $dc variable in the subsequent command. Did you mean to use the -Server parameter with $dc as the argument in the Get-ADUser cmdlet?

    • Avatar
      Bruce 5 years ago

      The first code snippet actually doesn't pull all the domain controllers in the domain.  It only pulls one DC and more specifically the DC that the account used to run the script.  To pull multiple, you'd have to use the  "-filter" variable to pull in others.  Pulling in other DCs is really not needed though, as the AD Database is replicated to each, and you'd just pull in duplicate data into your report. 

    • Avatar
      Jerry 5 years ago

      Actually, it doesn't matter as Get-ADDomainController only returns a single DC.  To get all of them, then you would need to do use:

      (Get-ADForest).Domains | Foreach-Object { Get-ADDomainController -Filter * -Server $_ } | Select-Object -ExpandProperty HostName

      And then user -Server $DC with Get-ADUser.

  3. Avatar
    Alan 5 years ago

    Bruce, I'm afraid you are in error. This is one of the few properties that AD does not replicate.  The lastlogondate property is unique per DC and indicates when a user last authenticated to that specific DC.  To get a true last logon you would need to query all DCs and sort and then select the most recent date.  Further, you would need error checking to ensure all DCs returned data or you risk a faulty return. Finally, if the last DC (or only DC) a user last logged into is removed from the domain at some time for any reason, the last login data is lost. So you can end up with no last logon data but a non-zero LogonCount (this property is replicated).

    Another property you might consider that is far more simple to work with, and is replicated, is lastlogontimestamp.  Since it is replicated it cannot be lost with a DC leaving the domain and can be checked on from any DC without needing to check all DCs and sort and select.  There is a drawback to using this property however.  It only updates if it is more than 14 days off from the most current LastLogon property recorded across all DCs in the domain.  That means it can be up to two weeks off from the actual last logon event!

    Trying to write a script to query all of your DCs and collating the LastLogon data to get the most accurate report possible can get rather involved. And if you have a lot of users and/or a lot of domain controllers the query can take a very long time depending on how you write it.  If you aren't a powershell guru, or just don't have the time, there are tools available that can do this work for you. Personally I have used Hyena and ManageEngine to great effect to produce last login data for SOX audits where we needed to be able to verify a user account was not used to log in after a termination.

    In short, this article is very short sighted and incomplete, as well as misleading.  It barely scratches the surface on the requirements of actually building a complete and useful last logon report that is accurate.  However, it does do well to introduce some of the fundamental capabilities of HTML report generation within powershell.  It really is a powerful shell.  🙂

    • Avatar

      Code example to compare the lastlogon LastLogonDate and lastlogonTimestamp properties:

      (Get-ADDomainController -Filter *).Name |
          ForEach-Object -Process {
              Get-ADUser -Identity JohnDo -Properties * -Server $_ |
                  Select-Object -Property name, lastlogon*


  4. Avatar
    Sudhir 5 years ago

    I think as well, the command for get-addomaincontroller does not return the list of all DC's i think, was trying to run and it does return on one, more information here:

  5. Avatar
    Leos Marek (Rank 4) 5 years ago

    Not that I want to advertise something, but Netwrix offers a free Active Directory auditing tool for that (plus other topics).

  6. Avatar Author

    Sorry about the code error. I've got it updated.

  7. Avatar
    Raymond 5 years ago

    Get-ADDomainController -Filter *
    would pull all of them easily, you might then want to invoke this across the DCs themselves to get it all back faster.

  8. Avatar
    Brad Allison 4 years ago

    This is great.  I am wondering if we can query not ALL users in the AD, but users that are in a security group.

    • Avatar
      Leos Marek (Rank 4) 4 years ago

      Sure you can. You just need to query the group first for its members and then query the results.

Leave a reply

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