Public/sessions/Get-RdpSessionHistory.ps1
|
#Requires -Version 5.1 function Get-RdpSessionHistory { <# .SYNOPSIS Retrieves Remote Desktop Protocol (RDP) session history from Windows Event Log .DESCRIPTION Queries the Microsoft-Windows-TerminalServices-LocalSessionManager/Operational event log on one or more computers to retrieve RDP session logon, logoff, disconnect, and reconnection events. Returns structured objects with user, IP address, and action details. The function filters events by ID: - 21: Logon - 23: Logoff - 24: Disconnected - 25: Reconnection .PARAMETER ComputerName One or more computer names to query. Defaults to the local machine. Supports pipeline input by value and by property name. .PARAMETER StartTime The earliest event timestamp to retrieve. Events older than this time are excluded from results. Defaults to January 1, 1970 (Unix epoch). .PARAMETER Credential Credential to use when querying remote computers. If not specified, uses the current user's credentials. .EXAMPLE Get-RdpSessionHistory Retrieves all RDP session events from the local computer since January 1, 1970. .EXAMPLE Get-RdpSessionHistory -ComputerName 'SRV01', 'SRV02' -StartTime (Get-Date).AddDays(-7) Retrieves RDP session history from SRV01 and SRV02 for the last 7 days. .EXAMPLE 'WEB01', 'APP01' | Get-RdpSessionHistory -Credential $cred Pipeline example: queries multiple servers using specified credentials. .EXAMPLE Get-ADComputer -Filter "OperatingSystem -like '*Server*'" | Get-RdpSessionHistory -StartTime (Get-Date).AddHours(-24) Retrieves last 24 hours of RDP session events from all domain servers. .EXAMPLE Get-RdpSessionHistory -StartTime (Get-Date).AddDays(-30) | Where-Object { $_.Action -eq 'Logon' } | Group-Object -Property User Retrieves last 30 days of RDP logon events and groups them by user. .OUTPUTS PSWinOps.RdpSessionHistory RDP logon/logoff event history from the event log. .NOTES Author: Franck SALLET Version: 1.1.0 Last Modified: 2026-03-19 Requires: PowerShell 5.1+ Permissions: Remote Event Log Readers group or local Administrator on target machines .LINK https://docs.microsoft.com/en-us/windows/win32/termserv/terminal-services-events #> [CmdletBinding()] [OutputType('PSWinOps.RdpSessionHistory')] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [Alias('CN', 'Name', 'DNSHostName')] [string[]]$ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [ValidateNotNull()] [datetime]$StartTime = [datetime]'1970-01-01', [Parameter(Mandatory = $false)] [ValidateNotNull()] [System.Management.Automation.PSCredential]$Credential ) begin { Write-Verbose "[$($MyInvocation.MyCommand)] Starting - PowerShell $($PSVersionTable.PSVersion)" # Event ID to Action mapping $eventActionMap = @{ 21 = 'Logon' 23 = 'Logoff' 24 = 'Disconnected' 25 = 'Reconnection' } # Filter configuration $logFilter = @{ LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational' ID = 21, 23, 24, 25 StartTime = $StartTime } Write-Verbose "[$($MyInvocation.MyCommand)] Querying events since: $($StartTime.ToString('yyyy-MM-dd HH:mm:ss'))" } process { foreach ($computer in $ComputerName) { Write-Verbose "[$($MyInvocation.MyCommand)] Processing: $computer" # Build Get-WinEvent parameters $winEventParams = @{ FilterHashtable = $logFilter ComputerName = $computer ErrorAction = 'Stop' } if ($PSBoundParameters.ContainsKey('Credential')) { $winEventParams['Credential'] = $Credential } try { # Query events from target computer $allEvents = Get-WinEvent @winEventParams if ($null -eq $allEvents -or $allEvents.Count -eq 0) { Write-Verbose "[$($MyInvocation.MyCommand)] No events found on $computer" continue } Write-Verbose "[$($MyInvocation.MyCommand)] Retrieved $($allEvents.Count) event(s) from $computer" # Process each event foreach ($eventEntry in $allEvents) { try { $eventXml = [xml]$eventEntry.ToXml() $eventData = $eventXml.Event.UserData.EventXML # Emit structured object [PSCustomObject]@{ PSTypeName = 'PSWinOps.RdpSessionHistory' TimeCreated = $eventEntry.TimeCreated ComputerName = $computer User = $eventData.User IPAddress = $eventData.Address Action = $eventActionMap[[int]$eventEntry.Id] EventID = $eventEntry.Id Timestamp = Get-Date -Format 'o' } } catch { Write-Warning "[$($MyInvocation.MyCommand)] Failed to parse event ID $($eventEntry.Id) on $computer - $_" } } } catch [System.Diagnostics.Eventing.Reader.EventLogException] { Write-Error "[$($MyInvocation.MyCommand)] Event log error on $computer - $_" } catch [System.UnauthorizedAccessException] { Write-Error "[$($MyInvocation.MyCommand)] Access denied to $computer - Requires Event Log Readers permissions" } catch [System.Exception] { Write-Error "[$($MyInvocation.MyCommand)] Failed to query $computer - $_" } } } end { Write-Verbose "[$($MyInvocation.MyCommand)] Completed" } } |