Es gibt Umstände, da möchte man Wissen von welchem System aus eine RDP-Verbindung hergestellt wurde, wie deren Status ist und mehr.

Die einfachste Möglichkeit ist via “Task-Manager – Benutzer” und die entsprechenden Spalten anzeigen lassen. Bordmittel an Befehlen wären zum Beispiel

  • query user
  • query session
  • qwinsta

Allen gemein ist, das sie im Gegensatz zum Task-Manager nicht den Clientname anzeigen. Möchte man das Ganze via Skript lösen geht das so:

Add-Type -MemberDefinition @'
[DllImport("wtsapi32.dll", CharSet = CharSet.Unicode)]
public static extern bool WTSQuerySessionInformation(
    IntPtr hServer,
    int sessionId,
    int infoClass,
    out IntPtr ppBuffer,
    out int pBytesReturned);

[DllImport("wtsapi32.dll")]
public static extern void WTSFreeMemory(IntPtr pMemory);
'@ -Name 'WtsApi' -Namespace 'Win32'

$WTS_CURRENT_SERVER = [IntPtr]::Zero
$WTSUserName        = 5
$WTSClientName      = 10
$WTSSessionName     = 6
$WTSConnectState    = 8

function Get-WTSInfo($sessionId, $infoClass) {
    $buffer = [IntPtr]::Zero
    $bytes  = 0
    if ([Win32.WtsApi]::WTSQuerySessionInformation(
            $WTS_CURRENT_SERVER, $sessionId, $infoClass,
            [ref]$buffer, [ref]$bytes)) {
        $value = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($buffer)
        [Win32.WtsApi]::WTSFreeMemory($buffer)
        return $value
    }
    return $null
}

function Get-WTSConnectState($sessionId) {
    $buffer = [IntPtr]::Zero
    $bytes  = 0
    if ([Win32.WtsApi]::WTSQuerySessionInformation(
            $WTS_CURRENT_SERVER, $sessionId, $WTSConnectState,
            [ref]$buffer, [ref]$bytes)) {
        $state = [System.Runtime.InteropServices.Marshal]::ReadInt32($buffer)
        [Win32.WtsApi]::WTSFreeMemory($buffer)
        switch ($state) {
            0 { return 'Aktiv' }
            1 { return 'Verbunden' }
            2 { return 'Verbindung wird hergestellt' }
            3 { return 'Inaktiv' }
            4 { return 'Getrennt' }
            5 { return 'Abgemeldet' }
            6 { return 'Zurückgestellt' }
            7 { return 'Zurückgesetzt' }
            8 { return 'Wird beendet' }
            default { return "Unbekannt ($state)" }
        }
    }
    return $null
}

qwinsta 2>$null | Select-Object -Skip 1 | ForEach-Object {
    if ($_ -match '\s+(\d+)\s+') {
        $id      = [int]$matches[1]
        $user    = Get-WTSInfo $id $WTSUserName
        $client  = Get-WTSInfo $id $WTSClientName
        $session = Get-WTSInfo $id $WTSSessionName
        $status  = Get-WTSConnectState $id

        if ($user) {
            [PSCustomObject]@{
                SessionID  = $id
                Sitzung    = $session
                Benutzer   = $user
                Clientname = $client
                Status     = $status
            }
        }
    }
}

Die Ausgabe sieht dann beispielsweise so aus:

SessionID : 1
Sitzung : RDP-Tcp#16
Benutzer : administrator
Clientname : PC06
Status : Aktiv

SessionID : 2
Sitzung : 
Benutzer : homeoffice
Clientname : 
Status : Getrennt

Das Ganze funktioniert sowohl unter Windows Server als auch Windows Clients.

Dieses Skript wurde mittels Anthropic Claude erstellt.

Update 21.04.2026

Das Skript hat sich schon mehrfach als nützlich erwiesen. Nachfolgend eine erweiterte Fassung die den Anzeigenamen und die IP-Adresse (des RDP-Clients) mit ausgibt:

Add-Type -MemberDefinition @'
[DllImport("wtsapi32.dll", CharSet = CharSet.Unicode)]
public static extern bool WTSQuerySessionInformation(
    IntPtr hServer,
    int sessionId,
    int infoClass,
    out IntPtr ppBuffer,
    out int pBytesReturned);

[DllImport("wtsapi32.dll")]
public static extern void WTSFreeMemory(IntPtr pMemory);
'@ -Name 'WtsApi' -Namespace 'Win32'

Add-Type -MemberDefinition @'
[StructLayout(LayoutKind.Sequential)]
public struct WTS_CLIENT_ADDRESS {
    public uint AddressFamily;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
    public byte[] Address;
}
'@ -Name 'WtsStructs' -Namespace 'Win32' -WarningAction SilentlyContinue

