目录
- 管理远程计算机
- 远程处理功能
- 会话管理与远程计算机的持久连接
- [创建和管理持久 PSSession](#创建和管理持久 PSSession)
- 断开连接
管理远程计算机
远程处理功能
远程处理是特定 Windows PowerShell 功能的名称,不要与更通用的远程连接概念混淆。 远程处理是一种通用方法,可将任何命令传输到远程计算机,使其在该计算机上进行本地运行。 你运行的命令不必在启动连接的计算机上可用。
许多 Windows PowerShell cmdlet 都具有 ComputerName 参数,此参数可使你在一台或多台远程计算机上收集数据和更改设置
这些 cmdlet 使用不同的通信协议,无需进行任何特殊配置即可在所有 Windows 操作系统上工作
这些 cmdlet 包括:
- Restart-Computer
- Test-Connection
- Clear-EventLog
- Get-EventLog
- Get-HotFix
- Get-Process
- Get-Service
- Set-Service
- Get-WinEvent
- Get-WmiObject
通常情况下,支持无需特殊配置的远程处理的 命令 具有 ComputerName 参数,但不具有 Session 参数。
若要在会话中查找这些 cmdlet,请输入:
powershell
Get-Command | where { $_.parameters.keys -contains "ComputerName" -and $_.parameters.keys -notcontains "Session"}
前期准备
- 客户端和被控主机都需要开启winrm
powershell
winrm quickconfig
- 客户端需要开启远程处理功能
powershell
Enable-PSRemoting -Force
这个命令会:
-
启动 WinRM 服务。
-
将 WinRM 服务的启动类型设置为"自动启动"。
-
配置防火墙规则,允许 WinRM 流量通过。
-
信任主机配置
powershell
Set-Item wsman:\localhost\client\trustedhosts "远程计算机IP或名称"
- 完成后,通常需要重启 WinRM 服务以使更改生效
powershell
Restart-Service WinRM
- 在建立正式连接前,可以先测试远程计算机是否已准备好接受 PowerShell 远程连接
powershell
Test-WSMan -ComputerName "远程计算机名或IP"
远程管理配置检查清单
为了确保远程管理功能正常工作,你可以使用以下清单进行检查:
- 网络连通性:确保本地计算机与远程计算机之间网络畅通(例如,可以互相 ping 通)。
- PowerShell 权限 :以管理员身份运行 PowerShell。
- 启用 PSRemoting :在远程计算机上已执行
Enable-PSRemoting -Force
。 - WinRM 服务状态 :确保远程计算机上的 WinRM 服务正在运行(
Get-Service WinRM
)。 - 防火墙规则 :确认防火墙允许 WinRM 流量(通常
Enable-PSRemoting
会自动配置)。 - 信任的主机 :在工作组环境中,已在本地计算机上使用
Set-Item wsman:\localhost\client\trustedhosts
将远程计算机添加为受信任主机。 - 用户权限:你使用的凭据在远程计算机上具有管理员权限。
- 执行策略 :远程计算机的 PowerShell 执行策略(Execution Policy)是否允许运行所需的脚本(可使用
Get-ExecutionPolicy
查看,如需设置可使用Set-ExecutionPolicy RemoteSigned
) - 是否对面被控主机也开启了winrm服务
交互式远程会话(一对一)
要启动一个交互式的远程会话 (类似于使用 SSH),进入一个仿佛直接操作远程计算机的命令行环境,可以使用 Enter-PSSession
命令:
powershell
Enter-PSSession -ComputerName "远程计算机名或IP" -Credential "用户名"
系统会提示你输入该用户对应的密码。执行成功后,命令提示符会变成 [远程计算机名或IP]: PS>
的格式,表示你当前的操作都在远程计算机上生效。
要退出交互式会话,回到本地 PowerShell 环境,只需执行:
powershell
Exit-PSSession
执行远程命令和脚本(一对多)
- 执行单条命令
powershell
Invoke-Command -ComputerName "远程计算机名或IP" -ScriptBlock { 你的命令 } -Credential "用户名"
这里会让你输入登录目标主机的密码,输入的密码是你指定的这个Credential
参数的用户名的密码
输入密码正确就执行成功了
- 执行脚本文件
powershell
Invoke-Command -ComputerName "远程计算机名或IP" -FilePath "本地脚本路径" -Credential "用户名"
- 对多台进行操作
powershell
$computers = "Server01", "Server02", "Server03" # 将计算机名或IP放入数组
Invoke-Command -ComputerName $computers -ScriptBlock { 你的命令 } -Credential "用户名"
Credential参数
上面说了一个就是直接给用户名没给密码,如果希望直接用脚本进行管理的话,每次都需要弹出来窗口上输入密码这会比较麻烦,所以我们可以先做好一个Credential参数值直接登入,当然这是有风险的,因为你的密码直接嵌入脚本里面:
powershell
$username = "用户名"
$password = ConvertTo-SecureString "你的密码" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
# 然后在 -Credential 参数中使用 $credential 变量
Enter-PSSession -ComputerName "远程计算机名或IP" -Credential $credential
常见远程处理技术
认证方式
此参数在复杂网络环境中至关重要。以下是几种常见机制的对比:
实际案例
1.连接到非标准端口并使用 SSL
假设目标服务器 ServerA
的 WinRM HTTPS 监听在端口 9999
,并且你信任其自签名证书(通过 -SessionOption
跳过部分检查)。
powershell
# 创建一个跳过CA检查和CN检查的会话选项(测试环境常用,生产环境请使用有效证书)
$so = New-PSSessionOption -SkipCACheck -SkipCNCheck
# 建立交互式会话
Enter-PSSession -ComputerName ServerA -Port 9999 -UseSSL -SessionOption $so -Credential (Get-Credential)
2.在工作组环境中使用特定认证方式
你的计算机和工作组中的计算机 192.168.1.100
都需要已配置 WinRM
powershell
# 1. 先将目标IP添加到本地TrustedHosts(信任所有主机,仅供参考,请注意安全风险)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.1.100" -Force
# 2. 使用Basic认证并连接(必须配合SSL)
$cred = Get-Credential # 输入192.168.1.100上的本地用户名和密码
Invoke-Command -ComputerName 192.168.1.100 -UseSSL -Authentication Basic -Credential $cred -ScriptBlock { Get-Service WinRM } -Port 5986
3.使用 CredSSP 实现双跳认证
CredSSP 将凭据缓存在远程服务器,使用 CredSSP 会使你面临潜在的凭据盗窃攻击。 如果远程计算机被攻破,攻击者将有权访问用户的凭据。 默认情况下,CredSSP 在客户端和服务器计算机上都处于禁用状态。 应该仅在最受信任的环境中启用 CredSSP。 例如,连接到域控制器的域管理员可能已启用 CredSSP,因为域控制器是高度可信任的。
假设你从本地客户端需要先登录到跳板机 JumpServer
,然后从跳板机访问另一台内部服务器 AppServer
上的资源。
在跳板机 (JumpServer
) 上启用 CredSSP 服务端(以管理员身份运行):
powershell
Enable-WSManCredSSP -Role Server
在你的本地客户端上启用 CredSSP 客户端并指定委托:(以管理员身份运行)
powershell
Enable-WSManCredSSP -Role Client -DelegateComputer "JumpServer"
建立到跳板机的会话并使用 CredSSP:
powershell
$cred = Get-Credential
$session = New-PSSession -ComputerName JumpServer -Credential $cred -Authentication CredSSP
Invoke-Command -Session $session -ScriptBlock {
# 现在可以从 JumpServer 访问 AppServer 上的资源了
Get-Item \\AppServer\C$\SomeFile.txt
}
Remove-PSSession $session
4.连接到 32 位 PowerShell 端点
在某些需要兼容旧版32位应用程序或脚本的场景下,可能需要连接到此端点
powershell
Invoke-Command -ComputerName LegacyServer -ConfigurationName "microsoft.powershell32" -ScriptBlock {
# 这里运行在32位环境中
[Environment]::Is64BitProcess # 会返回 False
}
5.基于资源的 Kerberos 约束委派
从 Windows Server 2012 开始,可以放弃使用 CredSSP,而改为使用约束委派。 约束委派通过使用安全描述符而不是服务器名称允许列表来实现服务票证的委派。 这允许资源确定哪些安全主体可以代表另一个用户请求票证。 无论域的功能级别如何,基于资源的约束委派都能正确工作。
约束委派需要:
- 访问与运行 Windows PowerShell 远程处理命令的主机计算机位于同一域中的域控制器。
- 访问托管你尝试从中间远程服务器访问的远程服务器的域中的域控制器。
设置权限的代码需要一台使用 Active Directory PowerShell 远程服务器管理工具 (RSAT) 运行 Windows Server 的计算机。 可通过运行以下两个命令,将 RSAT 添加为 Windows 功能:
powershell
Add-WindowsFeature RSAT-AD-PowerShell
Import-Module ActiveDirectory
要将基于资源的 Kerberos 约束委派从 LON-SVR1 授予到 LON-SVR2,然后再到 LON-SVR3,请运行以下命令:
powershell
Set-ADComputer -Identity LON-SVR2 -PrincipalsAllowedToDelegateToAccount LON-SVR3
有一个问题可能导致此命令失败。 密钥发行中心 (KDC) 有 15 分钟的 SPN 负缓存。 如果 LON-SVR2 已尝试与 LON-SVR3 通信,则存在一个负缓存条目。 需要使用以下方法之一来清除 LON-SVR2 上的缓存:
- 运行命令
klist purge -li 0x3e7
。 这是首选方法,也是最快的方法。 - 等待 15 分钟,使缓存自动清除。
- 重启 LON-SVR2。
要测试约束委派,请运行以下代码示例:
powershell
$cred = Get-Credential Adatum\TestUser
Invoke-Command -ComputerName LON-SVR1.Name -Credential $cred -ScriptBlock {Test-Path \\$($using:ServerC.Name)\C$ Get-Process lsass -ComputerName $($using:LON-SVR2.Name)
Get-EventLog -LogName System -Newest 3 -ComputerName $using:LON-SVR3.Name
}
6.Just Enough Administration
这种技术比较高级,暂时还handle不了,略过。感兴趣可以看下图官网解释:
会话控制
New-PSSessionOption
创建的会话选项对象可以精细控制会话行为,并通过 -SessionOption
参数传递给命令
powershell
# 创建一个会话选项,调整各种超时设置并跳过证书检查(测试用)
$options = New-PSSessionOption -IdleTimeout (60 * 60 * 1000) ` # 空闲超时1小时(单位毫秒)
-OperationTimeout (5 * 60 * 1000) ` # 操作超时5分钟
-OpenTimeout (2 * 60 * 1000) ` # 打开连接超时2分钟
-SkipCACheck ` # 跳过CA检查(测试环境自签名证书时)
-SkipCNCheck # 跳过CN检查(测试环境证书名称不匹配时)
# 在Invoke-Command中使用此会话选项
Invoke-Command -ComputerName SecureServer -UseSSL -SessionOption $options -ScriptBlock { Get-Process }
重要提醒: -SkipCACheck
和 -SkipCNCheck
会降低连接的安全性,仅建议在测试环境或受信任的隔离网络中使用。生产环境应部署有效的、由受信任CA签发的证书,并确保证书名称与主机名匹配。
参数发送到远程计算机
以下命令的意图是列出每台目标计算机上 10 条最近的安全事件日志项。 但此命令将不会按编写的那样起作用:
powershell
$Log = 'Security'
$Quantity = 10
Invoke-Command --Computer ONE,TWO --ScriptBlock {
Get-EventLog --LogName $Log --Newest $Quantity
}
原因在于变量 $Log
和 $Quantity
仅在本地计算机上有意义,在将这些值发送到远程计算机之前,这些值不会插入到脚本块中。 因此,远程计算机不能理解这些值。
此命令的正确语法如下所示:
powershell
$Log = 'Security'
$Quantity = 10
Invoke-Command --Computer ONE,TWO --ScriptBlock {
Param($x,$y) Get-EventLog --LogName $x --Newest $y
} --ArgumentList $Log,$Quantity
通过此语法,局部变量将传递给 Invoke-Command 的 ArgumentList 参数。 在脚本块中,创建了一个 Param() 块,其中包含与 --ArgumentList 值列表相同数量的变量,在本例中为两个。
Windows PowerShell 3.0 引入了简化的替代方法。 如果有一个局部变量 $variable
,并且希望将其内容包含在将在远程计算机上运行的命令中,可运行以下语法:
powershell
Invoke-Command --ScriptBlock { Do-Something $Using:variable } --ComputerName REMOTE
$Using:
前缀经本地和远程计算机正确处理,从而让 $Using:variable
被局部变量 $variable
的内容替换。
更多范围可以回顾:函数与模块变量的变量范围里查看
会话管理与远程计算机的持久连接
每台计算机都有一个名为 WSMan 的驱动器,其中包含许多与会话相关的配置参数,例如:
- 最大会话运行时
- 最长空闲时间
- 最大传入连接数
- 每个管理员的最大会话数
可运行dir WSMan:\localhost\shell
来浏览这些配置参数,并在同一位置更改它们。 还可以通过组策略控制许多设置。
创建和管理持久 PSSession
以下命令在 Server01 和 Server02 上创建远程会话,而会话对象将存储在 变量中$s
:
powershell
$s = New-PSSession -ComputerName Server01, Server02
建立会话后,你可以在这些会话中运行任何命令。 此外,由于会话是持久的,因此你可以从一个命令收集数据,并在另一个命令中使用它。
接着你可以统一管理不同session
例如,下面的命令在 变量中的会话中运行 Get-HotFix 命令,并将结果保存在 $s
变量中$h
:
powershell
Invoke-Command -Session $s {$h = Get-HotFix}
这些个session中都存了一个叫$h
的变量,所以后续操作依旧可以操作$h
powershell
Invoke-Command -Session $s {$h | where {$_.InstalledBy -ne "NTAUTHORITY\SYSTEM"}}
断开连接
如你所了解,当启动计算机和远程计算机都运行 Windows PowerShell 3.0 及更高版本时,可以断开与 PSSession 的连接。 断开连接通常需要手动进行。 在某些情况下,如果连接中断,Windows PowerShell 会自动将连接置于"断开连接"状态。 但是,如果手动关闭 Windows PowerShell 主机应用程序,则其不会断开与会话的连接,而只是将会话关闭。
命令 | 作用 | 会话是否还存在远程机上? | 使用场景 |
---|---|---|---|
Exit-PSSession |
退出交互模式,返回本地 | ✅ 存在 | 相当于"挂起对话",但不销毁 |
Disconnect-PSSession |
断开连接,保留远程会话 | ✅ 存在 | 想留着会话,稍后从本地或其他机器再连上 |
Remove-PSSession |
销毁远程会话 | ❌ 不存在 | 完全结束,不再保留 |
断开会话
powershell
Disconnect-PSSession -Session $session
会话不会销毁,只是把连接切断。
重新连接
powershell
Connect-PSSession -ComputerName Server01 -Name <会话名>
或者如果你已经有 $session
对象(比如导出来保存过),也可以直接:
powershell
Connect-PSSession -Session $session
- 断开 ≠ 关闭
Disconnect-PSSession
:会话还在远程机上保持。Remove-PSSession
:才是真的销毁。
- 自动断开
- 如果网络掉线、远程机重启,PowerShell 可能自动把状态变成
Disconnected
。 - 但是如果你直接关掉 PowerShell 窗口,会话就直接被关闭了(不会留在远程机)。
- 如果网络掉线、远程机重启,PowerShell 可能自动把状态变成
- 限制
- 只能 reconnect 自己的会话,不能接管别人开的。
- 需要 Windows PowerShell 3.0+。