一次远程桌面突然失联的排障实录:服务都在,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

我的机器里,相关规则是开启的,所以问题也不是防火墙。

到这里可以确定一件事:

远程桌面开关是开的,防火墙也是放行的,但 3389 没监听。说明问题已经从“网络问题”进入“系统内部服务异常”阶段了。

三、看事件日志,找到真正的报错

接下来最有价值的一步,就是查系统日志:

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)

看起来像是“谁都能来摸一下”,但实际上远程桌面依赖的账户,比如 SYSTEMNETWORK SERVICE,权限并不完整。

TermService 恰恰就依赖这些身份去读取私钥、加载证书。于是结果就是:

服务是启动了,但启动到关键步骤时被权限问题绊了一跤,3389 永远起不来。

五、修复方法

下面命令请在“管理员 PowerShell”中执行。

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 就是 SYSTEM
  • NETWORK 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

如果正常,应该至少满足下面两个条件:

  1. 3389 端口处于监听状态
  2. qwinsta 中能看到远程桌面相关会话正常

只要 3389 真正监听起来,远程桌面基本就能恢复连接。

八、适合收藏的一套排查顺序

以后如果你也碰到“远程桌面打不开,但服务看着又像正常”的情况,可以按这个顺序排:

  1. 先看远程桌面是否启用:fDenyTSConnections
  2. 再看防火墙是否放行
  3. 再看 3389 是否真的监听
  4. 如果没监听,就查终端服务日志
  5. 看到 0x80070005,优先怀疑权限问题
  6. 重点检查 MachineKeys 和证书私钥权限
  7. 修复后重启系统做最终收尾

九、结语

这次故障最容易让人误判的地方在于:服务名看着还活着,但端口根本没起来。

所以碰到远程桌面连不上时,别急着一通怀疑网络、怀疑防火墙、怀疑人生。先问自己一句:

“3389 到底有没有真的在听?”

很多时候,答案一出来,方向就清楚了。

posted @ 2026-04-25 19:51  张家华  阅读(139)  评论(0)    收藏  举报