An essential guide for IT professionals to track, audit and analyze user login events on Windows systems.
This is a powerful and practical PowerShell script to get user login history on Windows systems. This script is for IT professionals, system administrators and managed service providers (MSPs) who need to track user logins and security events. By using built-in Windows event logs this solution helps you to audit user activity, troubleshoot issues and meet compliance requirements quickly.
Auditing Windows login events is a must for a secure and stable IT environment. Whether you are investigating an unauthorized login, preparing for a security audit or just monitoring user activity, manually going through the Event Viewer is a tedious and time consuming process. This PowerShell User Login History script does that for you. It gives you a quick and formatted report that is easy to read and export, makes it a great tool for your daily administrative tasks. It’s a must have in your user audit script toolkit.
Here's the complete PowerShell script. You can copy and paste this directly into your PowerShell console or save it as a .ps1 file.
# -----------------------------------------------------------------------------
# Script Name: Get-UserLoginHistory.ps1
# Description: Retrieves user login and logoff history from Windows security event logs.
# Author: Team Zecurit
# Date: September 8, 2025
# -----------------------------------------------------------------------------
# PARAMETERS:
# -Username: Specifies the username to search for. If not provided, it will search for all users.
# -ComputerName: Specifies the remote computer to run the script on. Defaults to the local host.
# -TimeSpan: Specifies the time period to search for events (e.g., '7 days', '1 month'). Defaults to '30 days'.
param(
[string]$Username = '*',
[string]$ComputerName = $env:COMPUTERNAME,
[string]$TimeSpan = '30 days'
)
# Define the security event IDs for login (4624) and logoff (4634)
$loginEventID = 4624
$logoffEventID = 4634
# Convert the timespan string to a DateTime object
$startTime = (Get-Date).AddDays(-([int]$TimeSpan.Split(' ')[0]))
# Search the security log for relevant events
Write-Host "Searching for login/logoff events for user '$Username' on '$ComputerName'..."
$events = Get-WinEvent -FilterHashtable @{
Logname = 'Security';
ID = $loginEventID, $logoffEventID;
StartTime = $startTime
} -ComputerName $ComputerName | Where-Object { $_.Properties.Value -like "*$Username*" }
# Process and format the events
$history = $events | ForEach-Object {
$eventData = $_.Properties.Value
$loginType = switch ($_.Id) {
$loginEventID { 'Login' }
$logoffEventID { 'Logoff' }
default { 'Unknown' }
}
$logonType = ''
if ($_.Id -eq $loginEventID) {
$logonType = switch ($eventData[8]) {
2 { 'Interactive (Console)' }
3 { 'Network (e.g., shared folder)' }
4 { 'Batch' }
5 { 'Service' }
7 { 'Unlock' }
10 { 'RemoteInteractive (e.g., RDP)' }
11 { 'CachedInteractive' }
default { 'Unknown' }
}
}
[PSCustomObject]@{
Timestamp = $_.TimeCreated
UserName = $_.Properties[5].Value
EventType = $loginType
LogonType = $logonType
Source = $_.MachineName
Status = 'Success'
}
}
# Output the results, sorted by timestamp
$history | Sort-Object -Property Timestamp | Format-Table -AutoSize
The script uses the Get-WinEvent cmdlet, which is the modern and recommended way to query Windows Event Logs. The key to its efficiency is the -FilterHashtable parameter. This allows us to specify multiple criteria in a single, high-performance query. In this case, we're looking for two specific event IDs in the "Security" log:
Event ID 4624: A successful logon.
Event ID 4634: A successful logoff.
By providing both IDs in an array (ID = 4624, 4634), the script retrieves all relevant login and logoff events in a single pass. This is significantly more efficient than filtering events after they have been retrieved, which is a common mistake when using older cmdlets like Get-EventLog. For more details on these events and others, you can refer to the official Microsoft Docs on security event IDs.
Event ID 4624 provides additional context through a "Logon Type" field, which is crucial for understanding how a user accessed the system. The script includes a switch statement to translate the numerical Logon Type (e.g., 2, 3, 10) into a human-readable description (e.g., Interactive, Network, RemoteInteractive). This makes it easy to distinguish between someone logging into the physical console vs. accessing a shared drive over the network or connecting via Remote Desktop Protocol (RDP).
After retrieving and processing the events, the script uses [PSCustomObject] to create a structured output. This is a best practice in PowerShell scripting, as it creates objects with custom properties that are easy to work with. The Format-Table -AutoSize command then presents this data in a clean, columnar format, making the output instantly readable in the console.
The script includes a ComputerName parameter, which defaults to the local computer. To run this script on a remote machine, you simply need to provide the computer's name or IP address. For example:
.\Get-UserLoginHistory.ps1 -ComputerName 'SERVER-A1' -Username 'jdoe'
Running remote commands requires that the user has administrative privileges on the target machine and that the PowerShell Remoting (WinRM) service is configured and running. This is a core component of remote management for Windows systems.
Need to know when jdoe logged in last week? This script makes it easy. Just use the -Username and -TimeSpan parameters to get the report. This is great for HR investigations or security audits.
This script focuses on successful logins (4624) but you can easily modify it to include failed logins (Event ID 4625). Run this regularly to detect brute force attacks on user accounts.
Many regulatory frameworks (HIPAA, PCI DSS) require audit trails of user access. Run this script on a schedule to generate login history reports which can then be saved as CSV or HTML for long term archival and compliance review.
When a user's account is locked out it's usually because a service or application is trying to authenticate with a stale password. This script doesn't fix lockouts but reviewing the login history for a locked out user will help you identify the machine (the one generating the failed attempts) and the type of logon causing the issue. This is a key step in troubleshooting account lockout problems.
The ability to get login history programmatically with PowerShell is a fundamental skill for any Windows administrator. This script provides a solid foundation for auditing and tracking user logins, and can be easily customized to fit your specific needs.
Refer to this article for additional methods to fetch user logon history using Event Viewer and third-party tools
Upload this script to Zecurit's Script Repository and execute it across hundreds of endpoints in minutes. Support for PowerShell, Bash, Python,and more with full audit trails and scheduling.
The history you can retrieve is limited by the log retention policy on the target computer. By default, Windows Event Logs are configured to "Overwrite events as needed," meaning older events are deleted to make space for new ones. To retain logs for longer periods, you must configure the maximum log size in the Event Viewer. This is a crucial step if you need to maintain a long-term user audit script trail for compliance or forensic purposes.
To run the script on a remote computer, use the -ComputerName parameter. For example: .\Get-UserLoginHistory.ps1 -ComputerName 'RemoteServer' -Username 'testuser'. You must have administrative access to the remote machine, and the Windows Remote Management (WinRM) service must be running and configured to allow remote connections.
Yes, this script is safe to run in a production environment. It uses the Get-WinEvent cmdlet, which is read-only and does not modify any system settings or data. It simply queries the existing Windows Event Logs. The performance impact is minimal as it's designed to be a lightweight query.