How To Obtain IP Addresses Of Remote Desktop Clients With PowerShell

If you’ve ever managed a terminal server or RDS chances are there has been a need to identify the IP address of connected clients.

Task manager gives us the client hostname but sometimes DNS can have stale entries or the client can be on the remote side of a VPN. We can use tools like netstat, but this only gives us connected IPs, not the associated usernames. The old Remote Desktop Services Manager showed the client IP along with the username, but it is no longer present Server 2012 and newer.

A simple way I’ve been using is to parse the Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational event log. This log, under EventId 1149 shows each successful RDS authentication event, and contains the username, IP address, and timestamp.

RDS Authentication Event

The snippet below is essentially a shortcut to manually checking the RemoteConnectionManager logs. It pulls current users from quser so we only display data for existing sessions, then parses the event log (limiting the query to the last 31 days as we don’t need to pull everything), correlates the two, finally displaying the connected users, the IP they’re connecting from, and a timestamp of when they authenticated.

$CurrentUsers = quser
$CurrentUsers = $CurrentUsers[1..$CurrentUsers.Length] | % {$_.trim().Split(" ")[0].Replace(">", "")}

$Events = Get-WinEvent -FilterHashtable @{
    Logname   = 'Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational'
    ID        = 1149
    StartTime = (Get-Date).AddDays(-31)    
}
$EventObjects = @()
$Events | % {
    $EventXML = [xml]$_.ToXml()
    $obj = New-Object -TypeName PSObject -Property @{
        Username  = $EventXML.Event.UserData.EventXML.Param1
        IP        = $EventXML.Event.UserData.EventXML.Param3
        Timestamp = [datetime]$EventXML.Event.System.TimeCreated.SystemTime
    }
    $EventObjects += $obj
}

$CurrentSessions = $CurrentUsers | ForEach-Object {
    $EventObjects | Sort-Object -Property Timestamp -Descending | Where-Object Username -eq $_ | Select-Object -First 1
}

$CurrentSessions | Select-Object Username, IP, Timestamp

Which results in the following sample output.

Username IP           Timestamp
-------- --           ---------
user1    10.83.x.x    10/12/2019 4:25:59 PM
user2    10.83.x.x    10/12/2019 6:48:06 PM

One caveat with this method is that that if a user connected through an RD Gateway (keep in mind local connections bypass the RD Gateway by default), the event log entry will show the gateway IP address instead of the client. Gateway entries are logged in Microsoft-Windows-TerminalServices-Gateway/Operational, EventId 302, however, this has not been incorporated into the script at this stage.