RDP Logon and Logoff Log

Modified on Fri, 19 Jun at 5:04 PM

$Username  = "JohnDoe"
$StartDate = [datetime]"2026-06-01 00:00:00"
$EndDate   = [datetime]"2026-06-30 23:59:59"
$LogName   = "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational"

$events = Get-WinEvent -FilterHashtable @{
    LogName   = $LogName
    ID        = @(21, 23, 24, 25)
    StartTime = $StartDate
    EndTime   = $EndDate
} -ErrorAction SilentlyContinue | 
Where-Object { $_.Message -match $Username } | 
Sort-Object TimeCreated

$activeSessions = @{}
$rawResults = @()

foreach ($event in $events) {
    $user      = $event.Properties[0].Value
    $sessionID = $event.Properties[1].Value
    $ip        = if ($event.Properties.Count -gt 2) { $event.Properties[2].Value } else { "N/A" }

    switch ($event.Id) {
        { $_ -in 21, 25 } { 
            # Store the start time and IP
            $activeSessions[$sessionID] = @{ LogonTime = $event.TimeCreated; IP = $ip }
        }
        { $_ -in 23, 24 } { 
            # Match with the start time
            $session = $activeSessions[$sessionID]
            $logonTime = if ($session) { $session.LogonTime } else { $null }
            $logoffTime = $event.TimeCreated
            
            $durationStr = "N/A"
            $totalMinutes = 0

            # Calculate session duration
            if ($logonTime) {
                $ts = New-TimeSpan -Start $logonTime -End $logoffTime
                $hours = [math]::Floor($ts.TotalHours)
                $durationStr = "{0}h {1}m" -f $hours, $ts.Minutes
                $totalMinutes = $ts.TotalMinutes
            }

            $rawResults += [PSCustomObject]@{
                Username    = $user
                RemoteIP    = if ($session) { $session.IP } else { $ip }
                LogonTime   = if ($logonTime) { $logonTime } else { "Prior to Timeframe" }
                LogoffTime  = $logoffTime
                Duration    = $durationStr
                EndState    = if ($_ -eq 23) { "Logged Off" } else { "Disconnected" }
                _DateKey    = $logoffTime.Date # Hidden property for grouping by day
                _TotalMins  = $totalMinutes    # Hidden property for math
            }
            
            if ($session) { $activeSessions.Remove($sessionID) }
        }
    }
}

foreach ($key in $activeSessions.Keys) {
    $rawResults += [PSCustomObject]@{
        Username    = $Username
        RemoteIP    = $activeSessions[$key].IP
        LogonTime   = $activeSessions[$key].LogonTime
        LogoffTime  = "Still Active"
        Duration    = "N/A"
        EndState    = "Active"
        _DateKey    = $activeSessions[$key].LogonTime.Date
        _TotalMins  = 0
    }
}

$rawResults = $rawResults | Sort-Object LogonTime

$finalResults = @()
$grouped = $rawResults | Group-Object _DateKey

foreach ($group in $grouped) {
    $items = $group.Group
    
    # Calculate the total minutes for the day
    $dailyTotalMins = ($items | Measure-Object _TotalMins -Sum).Sum
    $dailyH = [math]::Floor($dailyTotalMins / 60)
    $dailyM = [math]::Round($dailyTotalMins % 60)
    $dailyTotalStr = "{0}h {1}m" -f $dailyH, $dailyM

    for ($i = 0; $i -lt $items.Count; $i++) {
        $item = $items[$i]
        $isLast = ($i -eq ($items.Count - 1)) # Check if it's the last row of the day
        
        $finalResults += [PSCustomObject]@{
            Username   = $item.Username
            RemoteIP   = $item.RemoteIP
            LogonTime  = $item.LogonTime
            LogoffTime = $item.LogoffTime
            Duration   = $item.Duration
            DailyTotal = if ($isLast) { $dailyTotalStr } else { "" }
            EndState   = $item.EndState
        }
    }
}

$finalResults | Format-Table -AutoSize

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article