我在执行远程 powershell 脚本时遇到了麻烦,该脚本本来是用来更新应用程序的安装,以便在每天运行一次的任务管理器任务中自动测试。
这个相当简单的脚本(详情见下文)曾经成功运行了大约一年。突然它开始失败,因为无法执行远程 powershell 脚本。我不知道这背后的根本原因是什么。当地 IT 部门确保他们没有做任何改动。
(我应该指出,我可能可以用其他东西替换 powershell 脚本,但我不打算轻易放弃。除此之外,我想了解这里出了什么问题)
以下是常规设置:
未连接到域的 Windows Server 2008 R2 虚拟机,称为目标。u_target
分配给目标上的管理员组的本地用户。
域(我们称之为域 D)中的 Windows Server 2008 R2 虚拟机,称为源。域 D 上的用户u_source
被分配到源上的管理员组。
两个虚拟机上的 Powershell 均有 2.0 版本。
目标上的所有命令都以管理员权限执行u_target
,源上的所有命令都以管理员权限执行u_source
。我反复检查,确保 powershell 在所有情况下都以管理员身份启动。
大约一年前,我在两台虚拟机上启用了 psremoting,如下所示:
在目标上,u_target 在管理员 powershell 中执行
enable-psremoting -force
,
set-item wsman:\local\client\TrustedHosts -value 'source'
然后机器重新启动。
两个命令执行都没有错误。后来,当我遇到麻烦时,我将“source”替换为*,以确保问题不是由于拼写错误造成的。
在源上,u_source
在管理员 powershell 中执行
enable-psremoting -force
。此机器也已重新启动。
后来,当事情失败时,目标也被添加到这里的TrustedHosts中。
需要执行的脚本原则上如下所示:
$server = 'target' #(using the FQHN)
$username = 'u_target'
$password = 'u_targetpwd' #(the correct one, of course)
$pass = ConvertTo-SecureString -AsPlainText $password -Force
$Cred = New-Object System.Management.Automation.PSCredential -Argumentlist $username,$pass
$scbScriptBlock = {
# a valid script. For simplicity assume it's
Get-ChildItem C:\
}
Invoke-Command -ComputerName $server -Credential $Cred -ScriptBlock $scbScriptBlock
大约一周后,出现了以下错误消息:
[target] Connecting to remote server failed with following error messages :
The connection to the specified 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. For more information,
see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (:) [], PSRemotingTransportException
+ FullyQualifiedErrorID : PSSessionStateBroken
我尝试修复此问题或者找出问题所在:
- 阅读 about_Remote_TroublShooting 帮助主题。除了少数例外(见下文),我确信我按照其中的说明操作,但没有成功。
- 阅读文档
- 重新配置 WSMan(见上文)
- 使用 Get-Item 验证受信任主机设置,使用 Set-Item 创建它们(并且没有忘记重新启动 wsman)。
- 使用相关用户登录两台计算机,并验证他们仍然属于管理员组,且其密码仍然有效
- 用一个简单的脚本块替换原始脚本块,以确保它不是被损坏的脚本块。
- 验证计算机彼此了解(ping,从源到目标的测试连接)
- 已验证 u_target 在远程桌面会话中使用 powershell 登录到目标时能够执行脚本块中的命令
- 搜索了互联网。一条结果显示 target 上的 u_target 用户配置文件可能已损坏,但事实并非如此
- 已验证 WSMan 正在服务管理器中运行
- 在脚本中将“u_target”替换为“target\u_target”,然后从头开始尝试
- 多次重启有问题的虚拟机并重复上述所有操作
- 创建了具有类似设置的备用源和目标 VM(这些 VM 安装了 powershell 版本 3.0)。远程处理在这里也失败了。远程处理似乎可以很好地与一对域绑定的 VM 配合使用(昨天、今天我也无法让它工作),但我并不想这样。
- 在 Windows 日志 -> 应用程序和 Windows 日志 -> 安全部分检查目标的事件日志。虽然之前的脚本(当它仍然运行良好时)生成了登录事件,但现在那里什么都没有了。也没有错误。
- 检查了源和目标上的防火墙设置。我认为它们没问题,但也许我只是想相信“enable-psremoting”工具正确地完成了它的工作
- (并且,当然,检查脚本是否也因我在这个问题中使用的简单脚本块而失败,而不是我不应该在这里发布的原始脚本块)。
我的问题是:
当然是这个;-):您知道是什么原因导致脚本突然失败吗???
我不确定的是 WS-Management 正在监听的端口和 HTTP URL,我该如何检查?我执行了“winrm enumerate winrm/config/listener”,因为事件中的一些旧消息告诉我这样做,我在这里注意到主机名似乎未定义。CertificateThumbprint 似乎也没有值,但传输是 HTTP。
- 是否有任何已知的最新更新或补丁会导致 PS 远程处理出现问题?
- 管理员是否会希望在整个网络范围内应用某些典型设置,从而导致此类故障?
- 我还能在哪里查看(特定事件日志、事件 ID)?
我想到了一些更荒谬的想法,但也许不是太荒谬(?):
- 在脚本开始失败之前几乎正好一年的时间就已经设置好了虚拟机 - 是否有一些设置在一年后过期,否则我不会注意到但会导致这种影响?
- 安装 .net Framework 4.5.2 —— 不过,我很确定在那之后脚本仍然正常工作
- 是否有任何证书可能已经过期?
答案1
如果您为 WSMan 提供程序启用跟踪选项(至少在源服务器上,也可能在远程服务器上),您可能能够获得有关此类问题的更多信息。如果没有这个,记录的内容就不多。要启用跟踪日志记录,请执行以下操作:
Import-Module PSDiagnostics
Enable-PsWsmanCombinedTrace
<run your script>
Disable-PsWsmanCombinedTrace
查看 powershell 事件日志(应用程序和服务日志/Microsoft/Windows/PowerShell/Operational)
如果 WinRM 使用 SSL,则证书应该位于计算机帐户个人存储中。
答案2
您可以使用以下命令确认配置监听的端口:winrm get winrm/config
。这将包括诸如受信任的地址/主机、源是手动配置还是 GPO(将覆盖您的配置)以及是否启用了证书身份验证等信息。
检查源服务器和目标服务器上的 Windows 远程管理/操作事件日志。日志记录较弱,但如果出现错误,可能会记录在那里。
netstat 应该确认监听端口(下例中为 5985):
netstat -ano | findstr /i ":598"
TCP 0.0.0.0:5985 0.0.0.0:0 LISTENING 4
TCP 192.168.1.132:49223 192.168.1.131:5985 ESTABLISHED 972
TCP [::]:5985 [::]:0 LISTENING 4
如果您在源和目标上执行 netmon 数据包捕获以确认正在发生的网络活动,这也会有所帮助。
答案3
就我而言,问题是由 PS-Remoting 客户端上设置的 winhttp 代理收到“连接被拒绝”错误引起的:
netsh winhttp show proxy
我需要做的就是将其删除:
netsh winhttp reset proxy