Skip to content
ADMIN
FUTURE
Главная страница » Windows Login History: How to Check via PowerShell
FIELD NOTES / 28.09.2026

Windows Login History: How to Check via PowerShell

Maksim Shapovalov5 min read
Таймлайн событий входа в Windows по журналу Security: успешные и неудачные попытки

The conversation with the security team always starts the same way: “We need to know who logged into this server over the past week.” And that’s when it turns out there are two different questions that are easy to mix up. The first is “when did this user last actually work here” (for cleaning up old profiles). The second is “who logged in exactly when, including failed attempts” (for a real investigation). One quick trick answers the first question in a second. The second requires looking somewhere less pleasant — the Security log.

The quick way: the secret in NTUSER.DAT

If you need to know in five seconds which profiles on a server are actually “alive” and which haven’t been touched in six months, don’t open the event log. Every profile in C:Users has a hidden file called NTUSER.DAT — the user’s personal registry hive, where desktop settings, file associations, and dozens of other small things get written. Windows updates it when the user logs off, which means the file’s modification date is the moment their last session ended.

PowerShell

Get-ChildItem -Path C:Users -Force -Directory |
    Where-Object { $_.Name -notin "Public", "Default", "Default User" } |
    Select-Object @{Name="User"; Expression={$_.Name}},
                  @{Name="Last session ended"; Expression={
                      (Get-Item "$($_.FullName)NTUSER.DAT" -Force -ErrorAction SilentlyContinue).LastWriteTime
                  }} |
    Sort-Object "Last session ended" -Descending |
    Format-Table -AutoSize
User           Last session ended
----           -------------------
admin          10/7/2025 8:30:11 AM
d.ivanov       10/6/2025 6:15:45 PM
a.petrov       9/1/2025 12:00:22 PM

The most recently active users sit at the top. A great way to spot at a glance that a.petrov hasn’t logged in for a month, and decide whether that profile should be archived.

But the trick has a weak spot worth knowing before you take these numbers into an incident review: NTUSER.DAT sometimes gets updated by background profile processes even without a full interactive logon, and the file itself says nothing about where the login came from, or whether there were failed attempts. Great for cleaning up old profiles. Not enough for an investigation.

The reliable way: the Security log and event IDs 4624/4625

When the question is “who exactly, and when,” the only authoritative source is the Security log. Two event codes cover almost everything you need for a login audit:

  • 4624 — a successful logon. The event details include the logon type (2 = local, 3 = network, 10 = RDP) and, for network logons, the source IP address.
  • 4625 — a failed logon attempt. This is exactly what no file in a profile will ever show you — and it’s usually exactly what the security team cares about most.

PowerShell

# Every logon and failed attempt over the last 24 hours
Get-WinEvent -FilterHashtable @{
    LogName   = 'Security'
    Id        = 4624, 4625
    StartTime = (Get-Date).AddHours(-24)
} | ForEach-Object {
    [PSCustomObject]@{
        Time      = $_.TimeCreated
        Event     = if ($_.Id -eq 4624) { "Successful logon" } else { "FAILED logon" }
        Account   = $_.Properties[5].Value
        SourceIP  = $_.Properties[18].Value
    }
} | Sort-Object Time -Descending | Format-Table -AutoSize
Time                  Event              Account      SourceIP
----                  -----              -------      --------
9/26/2026 9:15:03 AM  Successful logon   d.ivanov     10.20.4.51
9/26/2026 9:14:07 AM  FAILED logon       admin        185.220.101.42
9/26/2026 9:14:05 AM  FAILED logon       admin        185.220.101.42
9/26/2026 9:14:02 AM  FAILED logon       admin        185.220.101.42

Three failed attempts against the admin account from an external IP in three seconds isn’t “the user forgot their password” — it’s a brute-force attempt. That’s exactly the picture the Security log shows you, and exactly what a profile file’s timestamp will never reveal.

The $_.Properties[N] index on a Windows event has no readable names out of the box — this is one of those things you can’t memorize, only look up once and leave in the script with a comment about what lives where. Here, [5] is the account name, [18] is the source IP; for 4625 the indexes match, because both events share the same field schema.

Which method to use when

  • NTUSER.DAT — when you need to quickly find unused profiles for cleanup, inventory, or freeing up space. Not for security reports.
  • The Security log (4624/4625) — when the source, second-precision timing, and failed attempts matter. The only real option for an actual investigation.
  • The limit of both methods: if the event log has already rolled over (the Security log isn’t infinite by default) or the profile was deleted long ago, neither method will have any data. For servers that need history longer than a week or two, ship these events to an external SIEM instead of relying on the local log.

Practical uses for both scripts:

  • Security audit: failed logon attempts after hours or from unfamiliar IPs.
  • System cleanup: profiles untouched for months are candidates for archiving.
  • Inventory: which accounts on a shared server are actually in use, and which can be closed.

Tags: #powershell #windows #security #audit #sysadmin


Want to become tomorrow’s architect instead of just an admin? This article is only the tip of the iceberg. On our Telegram channel “Admin Future” we publish systems-thinking guides, ready-to-use scripts, AI tips, and checklists every day that you won’t find on Google. Subscribe and become the expert in the room: Admin Future

МШ

Maksim Shapovalov

Systems administrator. 17+ years working with infrastructure.

Discuss your project ↗

Leave a Comment

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

Scroll to Top