Ways to find VPN client address on RDP connection

Solution 1:

I would search for the client computer name. The %CLIENTNAME% environment variable keeps this value.

On the host in the user session, it will be available from the command line or in a script:

echo %CLIENTNAME%

However, note that on a system that has several users sharing the same session, using a shared user account, this value can go stale.

A more reliable way to get the currently logged in session on the host is by getting the value from the registry. Depending on the version of Windows used, it will sit in one of these locations:

Example 1 (NT 5.2):

[HKEY_USERS\S-1-5-21-***\Volatile Environment]
"CLIENTNAME"="DESKTOP-223XGQ"

Example 2 (NT 6.3):

[HKEY_USERS\S-1-5-21-***\Volatile Environment\3]
"CLIENTNAME"="DESKTOP-223XGQ"

Example 3 (NT 6.1) batch-script runned from user environment:

for /f "tokens=3*" %%i in ('reg query "hkcu\Volatile Environment" /s /v CLIENTNAME^|find/i"CLIENTNAME"') do @echo %%i

Where the *** in S-1-5-21-*** is the user SID.

Note that there will also be a similar HKEY_USERS\S-1-5-21-***_Classes which won't hold the CLIENTNAME subkey.

The approach that will reliable get you a client name is to check HKEY_USERS\S-1-5-21-***\Volatile Environment for a CLIENTNAME subkey and if it's not there, to enumerate the keys in Volatile Environment and check any of them that have a an all integer value name (1, 2, etc.) for a CLIENTNAME subkey.

A Python function that does this:

def get_client_name():
    with ConnectRegistry(None, HKEY_USERS) as root:
        try:
            n = 0
            while True:
                user_key = EnumKey(root, n)
                if user_key.startswith('S-1-5-21-') and not user_key.endswith('_Classes'):
                    with OpenKey(root, f"{user_key}\Volatile Environment", 0, KEY_READ) as ve_key:
                        try:
                            return QueryValueEx(ve_key, 'CLIENTNAME')[0]
                        except FileNotFoundError:
                            pass
                        try:
                            m = 0
                            while True:
                                client = EnumKey(ve_key, m)
                                try:
                                    with OpenKey(ve_key, f'{client}', 0, KEY_READ) as client_key:
                                        return QueryValueEx(client_key, 'CLIENTNAME')[0]
                                except (OSError, FileNotFoundError):
                                    pass
                                m += 1
                        except OSError:
                            pass
                n += 1
        except OSError:
            return None

And all theese ways are applicable to Windows Terminal Server and Citrix Servers (checked on Receiver 4.12).

Another approach is to install a PowerShell cmdlet and capture the information with that:

Install-Module -Name PSTerminalServices
Get-TSSession

Or, specifically

Get-TSSession | ft ClientName