我一直在尝试使用 Jenkins 自动测试虚拟机,包括将新代码复制到虚拟机中,或使用 Powershell 脚本将主机中的某些命令运行到虚拟机中。但是,我在尝试在 Jenkins Freestyle 和 Pipeline 项目中对 Hyper-V Windows 10 虚拟机使用“Invoke-Command”或“New-PSSession”时遇到了错误。
这是 Jenkins 运行的环境:
Windows Specifications:
Edition: Windows Server 2019 Standard
Version: 1809
OS build: 17763.379
Jenkins ver. 2.190.1
Hyper-V Manager: 10.0.17763.1
这是我在自由式项目的“Windows Powershell”构建步骤中编写的 Powershell 脚本:
# Win10-Clean is currently running and the credentials are for the Win 10 VM.
$VMName = "Win10-Clean"
$username = "username"
$pwd = "password"
$secpasswd = ConvertTo-SecureString $pwd -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("$username", $secpasswd)
Get-VM
Invoke-Command -Credential $mycreds -VMName$VMName -ScriptBlock {host}
Jenkins 的输出如下:
Running as SYSTEM
Building on master in workspace G:\ci_server_1\jenkins\workspace\powershell-testing-ground
[powershell-testing-ground] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Windows\TEMP\jenkins6936256398230803297.ps1'"
Name State CPUUsage(%) MemoryAssigned(M) Uptime Status Version
---- ----- ----------- ----------------- ------ ------ -------
Win10-Clean Running 0 1656 4.12:52:52.1170000 Operating normally 8.3
An error has occurred which Windows PowerShell cannot handle. A remote session might have ended.
+ CategoryInfo : OpenError: (Win10-Clean:String) [], PSRemotingDataStructureException
+ FullyQualifiedErrorId : PSSessionStateBroken
参考关于此问题的微软官方网页,可能的原因有:
- VM 存在但未运行
- 客户机操作系统不支持 PowerShell Direct
Powershell 在来宾中尚不可用:
- 操作系统尚未启动
- 操作系统无法正确启动
- 某些启动时事件需要用户输入
- 当前版本中存在一个错误,即必须使用 -Credential 明确传递凭据。运行 Restart-Service -Name vmicvmsession 即可解决问题。
但是,从 Jenkins 的输出来看,我尝试连接的虚拟机处于“正在运行”状态,并且已正确启动。
然后,我尝试直接从主机将“Invoke-Command”和“New-PSSession”插入 VM,并且能够连接到 VM。
我也在安装在 Windows 10 机器而不是 Windows Server 2019 上的 Jenkins 中尝试了同样的事情,一切正常。
至于用户管理信息,运行 Jenkins 的登录用户既是“管理员”,又是“hyper-v 管理员”。
这些是我用来调试的一些参考资料,但我无法找出问题所在:
使用 PowerShell 和 Jenkins 进行远程访问,但我不知道这究竟是如何工作的。
有人知道为什么会发生这种情况吗?
编辑:
我找到了解决这个问题的方法。请注意,这不是最终的解决方案,而是一种解决方法。
不要运行 ,而是Invoke-Command -Credential $mycreds -VMName $VMName -ScriptBlock {host}
运行以下命令:
Invoke-Command -ComputerName "MyHostComputer" -ScriptBlock {Invoke-Command -Credential $mycreds -VMName $VMName -ScriptBlock {host}}
这个命令本质上是invoke-commanding
进入主机,并使用主机运行Invoke-Command
进入虚拟机。
这绝对不是完美的解决方案,但在有人有更好的解决方案之前,我会采用这个解决方案。