“Windows Update 之后,帮我看看 20 台服务器是不是都正常启动了”“想请你查一下所有据点的 PC 上那个设置值现在是什么状态”── 面对这类请求,你是不是还在用远程桌面一台台登录确认?哪怕每台只要 3 分钟,20 台也要花 1 小时。人一旦重复劳动就会疲于应付,也容易漏检。
PowerShell Remoting 正是把“对多台机器执行同一操作”这件事,变成一条命令就能完成的机制。Windows 标准内置了名为 WinRM 的远程管理基础设施,在 Windows Server 上默认已经启用。也就是说,在很多现场,今天就可以直接使用,不需要安装任何额外软件。尽管如此,“总觉得有点可怕”“在工作组环境里连不上就放弃了”这样的声音却很常见。
本文面向中小企业的信息系统部门与运维人员,梳理 Remoting 的原理(哪些内容在哪个端口上运行、谁可以连接)、通过 Invoke-Command 实现批量执行、域环境与工作组环境的差异、second hop 问题这类著名的陷阱、“连不上”时的排查方法,以及“从只读操作开始”的安全运维方式。
前提环境
- 被连接的一方:在 Windows Server 2012 及以后的 Windows Server 上,PowerShell Remoting 默认已启用。1 客户端版 Windows 的 WinRM 服务默认为禁用状态,需要通过
Enable-PSRemoting启用。1 - 发起连接的一方:本文的命令示例只使用 Windows PowerShell 5.1 与 PowerShell 7 两者都具备的 cmdlet。不过
WSMan:驱动器与Test-WSMan等 WS-Management 相关 cmdlet 仅在 Windows 上的 PowerShell 中可用(Linux、macOS 上的 PowerShell 请使用第 6 章介绍的基于 SSH 的 Remoting)。2 - 权限:无论是修改远程一侧的设置(Enable-PSRemoting、TrustedHosts、监听器),都需要以管理员身份启动的 PowerShell。1
- 网络:本文同时涉及域环境与工作组环境,两者的差异汇总在第 3 章。
1. 先说结论
- PowerShell Remoting 运行在 WinRM(WS-Management 实现)之上,默认使用 HTTP 5985 / HTTPS 5986 端口。即使走 HTTP,通信内容也会由认证协议施加消息级加密。3
- 默认情况下只有远程一侧 Administrators 组的成员才能连接,会话在所连接用户的上下文中运行。并不是“启用 Remoting 后谁都能进来”。3
- Enable-PSRemoting 所做的事情有明确定义。包括启动 WinRM 服务并设为自动启动、创建监听器、开启防火墙例外、启用会话配置。Windows Server 上默认启用,客户端 Windows 需要手动启用。43
- 域环境下 Kerberos 可以直接工作,工作组则需要 NTLM + TrustedHosts + 显式凭据。TrustedHosts 并非“信任对方”的设置,而是“放弃验证对方身份的列表”,因此应控制在最小范围。53
- 批量执行用 Invoke-Command,交互式操作用 Enter-PSSession,需要保持状态并反复使用则用 New-PSSession。Invoke-Command 默认最多并行处理 32 台。67
- 从远程返回的是反序列化后的对象,不带方法。操作应在 ScriptBlock 内部(远程一侧)完结,本地只做结果的汇总。87
- 无法从连接目标进一步访问另一台服务器(second hop 问题)。这不是缺陷,而是“不把凭据发送到远程”这一安全设计的必然结果。应对方法有多种,需按需求选择。9
- PowerShell 7 还可以使用基于 SSH 的 Remoting。在需要与 Linux 互相管理,或者不想开放 WinRM 的环境中,可以作为一个选项。2
2. 原理 ── 在 WinRM 之上,谁、如何进入
PowerShell Remoting 的基础是 WinRM(Windows Remote Management)。WinRM 是标准协议 WS-Management 的微软实现,PowerShell Remoting 正是通过这个 WinRM,把命令发送到远程计算机上的 PowerShell。3 通信默认使用 HTTP 5985 端口、HTTPS 5986 端口。35
有人会担心“HTTP 是不是明文传输”,但初次认证完成后 WinRM 会对通信进行加密。HTTPS 下用的是 TLS,HTTP 下则是由认证协议协商出的消息级加密(若是 Kerberos,在现代环境中为 AES-256)。3 另外,默认情况下只有远程一侧 Administrators 组的成员才能连接,会话在所连接用户的上下文中执行,因此文件与注册表的访问控制会照常适用。3
接受连接一方的准备工作是 Enable-PSRemoting。这个 cmdlet 会做什么,官方文档中有明确列举。它在内部执行 Set-WSManQuickConfig,完成 (1) 启动 WinRM 服务、(2) 将启动类型改为自动、(3) 创建可在任意 IP 地址上接收请求的监听器、(4) 启用 WS-Management 通信所需的防火墙例外、(5) 创建并启用会话配置(终结点)及远程访问权限之后,重新启动 WinRM 服务。4
# 在被连接的一方,用管理员权限的 PowerShell 只需执行一次
# (Windows Server 默认已启用,通常不需要执行;客户端 Windows 上需要)
Enable-PSRemoting
# 从发起连接的一方进行连通性确认 ── 这个通了,说明 Remoting 的基础已经就绪
Test-WSMan -ComputerName sv-app01
有两个不了解就容易踩坑的地方。第一是防火墙。在服务器版 Windows 上,Enable-PSRemoting 会针对公用网络也创建“仅允许来自同一子网”的规则;而在客户端版上,如果网络配置文件是公用网络,启用操作本身就会报错(这是把测试机接入公司 Wi-Fi 时的经典问题)。这种情况下可以加上 -SkipNetworkProfileCheck,或者把网络配置文件改为专用网络。4
第二是 PowerShell 版本与终结点的关系。Enable-PSRemoting 会为“执行它所使用的那个 PowerShell 版本”配置对应的终结点。即使在 PowerShell 7 中执行,也不会影响 Windows PowerShell 5.1 的终结点,反过来也一样。4 而且即便从 PowerShell 7 发起连接,默认情况下也会使用 Windows PowerShell 5.1 已有的终结点(Microsoft.PowerShell)10,所以“本地明明是 7,远程实际运行的却是 5.1”是很常见的情况。请养成在远程一侧显示 $PSVersionTable 确认版本的习惯。
3. 域与工作组 ── 认证的分水岭在这里
Remoting 入门时最容易卡住的地方,不是命令的语法,而是认证。所需的准备工作会因环境而异。
| 项目 | 域环境 | 工作组环境 |
|---|---|---|
| 认证协议 | Kerberos(具备相互认证)5 | NTLM(不验证服务器身份)5 |
| 额外设置 | 原则上不需要,直接用计算机名连接即可 | 需要在发起连接的一方登记 TrustedHosts5 |
| 凭据 | 直接使用当前登录用户 | 通常需要用 -Credential 显式指定 |
| 按 IP 地址连接 | 需要登记 TrustedHosts 或使用 HTTPS11 | 同左 |
如果是域环境,Kerberos 的相互认证(客户端与服务器互相验证对方身份)会生效,Invoke-Command -ComputerName sv-app01 { ... } 可以直接连通。工作组环境无法使用 Kerberos5,因此需要在发起连接的一方把目标主机登记到 TrustedHosts。
# 在发起连接的一方,用以管理员身份启动的 PowerShell 执行(仅工作组环境需要)
# 修改 TrustedHosts 同样需要管理员权限。已有的值会被覆盖,所以先确认当前值
Get-Item WSMan:\localhost\Client\TrustedHosts
# 只追加必需的最少主机名。不加 -Concatenate 会清空已有登记。应避免用 '*' 全部放行
Set-Item WSMan:\localhost\Client\TrustedHosts -Value 'sv-app01,sv-app02' -Concatenate
# 显式指定凭据进行连接测试
$cred = Get-Credential sv-app01\Administrator
Invoke-Command -ComputerName sv-app01 -Credential $cred -ScriptBlock { hostname }
这里 TrustedHosts 的含义很关键。官方文档明确写道:“登记在 TrustedHosts 中的计算机不会被身份验证,客户端有可能因此把凭据发送出去”。5 也就是说,与其说是“可信对象的列表”,不如说是“放弃验证服务器身份这一警告的抑制列表”。3 如果 DNS 或 ARP 被篡改,就存在把管理员凭据发送给伪造服务器的风险。因此应避免通配符登记,只登记固定的主机名或 IP,并且数量要控制到最少。对于要长期使用的工作组环境或 DMZ,准备证书并构建 HTTPS(5986) 监听器,才是更稳妥的实务判断。3
另外需要留意,如果你开始把 Get-Credential 取得的凭据以明文形式写进脚本,那就是一个危险信号了。关于凭据的保存与传递定式,已整理在同期发布的《安全地在 PowerShell 中处理凭据》中。
在工作组环境里,还有一点容易被忽略,那就是密码是否为空。如果目标账户没有设置密码(空密码),远程命令将无法执行。1
3.1. 构建 HTTPS(5986) 监听器
如果要在工作组或 DMZ 环境中长期使用,就不能只靠 TrustedHosts 应付,而应搭建 HTTPS 监听器。步骤大致如下。12
- 准备用于服务器身份验证的证书。要求包括“是本地计算机的服务器身份验证证书”“CN(或使用者备用名称)与主机名一致”“在有效期内、未被吊销、且不是自签名证书”。如果有企业内部 CA,可以通过
https://<证书颁发机构服务器>/certsrv的 Web 注册页面申请。 - 将证书导入本地计算机的个人存储区。可以通过证书管理单元(在 MMC 中添加“证书”,并在向导中选择“计算机账户”)的 证书(本地计算机) > 个人 > 证书 进行确认。
-
创建 HTTPS 监听器。最简单的方式是执行下面这一行命令。
winrm quickconfig -transport:https如果有多张证书,想明确指定使用哪一张,也可以用 PowerShell 通过指纹来创建(指纹可以用
Get-ChildItem Cert:\LocalMachine\My确认)。New-Item -Path WSMan:\localhost\Listener -Address * -Transport HTTPS -CertificateThumbPrint '证书指纹' -Force - 在防火墙上允许 TCP 5986 的入站连接。
Enable-PSRemoting创建的规则是针对 HTTP(5985) 的,HTTPS 需要另行开放。 -
确认监听器是否已创建。
winrm enumerate winrm/config/listener
发起连接的一方只需加上 -UseSSL 即可。
Invoke-Command -ComputerName sv-app01.example.local -UseSSL -Credential $cred -ScriptBlock { hostname }
如果证书不满足条件,创建监听器时会出现“Cannot create a WinRM listener on HTTPS because this machine does not have an appropriate certificate.(错误代码 -2144108267 / 0x80338115)”这样的错误。这时应依次检查证书的有效期、颁发对象是否与主机名一致、增强型密钥用法中是否包含“服务器身份验证”、以及证书路径是否有效。12
4. Invoke-Command ── “对 20 台机器做同一件事”的基本用法
Remoting 的主角是 Invoke-Command。把多台机器传给 -ComputerName,把“要在远程做的事”写进 -ScriptBlock。6 从只读的盘点操作开始,是安全运维的铁律。
$servers = 'sv-app01', 'sv-app02', 'sv-db01'
# 打补丁后的状态确认 ── 只是读取,可以放心执行
$result = Invoke-Command -ComputerName $servers -ScriptBlock {
# 这个代码块内部是在“远程一侧”执行的
$os = Get-CimInstance Win32_OperatingSystem
[PSCustomObject]@{
LastBoot = $os.LastBootUpTime # 是否已完成重启
SpoolerRun = (Get-Service -Name Spooler).Status # 业务所需服务的状态
FreeGB = [math]::Round((Get-PSDrive C).Free / 1GB, 1)
}
}
# 哪个结果来自哪台服务器,可以通过 PSComputerName 分辨
$result | Sort-Object PSComputerName |
Select-Object PSComputerName, LastBoot, SpoolerRun, FreeGB |
Export-Csv -Path .\patch-check.csv -NoTypeInformation -Encoding UTF8
对每台服务器的连接是并行处理的,默认的并发数(ThrottleLimit)为 32。7 结果会按到达顺序混杂返回,因此需要像上面的示例那样,用自动附加的 PSComputerName 属性重新排序。8
4.1. 变量的传递方式 ── $using: 与 -ArgumentList
ScriptBlock 是在远程执行的,本地变量并不会直接可见。把值带过去的方法有两种。13
$threshold = (Get-Date).AddDays(-30)
# 方法 1: $using: ── 把调用方变量的“值的副本”嵌入到远程一侧
Invoke-Command -ComputerName $servers -ScriptBlock {
(Get-ChildItem 'D:\AppLogs' -Filter *.log |
Where-Object LastWriteTime -lt $using:threshold).Count
}
# 方法 2: -ArgumentList ── 在 ScriptBlock 一侧的 param 中接收(参数较多时更易读)
Invoke-Command -ComputerName $servers -ScriptBlock {
param($limit)
(Get-ChildItem 'D:\AppLogs' -Filter *.log |
Where-Object LastWriteTime -lt $limit).Count
} -ArgumentList $threshold
通过 $using: 传递的值,在远程一侧是独立的副本。即使在远程一侧改写,本地的变量也不会随之改变。13
4.2. 返回的是“快照”── 反序列化后的对象
这是使用 Remoting 时最先让人困惑的地方。由于活的 .NET 对象无法跨越网络,远程的输出会被序列化为 XML(CLIXML) 后发送,并在本地还原为反序列化后的对象。这只是执行那一刻各属性的快照,不带方法。87
例如,在本地接收 Get-Service 的结果后,无法对它调用 .Stop()。如果想停止服务,就应该在 ScriptBlock 内部执行 Stop-Service ── 也就是说,正确的做法是把角色分开:操作在远程一侧完结,带回本地的只是用于报告的数据。属性的筛选、整理、转成 CSV 等本地加工,可以像平时使用 PowerShell 那样进行(这部分的基本操作可以参考《PowerShell 命令基础》)。
5. Enter-PSSession 与 New-PSSession ── 交互与复用
想对单台机器做交互式排查时,用 Enter-PSSession。提示符会变成 [sv-app01]: PS>,输入的命令会在远程执行,用 exit 退出。11 与远程桌面不同,它不会带来画面,但如果只是“看看日志”“确认一下设置”,这种方式反而更快,连接同样要求是 Administrators 组的成员。11
另一方面,每次用 -ComputerName 调用 Invoke-Command,都会重新建立并关闭连接。14 如果要向同一批服务器多次发送命令,用 New-PSSession 创建持久会话并反复使用会更快,而且远程一侧的变量和状态会在多条命令之间保持。1415
# 只建立一次会话,通过变量 $s 反复使用
$s = New-PSSession -ComputerName $servers
try {
# 第 1 次: 在远程一侧创建变量 $hotfix
Invoke-Command -Session $s { $hotfix = Get-HotFix | Sort-Object InstalledOn -Descending }
# 第 2 次: 前一条命令创建的变量可以直接使用(会话保持了状态)
Invoke-Command -Session $s { $hotfix | Select-Object -First 5 }
}
finally {
# 即使中途出错或被中断,也一定要释放(回收远程一侧的资源)
Remove-PSSession $s
}
6. 陷阱 ── second hop,以及 SSH 这一选项
6.1. second hop(双跳)问题
这是现场最有名的一道墙。从本地 PC(A) 通过 Remoting 进入服务器 B,再从 B 内部尝试读取 \\fs01\share(服务器 C)时会被拒绝访问。默认的 Kerberos/NTLM 认证是一种不把凭据本身发送给 B 的安全方式,因此 B 无法代表你去向 C 认证。39
应对方法有多种,官方文档按推荐顺序做了整理。9 只列出主要几种如下。
- 在 ScriptBlock 内显式传递凭据 ── 不需要修改服务器一侧的配置,最为方便。通过
$using:cred把凭据传给内层的 Invoke-Command。9 但由于凭据对象会传到中继服务器(B)的会话中,一旦 B 被攻破,传过去的凭据也可能被利用,因此前提是只有在完全信任 B 的情况下才能使用,而且传递的账户也应是在 C 一侧仅拥有最小必要权限的专用账户。 - 基于资源的 Kerberos 约束委派 ── 不保存凭据,而是在被访问方(C)一侧配置“接受来自 B 的委派”。无需域管理员权限即可配置,是安全性与配置复杂度之间平衡较好的一个选项。9
- JEA(Just Enough Administration) ── 一种 PowerShell 机制,通过准备一个只允许“该业务所需命令”的专用终结点来收窄权限。如果配置为使用虚拟账户,使用者就能以非管理员凭据连接,同时只能执行被允许的管理命令。16 在 second hop 的场景下,这可以理解为:不给中继服务器(B)分发管理员凭据,而是开一个只能执行包含访问 C 在内的定型作业的窗口。9
- CredSSP ── 凭据会被缓存到远程服务器上,一旦该服务器被攻破,凭据也会随之被窃取。默认为禁用状态,启用应仅限于最值得信赖的环境。9
# 最简便的规避方式: 通过 $using:cred 把凭据传给内层的 Invoke-Command
# 外层(sv-app01)用自己的凭据连接,传给内层的则是在 fs01 一侧
# 只拥有最小必要权限的专用账户(不分发管理员凭据)
#
# 【前提】内层调用是"从 sv-app01 到 fs01 的一次新的 Remoting 连接",因此需要:
# 1. sv-app01 能够到达 fs01 的 WinRM(5985/5986)
# 2. 若是工作组环境或按 IP 地址指定,需要 sv-app01 一侧的 TrustedHosts 中已登记 fs01
# 3. $cred 是在 fs01 上有效的账户(域账户,或 fs01 的本地账户)
# 不确认这些就直接照搬使用,很容易出现"本地能跑,但从中继服务器执行就失败"的情况
$cred = Get-Credential CONTOSO\svc-fileread
Invoke-Command -ComputerName sv-app01 -ScriptBlock {
Invoke-Command -ComputerName fs01 -Credential $using:cred -ScriptBlock { hostname }
}
与其“经由 B 去读 C 上的文件”,不如先考虑能否改为从本地直接对 C 执行 Invoke-Command ── 这才是成本最低的解决方案。
6.2. PowerShell 7 还可以选择基于 SSH 的 Remoting
从 PowerShell 6.0 开始,可以用 SSH 代替 WinRM 进行 Remoting 连接。Invoke-Command / Enter-PSSession / New-PSSession 都新增了 -HostName、-UserName、-KeyFilePath 这一组 SSH 专用参数集,可以实现跨 Windows 和 Linux 的管理。2 连接目标需要有 SSH 服务器以及 PowerShell 的 SSH 子系统配置,目前尚不支持 WinRM 方式所具备的终结点配置或 JEA 这类功能。2 在混有 Linux 服务器的环境,或者想统一采用密钥认证运维的场合,可以把它记在心里作为一个选项。Windows PowerShell 5.1 没有这项功能,如果需要用到,也可以成为迁移的一个动机(关于两者差异的全貌,可参考同期发布的《Windows PowerShell 5.1 与 PowerShell 7 的差异》)。
顺带一提,Remoting 的会话不会像 RDP 那样创建桌面会话。“在远程运行”这句话在两者之间的含义有何不同,已经在《如何理解 Windows 的会话隔离》中整理过。
7. 连不上时的排查方法
初学者放弃 Remoting 的原因,大多是“连不上”。而且失败的原因,可能出在服务、监听器、防火墙、认证、权限中的任何一个环节。按从上游到下游的顺序逐一排除,就不会迷失方向。
7.1. 排查顺序
- 先看连通性。从发起连接的一方执行
Test-WSMan -ComputerName sv-app01。如果这一步能通,说明 WinRM 服务、监听器、防火墙都还活着(认证与权限的问题仍可能存在)。如果不通,进入下一步。 - 看远程一侧的 WinRM 服务是否在运行。服务器版的启动类型是自动,但客户端版 Windows 的 WinRM 服务默认是禁用的。1 用
Get-Service WinRM确认,如有需要就执行Enable-PSRemoting(一并完成服务启动、自动启动化、监听器、防火墙例外、会话配置)。4 -
看监听器是否在监听。在远程一侧执行下面的命令,确认
ListeningOn是否为空。如果为空,常见原因是通过组策略下发监听器时配置有误。1Get-WSManInstance winrm/config/listener -Enumerate - 看网络配置文件。在客户端版上,如果网络是公用网络,
Enable-PSRemoting本身就会因“Unable to check the status of the firewall”而失败。可以把配置文件改为专用网络,或加上-SkipNetworkProfileCheck。1 - 看防火墙规则。即使是服务器版,在公用网络配置文件下也会是“仅允许来自同一子网”的规则。如果要从其他子网连接,就需要调整规则(请先用
Get-NetFirewallRule确认规则名称再修改,规则名称会因 Windows 版本而不同)。1 - 看是否满足认证方式的条件。在工作组、非域成员、以及按 IP 地址指定的情况下,无法使用 Kerberos 而只能用 NTLM,因此登记 TrustedHosts(或使用 HTTPS)以及显式指定
-Credential都是必需的。目标账户不能使用空密码。1 - 看是否有连接所需的权限。能连接到默认终结点的,只有远程一侧 Administrators 的成员。来自其他域的用户或本地账户,默认会得到标准用户级别的令牌,无法以管理员身份操作(如有需要可以用
LocalAccountTokenFilterPolicy,但这会对所有用户禁用 UAC 的远程限制,请在理解其影响后再使用)。1 - 确认终结点的 PowerShell 版本。如果已经连上了,却提示“找不到这个 cmdlet”,很可能像第 2 章说的那样,进入的是 Windows PowerShell 5.1 一侧的终结点。可以用
Invoke-Command -ComputerName sv-app01 { $PSVersionTable.PSVersion }确认,如有需要用-ConfigurationName显式指定。10
7.2. 常见错误信息的解读方式
错误文本几乎都是固定套路,与其说要背下来,不如养成“看到这句话就去查这里”的对照习惯,更实用。1
| 错误信息(节选) | 常见原因 | 首先查看的地方 |
|---|---|---|
Access is denied. You need to run this cmdlet from an elevated process. |
本地的 PowerShell 不是以管理员权限运行 | 用“以管理员身份运行”重新打开 |
ACCESS IS DENIED |
目标一侧 Remoting 未启用 / 连接用户不属于 Administrators / 其他域或本地管理员的令牌受限 | 在目标一侧执行 Enable-PSRemoting、用 -Credential 指定管理员,如有需要检查会话配置的权限或 LocalAccountTokenFilterPolicy |
The connection to the remote host was refused. Verify that the WS-Management service is running on the remote host and configured to listen for requests on the correct port and HTTP URL. |
WinRM 服务已停止、没有监听器、端口不对 | Get-Service WinRM、枚举监听器、检查端口设置 |
The client cannot connect to the destination specified in the request. Verify that the service on the destination is running and is accepting requests. |
监听器的 ListeningOn 为空(策略配置有误)、受代理影响 |
枚举监听器、检查 New-PSSessionOption 的代理设置 |
The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. |
工作组环境、非域成员、按 IP 地址指定 | 登记 TrustedHosts + -Credential,或参照 3.1 构建 HTTPS |
Unable to check the status of the firewall(执行 Enable-PSRemoting 时) |
客户端版上网络是公用网络 | 改为专用网络,或加上 -SkipNetworkProfileCheck |
The WS-Management service cannot complete the operation within the time specified in OperationTimeout. |
处理耗时过长、对方负载过高 | 用 New-PSSessionOption -OperationTimeout 延长超时时间 |
The total data received from the remote client exceeded allowed maximum. |
返回的数据量过大 | 在 ScriptBlock 内先汇总、筛选后再返回,如有需要调整配额 |
排查的诀窍是,逐一确定“是本地的问题、路径的问题,还是对方的问题”。先用 Test-WSMan 是否能通,来区分出路径和对方服务这一层;通过之后再出现的错误,则集中在认证与权限上。养成这两段式的思路,就不会在原因不明的情况下反复瞎改配置。
8. 实务定式(判断表)
| 论点 | 选项 | 判断标准 |
|---|---|---|
| 交互式排查单台机器 | RDP / Enter-PSSession | 需要画面就用 RDP,命令能解决就用更轻量的 Enter-PSSession11 |
| 对多台机器执行同一处理 | 逐台手动操作 / Invoke-Command | 超过 3 台就用 Invoke-Command。默认最多并行 32 台67 |
| 需要多次发送命令 | 每次用 -ComputerName 连接 / 复用 New-PSSession | 需要交互式反复往返的调查场景,应复用会话。用完记得 Remove-PSSession14 |
| 工作组的认证 | TrustedHosts(HTTP) / HTTPS 监听器 | 临时使用就用最小限度的 TrustedHosts。要长期使用就构建 HTTPS(步骤见 3.1)5312 |
| second hop 的应对 | 显式传递凭据 / 基于资源的委派 / CredSSP | 先选不需要修改配置的显式传递方式。若是长期使用则选基于资源的委派。CredSSP 是最后手段9 |
| 最先执行的命令 | 变更类 / 只读类 | 一定先用 Get 系列命令做盘点。变更类命令先用支持 -WhatIf 的命令做预演,再正式执行 |
最后一行值得特别强调。Invoke-Command 既是“瞬间修好 20 台机器的命令”,同时也是“瞬间弄坏 20 台机器的命令”。所幸,像 Stop-Service、Set-ItemProperty 这类变更类 cmdlet 大多支持 -WhatIf,在 ScriptBlock 内部也可以照常使用。新脚本先在 1 台上试跑,再带 -WhatIf 面向全体机器演练一遍,最后才正式执行——养成这三段式的习惯,事故率会明显下降。
9. 总结
- Remoting 运行在 WinRM(WS-Management)之上,默认端口是 HTTP 5985 / HTTPS 5986。默认情况下只有远程一侧 Administrators 的成员才能连接,通信在认证完成后会被加密。
- Enable-PSRemoting 会启动 WinRM 服务、创建监听器、开启防火墙例外、启用会话配置。需要注意的是,配置的终结点是与执行它所用的 PowerShell 版本对应的。
- 域环境下 Kerberos 可以直接使用,工作组则需要 TrustedHosts + 显式凭据。TrustedHosts 是放弃身份验证的列表,因此要控制在最小范围。
- 批量执行用 Invoke-Command(默认并行 32 台),交互操作用 Enter-PSSession,需要保持状态就复用 New-PSSession。结果是不带方法的反序列化对象,因此操作应在远程一侧完结。
- 无法从连接目标进一步访问下一台机器(second hop)。首先考虑显式传递凭据,如果要长期使用,则应研究基于资源的 Kerberos 约束委派。
- “连不上”时,先用
Test-WSMan把路径和对方服务这一层排除掉,再把注意力集中在认证(TrustedHosts、凭据)与权限(Administrators)上。常见错误文本及对应查看点已汇总在第 7 章的表格中。 - 运维应先从只读操作入手。变更类操作按“1 台 → -WhatIf → 正式执行”三个阶段推进。应用到文件服务器盘点的具体示例,请参见同期发布的《用 PowerShell 盘点文件服务器》。
相关文章
- PowerShell 命令基础 ── 应先掌握的操作与安全使用方法
- PowerShell 实用命令合集 —— 积累日常工作中常用的小工具
- 用 PowerShell 盘点文件服务器 ── 容量调查与访问权限(ACL)审计
- PowerShell 中凭据的安全处理方式 ── 把明文密码逐出脚本
- 如何理解 Windows 的会话隔离 ── Session 0・RDP・多用户同时运行
- 正确处理 Windows 的模拟令牌 ── 线程级权限借用与安全的还原方式
相关咨询领域
小村软件有限公司提供通过 PowerShell 构建服务器・客户端批量管理机制、设计与评审内置 Remoting 的运维脚本,以及针对“连不上”“只在特定环境下认证失败”这类 WinRM/认证相关问题的调查服务。
参考链接
-
Microsoft Learn,about_Remote_Troubleshooting。关于 Windows Server 2012 及以后的 Windows Server 上 Remoting 默认启用、客户端版 Windows 的 WinRM 服务默认禁用、修改 WSMan: 驱动器的设置需要管理员权限、常见错误信息(拒绝访问/连接被拒绝/Unable to check the status of the firewall/与 TrustedHosts 及 HTTPS 相关的 WinRM 客户端错误/超时/超出配额)及其应对方式、用 Get-WSManInstance 枚举监听器以及 ListeningOn 为空的策略配置错误、公用网络下防火墙规则的行为、工作组环境下无法使用空密码账户,以及其他域或本地账户的管理员令牌限制与 LocalAccountTokenFilterPolicy。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11
-
Microsoft Learn,PowerShell remoting over SSH。关于 PowerShell 6 及以后可以使用基于 SSH 的 Remoting、New-PSSession/Enter-PSSession/Invoke-Command 新增了 -HostName/-UserName/-KeyFilePath 参数集、可跨平台运行,以及终结点配置和 JEA 目前尚不支持。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn,Security Considerations for PowerShell Remoting using WinRM。关于 Remoting 使用 WinRM(WS-Management 的微软实现)、默认端口为 HTTP 5985/HTTPS 5986、默认只有 Administrators 组成员可以连接且会话在用户上下文中运行、认证完成后通信会被加密、TrustedHosts 只是身份验证错误的抑制列表,以及 second hop 问题的背景。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12
-
Microsoft Learn,Enable-PSRemoting。关于 Enable-PSRemoting 所执行操作的清单(启动 WinRM 服务并设为自动启动、创建监听器、开启防火墙例外、启用会话配置并修改安全描述符)、Windows Server 上默认启用、客户端版在公用网络下的限制与 SkipNetworkProfileCheck,以及会为执行时所用的版本配置对应终结点。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn,Installation and configuration for Windows Remote Management。关于 WinRM 2.0 默认监听端口为 5985/5986、域账户选用 Kerberos・本地账户选用 NTLM、Kerberos 在工作组下无法使用而仅限于域、TrustedHosts 中的计算机不会被身份验证而可能导致凭据被发送出去,因此应控制在最小范围。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn,Invoke-Command。关于 Invoke-Command 可以用单条命令在多台计算机上执行命令、-ComputerName 的临时连接与 -Session 使用 PSSession 的区别,以及 -ArgumentList、-FilePath 等参数。 ↩ ↩2 ↩3
-
Microsoft Learn,PowerShell Remoting FAQ。关于并发连接数默认值为 32、可通过 ThrottleLimit 参数修改、远程命令的输出会被序列化为 CLIXML 并以反序列化对象(不带方法)的形式返回,以及 Invoke-Command 的结果会附加用于区分来源的属性。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn,about_Remote_Output。关于远程命令的输出经过序列化/反序列化后会变成仅含属性的快照,以及结果按到达顺序返回,因此需要用 PSComputerName 重新排序。 ↩ ↩2 ↩3
-
Microsoft Learn,Making the second hop in PowerShell Remoting。关于 second hop 问题的场景、应对方法一览及推荐顺序(CredSSP、基于资源的 Kerberos 约束委派、JEA 等)、CredSSP 会把凭据缓存到远程一侧因而在遭入侵时存在风险且默认禁用,以及在 ScriptBlock 内通过 $Using:cred 传递凭据的示例。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn,Migrating from Windows PowerShell 5.1 to PowerShell 7。关于在启用了 WinRM 的环境中,PowerShell 7 默认会使用 Windows PowerShell 5.1 已有的终结点(Microsoft.PowerShell)进行连接,以及需要执行 Enable-PSRemoting 才能创建 PowerShell 7 自身的终结点。 ↩ ↩2
-
Microsoft Learn,Enter-PSSession。关于 Enter-PSSession 会与单台远程计算机建立交互式会话、用 exit/Exit-PSSession 结束、需要是远程一侧 Administrators 组的成员,以及按 IP 地址指定时需要 HTTPS 配置或 TrustedHosts 登记。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn,How to configure WINRM for HTTPS(KB 2019527)。关于 HTTPS 监听器所需的证书要求(本地计算机的服务器身份验证证书、CN 与主机名一致、未过期・未吊销・非自签名)、通过证书管理单元确认的步骤、用 winrm quickconfig -transport:https 进行配置、用 winrm enumerate winrm/config/listener 进行确认、Windows 7 及以后的 HTTP 5985/HTTPS 5986 端口,以及在没有合适证书时出现的错误 0x80338115 与应检查的证书属性。 ↩ ↩2 ↩3
-
Microsoft Learn,about_Remote_Variables。关于用于在远程执行的命令中使用本地变量的 $using: 作用域修饰符、在远程会话中值会以独立副本的形式传递,以及序列化会导致方法丢失。 ↩ ↩2
-
Microsoft Learn,New-PSSession。关于 New-PSSession 会创建持久连接(PSSession)、用于执行需要共享数据的多条命令、指定 -ComputerName 时会创建临时连接并在每条命令后关闭,以及同样支持基于 SSH 的连接。 ↩ ↩2 ↩3
-
Microsoft Learn,Running Remote Commands。关于通过 Invoke-Command 执行脚本文件(-FilePath),以及在用 New-PSSession 创建的持久会话中,变量等状态会在多条命令之间保持。 ↩
-
Microsoft Learn,Overview of Just Enough Administration (JEA)。关于 JEA 是一种可对 PowerShell 管理的对象实现委派管理的安全技术、可以限定能够执行的 cmdlet・函数・外部命令、通过虚拟账户或组托管服务账户减少管理员账户的数量,以及可通过转录和日志了解实际执行了什么。 ↩
相关文章
共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。
PowerShell 中凭据的安全处理方式 ── 把明文密码逐出脚本
本文整理将 PowerShell 脚本中的明文密码迁移到安全存储的步骤。讲解 SecureString 的真实面貌与局限、Export-Clixml 基于 DPAPI 保存的原理,直至 SecretManagement/SecretStore 的适用场景。
PowerShell 的执行策略与脚本签名 ── 从「用 Bypass 蒙混过关」的运维方式毕业的实务指南
PowerShell 的执行策略『不是安全边界,而是一种安全装置』。本文梳理 RemoteSigned 等策略的差异、作用域的优先顺序、Mark of the Web 与 Unblock-File、脚本签名,以及公司内部分发的现实运维方式。
PowerShell脚本运行慢时该看哪里 ── 数组・管道・匹配的诀窍
整理 PowerShell 脚本变慢的常见原因。从数组 += 导致 O(n^2) 的原理、管道与 foreach 的差异、匹配的哈希表化、文件 I/O 的改善,到正确的测量方法,从实务角度进行讲解。
不再使用 Write-Host ── PowerShell 的输出流与日志设计
本文整理 PowerShell 六个输出流的用法区分、Write-Host 存在的问题与正确的使用场景、函数返回值被污染的原因、通过 -Verbose 与 -InformationVariable 实现调用方控制,以及结构化日志的留存方法。
PowerShell 的并行处理 ── ForEach-Object -Parallel 与作业(Job)的选用之道
本文从实务角度整理 ForEach-Object -Parallel、Start-ThreadJob、Start-Job 的区别与选用之道,$using: 与线程安全性,ThrottleLimit 的确定方法,以及反而会变慢的情形。
相关主题
与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。
Windows 技术主题
汇整 KomuraSoft LLC 关于 Windows 开发、故障调查与既有资产活用文章的主题中心。
常见问题
汇总了咨询这一主题时常见的问题。
- 执行 Enable-PSRemoting 会发生什么?
- 内部会执行 Set-WSManQuickConfig,从而启动 WinRM 服务并将其启动类型改为自动,创建可在任意 IP 地址上接收请求的监听器,启用 WS-Management 通信所需的防火墙例外,并启用会话配置(终结点)及远程访问权限。Windows Server 上默认已启用,但客户端 Windows 需要自行执行。只有接受连接的一方需要执行,发起连接的一方无需执行。
- 在工作组环境(无域)中使用 PowerShell Remoting 需要什么?
- 由于没有域就无法使用 Kerberos 认证,因此会改用 NTLM 认证。基本做法是在发起连接的一方把目标主机加入 WSMan 的 TrustedHosts 列表,并通过 -Credential 显式传入凭据。但由于加入 TrustedHosts 的对象不会被身份验证(即不做冒充检测)就把凭据发送出去,因此不要使用通配符,只登记必需的最少主机名,并尽量考虑构建 HTTPS(5986) 监听器。
- 为什么 Invoke-Command 返回的结果对象无法调用方法?
- 因为远程命令的输出需要经网络传送而被序列化为 XML(CLIXML),在本地则以反序列化后的对象形式还原。这只是执行那一刻各属性的快照,而不是活的对象,因此不带方法。像停止服务这样的操作,不应在本地对结果对象调用方法,而必须在 ScriptBlock 内部(即远程一侧)执行。
- second hop(双跳)问题是什么?
- 指从 PC A 通过 Remoting 进入服务器 B,再从 B 试图访问另一台服务器 C(例如文件服务器)时被拒绝的问题。默认的 Kerberos/NTLM 认证不会把凭据本身发送给 B,因此 B 无法以你的身份向 C 进行认证。应对方法包括在 ScriptBlock 内显式传递凭据、基于资源的 Kerberos 约束委派、CredSSP(凭据会传到远程一侧,风险更高)等,需要根据需求选择。
- PowerShell Remoting 是不是谁都能连接进来?
- 不是。默认情况下只有远程计算机 Administrators 组的成员才能连接。而且连接建立后的会话在所连接用户的上下文中运行,操作系统的访问控制会照常生效。尽管如此,对管理员而言这仍是一个强有力的入口,因此应结合防火墙规则审查、HTTPS 监听器、仅限必要管理员使用等多层防御手段一起运维。