Skip to main content desktop
Try Now

History of Logged on Users

Jordan HammondJordan Hammond

If you have read some of my blogs, you know how much I love PowerShell. If this is your first blog, HI! I am Jordan, and I love PowerShell! My love for it is why we are here today, PDQ has a new feature out that will allow you to create a custom scanner in Inventory using PowerShell. What does this mean for you? It means you can grab virtually any data that you could ever want. As always, with PowerShell, it is not about “can I”? But “how do I”? With that in mind, let’s break down a script we have in our GitHub for checking logged on user history. Watch the accompanying video to this blog post here.

Prep Work!

First, let’s get the caveats out of the way. This script uses the event log to track this, so if you have not enabled Audit Logon Events from Group Policy, you will need to. Without it, it will look at the events still, but chances are the data you want most has been overwritten already. DAMN YOU CIRCULAR LOGGING!!!!

Getting Logged on User History

I will break down some critical points in this, but Nate has done an excellent job with his comments. I will have the full script at the end, and it should answer any lingering questions. The base of this script is the Get-EventLog command. Logon eventID’s are 4624.

Get-EventLog -LogName "Security" -InstanceId 4624 -ErrorAction "SilentlyContinue"

This is going to grab a LOT of events, so step 2 of this is fine-tuning your results. In a foreach loop, you will need to grab the specific data you need: the account name that logged in and the logon type. Logon type is so you can remove any logon that is not a local or remote logon.

    $EventMessage = $_
    $AccountName = $EventMessage.ReplacementStrings[5]
    $LogonType = $EventMessage.ReplacementStrings[8]

Now that we have the data, and it is in a format we can use, it is time to remove what we don’t need. There is a bit of logic in there. First, we exclude all events that are not logon type 2 or 10 (Local and Remote) as well as all logons done with Windows Service Accounts. Then, we remove all duplicate entries. I do not care how often Bo Jangles logged in, just if he has or not. Finally, we put our results into a custom object where we can control our results format.

Username = $AccountName
LogonType = $LogonTypeName
LastLogon = $EventMessage.TimeGenerated.ToString("yyyy-MM-dd HH:mm:ss")

Putting it all Together

Now let’s see what the script looks like when we put it all together. Below is the complete script that we have been talking about. We highly recommend that if you are going to use it you get it from GIT and follow the steps in there so your scanner will remain up to date if changes are made. Iterate with Foreach-Object

# This script requires that Audit Logon events are enabled in Group Policy and those events are kept for the amount of history preferred

param (

$UserArray = New-Object System.Collections.ArrayList

# Query all logon events with id 4624 
Get-EventLog -LogName "Security" -InstanceId 4624 -ErrorAction "SilentlyContinue" | ForEach-Object {

    $EventMessage = $_
    $AccountName = $EventMessage.ReplacementStrings[5]
    $LogonType = $EventMessage.ReplacementStrings[8]

    if ( $Lowercase ) {

        # Make all usernames lowercase so they group properly in Inventory
        $AccountName = $AccountName.ToLower()


    # Look for events that contain local or remote logon events, while ignoring Windows service accounts
    if ( ( $LogonType -in "2", "10" ) -and ( $AccountName -notmatch "^(DWM|UMFD)-\d" ) ) {
        # Skip duplicate names
        if ( $UserArray -notcontains $AccountName ) {

            $null = $UserArray.Add($AccountName)
            # Translate the Logon Type
            if ( $LogonType -eq "2" ) {

                $LogonTypeName = "Local"

            } elseif ( $LogonType -eq "10" ) {

                $LogonTypeName = "Remote"


            # Build an object containing the Username, Logon Type, and Last Logon time
                Username = $AccountName
                LogonType = $LogonTypeName
                LastLogon = $EventMessage.TimeGenerated.ToString("yyyy-MM-dd HH:mm:ss")




This script is a great one to dive in and learn if you are getting into PowerShell. You don’t want to run any old script you got off the internet without knowing what is in it, so I highly recommend breaking this one down to understand what is going into it. If you are a PowerShell vet, take some time to appreciate how awesome Nate is, if you are new to PowerShell, take some time breaking this down and learning what he did and why. You will learn a lot about best practices if you do.

Ready to put the PowerShell Scanner through its paces?

Take our 14-day Free Trial. Feel the power of the PowerShell scanner.
Start a Trial

Don't miss the next post!

Press Release: PDQ Acquires SmartDeploy, a leading provider of IT asset management software, announced today its acquisition of SmartDeploy, an industry leader in remote computer management.
© 2022 Corporation
  • PDQ Deploy ®
  • PDQ Inventory ®
  • SimpleMDM
  • Pricing
  • Downloads
  • Licensing
  • Buy