$WTS_CURRENT_SERVER = [IntPtr]::Zero
$WTSUserName        = 5
$WTSDomainName      = 7
$WTSClientName      = 10
$WTSSessionName     = 6
$WTSConnectState    = 8
$WTSClientAddress   = 14

function Get-WTSInfo($sessionId, $infoClass) {
    $buffer = [IntPtr]::Zero
    $bytes  = 0
    if ([Win32.WtsApi]::WTSQuerySessionInformation(
            $WTS_CURRENT_SERVER, $sessionId, $infoClass,
            [ref]$buffer, [ref]$bytes)) {
        $value = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($buffer)
        [Win32.WtsApi]::WTSFreeMemory($buffer)
        return $value
    }
    return $null
}

function Get-WTSConnectState($sessionId) {
    $buffer = [IntPtr]::Zero
    $bytes  = 0
    if ([Win32.WtsApi]::WTSQuerySessionInformation(
            $WTS_CURRENT_SERVER, $sessionId, $WTSConnectState,
            [ref]$buffer, [ref]$bytes)) {
        $state = [System.Runtime.InteropServices.Marshal]::ReadInt32($buffer)
        [Win32.WtsApi]::WTSFreeMemory($buffer)
        switch ($state) {
            0 { return 'Aktiv' }
            1 { return 'Verbunden' }
            2 { return 'Verbindung wird hergestellt' }
            3 { return 'Inaktiv' }
            4 { return 'Getrennt' }
            5 { return 'Abgemeldet' }
            6 { return 'Zurückgestellt' }
            7 { return 'Zurückgesetzt' }
            8 { return 'Wird beendet' }
            default { return "Unbekannt ($state)" }
        }
    }
    return $null
}

function Get-WTSClientIP($sessionId) {
    $buffer = [IntPtr]::Zero
    $bytes  = 0
    if ([Win32.WtsApi]::WTSQuerySessionInformation(
            $WTS_CURRENT_SERVER, $sessionId, $WTSClientAddress,
            [ref]$buffer, [ref]$bytes)) {
        $addr = [System.Runtime.InteropServices.Marshal]::PtrToStructure(
            $buffer, [type][Win32.WtsStructs+WTS_CLIENT_ADDRESS])
        [Win32.WtsApi]::WTSFreeMemory($buffer)

        if ($addr.AddressFamily -eq 2) {
            return "$($addr.Address[2]).$($addr.Address[3]).$($addr.Address[4]).$($addr.Address[5])"
        }
        elseif ($addr.AddressFamily -eq 23) {
            $ipv6 = [System.Net.IPAddress]::new($addr.Address[2..17])
            return $ipv6.ToString()
        }
    }
    return $null
}

function Get-DisplayName($username, $domain) {
    if (-not $username) { return $null }
    try {
        # Versuch über Active Directory (ADSI)
        $searcher = New-Object System.DirectoryServices.DirectorySearcher
        $searcher.Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=$username))"
        $searcher.PropertiesToLoad.Add("displayName") | Out-Null
        $result = $searcher.FindOne()
        if ($result) {
            return $result.Properties["displayName"][0]
        }
    }
    catch {}

    try {
        # Fallback: lokaler Benutzer
        $localUser = Get-LocalUser -Name $username -ErrorAction SilentlyContinue
        if ($localUser -and $localUser.FullName) {
            return $localUser.FullName
        }
    }
    catch {}

    return $null
}

qwinsta 2>$null | Select-Object -Skip 1 | ForEach-Object {
    if ($_ -match '\s+(\d+)\s+') {
        $id          = [int]$matches[1]
        $user        = Get-WTSInfo $id $WTSUserName
        $domain      = Get-WTSInfo $id $WTSDomainName
        $client      = Get-WTSInfo $id $WTSClientName
        $session     = Get-WTSInfo $id $WTSSessionName
        $status      = Get-WTSConnectState $id
        $ip          = Get-WTSClientIP $id
        $displayName = Get-DisplayName $user $domain

        if ($user) {
            [PSCustomObject]@{
                SessionID   = $id
                Sitzung     = $session
                Benutzer    = $user
                Anzeigename = $displayName
                Clientname  = $client
                ClientIP    = $ip
                Status      = $status
            }
        }
    }
}

Wie hat Dir der Artikel gefallen ?

1 Stern2 Sterne3 Sterne4 Sterne5 Sterne (Bislang keine Stimmen erhalten.)
Loading...

Du möchtest den Blog unterstützen ?

Neben PayPal.ME gibt es noch weitere Möglichkeiten, lies hier wie du diesen Blog unterstützen kannst.