如何使用PowerShell检查账户是否具备服务器RDP连接权限
RDP预认证阶段连通性校验脚本实现
你的需求本质是校验RDP连接流程走到服务端等待凭据输入的节点即可,不需要提交账号密码、不需要完成完整登录,核心判断逻辑不需要依赖完整RDP客户端,轻量脚本就能实现。
校验逻辑原理
标准RDP连接在提交凭据前的固定流程为:
- TCP三次握手连接目标端口(默认3389)
- 完成TLS协商(现代RDP默认强制TLS加密,兼容自签证书场景)
- 客户端发送固定格式的RDP初始连接请求
- 服务端返回合法RDP响应,等待客户端提交认证信息
走到最后一步时,就已经满足“返回凭据输入提示、连接正常建立”的校验要求,此时直接断开连接即可,不会触发账户登录成功/失败的审计日志,只会产生基础连接记录。
方案1:PowerShell原生脚本(Windows环境无依赖)
不需要安装任何第三方组件,直接在Windows系统上运行,支持超时控制、自定义端口、自动跳过RDP证书校验:
function Test-RdpCredentialPrompt { param( [Parameter(Mandatory=$true)] [string]$TargetHost, [int]$Port = 3389, [int]$TimeoutMs = 3000 ) $tcpClient = $null $tlsStream = $null try { $tcpClient = New-Object System.Net.Sockets.TcpClient $connectTask = $tcpClient.ConnectAsync($TargetHost, $Port) if (-not $connectTask.Wait($TimeoutMs)) { return @{ Success = $false; Reason = "TCP连接超时,目标端口不可达" } } $tlsStream = New-Object System.Net.Security.SslStream($tcpClient.GetStream(), $false, { $true }) $tlsTask = $tlsStream.AuthenticateAsClientAsync($TargetHost) if (-not $tlsTask.Wait($TimeoutMs)) { return @{ Success = $false; Reason = "TLS协商失败,RDP服务运行异常" } } # 发送固定格式的RDP初始连接请求,无任何凭据信息 $rdpConnReq = [byte[]]@(0x03,0x00,0x00,0x13,0x0E,0xE0,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x03,0x00,0x00,0x00) $tlsStream.Write($rdpConnReq, 0, $rdpConnReq.Length) $buffer = New-Object byte[] 1024 $readTask = $tlsStream.ReadAsync($buffer, 0, 1024) if (-not $readTask.Wait($TimeoutMs)) { return @{ Success = $false; Reason = "未收到RDP凭据请求响应,连接被拦截" } } # 校验RDP协议头:合法RDP包前两字节固定为0x03 0x00 if ($buffer[0] -eq 0x03 -and $buffer[1] -eq 0x00) { return @{ Success = $true; Reason = "RDP连接正常,已返回凭据输入提示" } } else { return @{ Success = $false; Reason = "端口响应非RDP协议,服务不匹配" } } } catch { return @{ Success = $false; Reason = "连接异常:$($_.Exception.Message)" } } finally { if ($tlsStream) { $tlsStream.Close() } if ($tcpClient) { $tcpClient.Close() } } } # 调用示例 Test-RdpCredentialPrompt -TargetHost "192.168.1.100"
方案2:Python跨平台脚本(兼容Linux/macOS/Windows)
仅依赖Python原生标准库,不需要安装第三方包,适合批量探测场景:
import socket import ssl def test_rdp_credential_prompt(host: str, port: int = 3389, timeout: int = 3) -> tuple[bool, str]: sock = None tls_sock = None try { sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) sock.connect((host, port)) # 跳过证书校验,兼容自签证书、私有CA签发的证书 ctx = ssl._create_unverified_context() tls_sock = ctx.wrap_socket(sock, server_hostname=host) # 发送固定RDP初始连接请求 rdp_initial_req = bytes([ 0x03, 0x00, 0x00, 0x13, 0x0E, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00 ]) tls_sock.sendall(rdp_initial_req) resp = tls_sock.recv(1024) if len(resp) >= 2 and resp[0] == 0x03 and resp[1] == 0x00: return (True, "RDP连接正常,已返回凭据输入提示") else: return (False, "端口响应非RDP协议,服务不匹配") } catch Exception as e: return (False, f"连接失败:{str(e)}") finally: if tls_sock: tls_sock.close() if sock: sock.close() # 调用示例 if __name__ == "__main__": print(test_rdp_credential_prompt("192.168.1.100"))
注意事项
- 不要用单纯的TCP端口探测代替RDP校验:很多场景下3389端口能通,但RDP服务崩溃、组策略拦截、NLA配置异常时,根本到不了凭据输入界面,上述脚本覆盖了TLS协商、RDP协议握手流程,能准确识别这类假连通情况
- 兼容NLA场景:默认开启的网络级别身份验证(NLA)不会影响校验结果,NLA校验本身就处于凭据提交前的阶段,服务端依然会返回合法RDP响应等待认证信息
- 不需要依赖重型RDP库:不需要引入FreeRDP、rdpy等完整RDP实现库,初始连接请求是固定格式的19字节数据包,不需要实现完整RDP协议栈就能完成校验
内容的提问来源于stack exchange,提问作者P.J. Some
相关产品推荐
相关产品推荐

