一次远程桌面突然失联的排障实录:服务都在,3389 却不听话
事情是这样的。
某天我准备远程连回自己电脑,结果远程桌面怎么点都没反应。第一反应当然是:
“不会吧,昨天还好好的,今天就开始装高冷了?”
于是我登录本机检查了一下远程桌面相关服务,发现表面上看居然没啥大问题:
Name Status StartType
---- ------ ---------
SessionEnv Stopped Manual
TermService Running Manual
UmRdpService Stopped Manual
乍一看,像是“服务有的在跑,有的没跑”,但这个信息其实还不够。因为远程桌面能不能真正被连接,不是只看服务名字顺不顺眼,而是要看它有没有真正监听 3389 端口。
一、先确认:到底是没开远程桌面,还是没真正监听端口
先检查远程桌面开关:
Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections
如果结果是 0,说明远程桌面是启用状态;如果是 1,那就是系统根本不让远程连。
接着检查 3389 端口有没有监听:
Get-NetTCPConnection -LocalPort 3389 -State Listen
或者:
netstat -ano | findstr ":3389"
我这里的结果很扎心:没有监听。
也就是说,虽然 TermService 看起来在运行,但它并没有把远程桌面真正“开门营业”。门牌挂着,门没开,主打一个形式主义。
二、继续查:防火墙是不是在背后使坏
再看一下远程桌面规则是否放行:
Get-NetFirewallRule | Where-Object {
$_.DisplayName -match '远程桌面|Remote Desktop|RDP|3389' -or
$_.DisplayGroup -match '远程桌面|Remote Desktop'
} | Select-Object DisplayName,DisplayGroup,Enabled,Direction,Action
我的机器里,相关规则是开启的,所以问题也不是防火墙。
到这里可以确定一件事:
三、看事件日志,找到真正的报错
接下来最有价值的一步,就是查系统日志:
Get-WinEvent -LogName 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational' -MaxEvents 20 |
Select-Object TimeCreated,Id,LevelDisplayName,Message | Format-List
结果里反复出现一条错误:
远程桌面服务启动失败。相关的状态代码为 0x80070005。
0x80070005 这个错误很经典,翻译成人话就是:
“我想干活,但是权限不够。”
这时候方向就比较清晰了:不是服务不会启动,而是它在启动某个关键组件时,被系统权限拦住了。
四、问题根因:MachineKeys 权限异常
远程桌面启动时,会用到系统证书和私钥文件。它们通常存放在这个目录:
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
查看这个目录权限:
icacls "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys"
我这台机器当时的权限很不正常,只剩下类似下面这种:
Everyone:(R,W)
BUILTIN\Administrators:(F)
看起来像是“谁都能来摸一下”,但实际上远程桌面依赖的账户,比如 SYSTEM、NETWORK SERVICE,权限并不完整。
而 TermService 恰恰就依赖这些身份去读取私钥、加载证书。于是结果就是:
服务是启动了,但启动到关键步骤时被权限问题绊了一跤,3389 永远起不来。
五、修复方法
1. 修复 MachineKeys 目录权限
icacls --% C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys /grant *S-1-5-18:(OI)(CI)(F) "NETWORK SERVICE":(OI)(CI)(M) BUILTIN\Administrators:(OI)(CI)(F)
说明一下:
S-1-5-18就是SYSTEMNETWORK SERVICE需要有修改权限- 管理员组保留完全控制
然后递归修复已有文件:
icacls --% C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys /grant *S-1-5-18:(F) "NETWORK SERVICE":(M) BUILTIN\Administrators:(F) /T /C
2. 如果某个私钥文件权限特别脏,直接复制正常 ACL
有时目录修好了,但最新生成的私钥文件权限还是不对。这时候可以把正常文件的 ACL 复制过去:
$files = Get-ChildItem 'C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys' | Sort-Object LastWriteTime
$src = $files[0].FullName
$dst = $files[-1].FullName
$acl = Get-Acl $src
Set-Acl -Path $dst -AclObject $acl
这一步非常接地气,属于“别讲大道理,先把能工作的权限模板抄过去”。
3. 确保远程桌面相关服务状态正常
Set-Service -Name SessionEnv -StartupType Automatic
Start-Service SessionEnv
Get-Service TermService,UmRdpService,SessionEnv | Select-Object Name,Status,StartType
修复后,我这里最终把状态恢复成了:
Name Status StartType
---- ------ ---------
SessionEnv Running Automatic
TermService Running Automatic
UmRdpService Running Manual
六、为什么最后还要重启系统
理论上说,权限修好、服务重启,问题就该结束了。
但实际情况比较“Windows 风格”:有些服务虽然你看着重启了,但它背后的证书、私钥句柄、监听器状态,未必真的被完全刷新。
尤其像远程桌面这种牵扯:
- 服务进程
- 证书私钥
- RDP 监听器
- 会话管理组件
只要其中一个环节还握着旧状态,3389 就可能继续装死。
所以最稳妥的收尾方式就是:
shutdown /r /t 5 /c "Restart to finalize Remote Desktop repair"
我最后也是这么处理的。因为和 Windows 讲道理,不如让它重新开机冷静一下。
七、重启后如何验证是否修好了
系统重启完成后,优先检查这两项:
Get-NetTCPConnection -LocalPort 3389 -State Listen
qwinsta
如果正常,应该至少满足下面两个条件:
3389端口处于监听状态qwinsta中能看到远程桌面相关会话正常
只要 3389 真正监听起来,远程桌面基本就能恢复连接。
八、适合收藏的一套排查顺序
以后如果你也碰到“远程桌面打不开,但服务看着又像正常”的情况,可以按这个顺序排:
- 先看远程桌面是否启用:
fDenyTSConnections - 再看防火墙是否放行
- 再看 3389 是否真的监听
- 如果没监听,就查终端服务日志
- 看到
0x80070005,优先怀疑权限问题 - 重点检查
MachineKeys和证书私钥权限 - 修复后重启系统做最终收尾
九、结语
这次故障最容易让人误判的地方在于:服务名看着还活着,但端口根本没起来。
所以碰到远程桌面连不上时,别急着一通怀疑网络、怀疑防火墙、怀疑人生。先问自己一句:
“3389 到底有没有真的在听?”
很多时候,答案一出来,方向就清楚了。

浙公网安备 33010602011771号