I have been trying to use Jenkins to automatically test VMs, which includes copying new code into the VM, or running certain commands from the host into the VM using Powershell Scripts.
However, I've been running into an error trying to using "Invoke-Command" or "New-PSSession" to a hyper-V Windows 10 VM in Jenkins Freestyle and Pipeline projects.
This is the environment Jenkins is running on:
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
This is the Powershell Scripts that I've written in a "Windows Powershell" Build Step in a freestyle project:
# Win10-Clean is currently running and the credentials are for the Win 10 VM.
$ErrorActionPreference = "Stop"
$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}
I expect the output to be:
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 1854 5.14:10:42.5100000 Operating normally 8.3
PSComputerName : Win10-Clean
RunspaceId : 56151e46-5772-458f-8f11-9beba5491bc2
Name : ServerRemoteHost
Version : 1.0.0.0
InstanceId : fe09fc40-8434-4a7c-903b-b7b2c3f88506
UI : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture : en-US
CurrentUICulture : en-US
PrivateData :
DebuggerEnabled : True
IsRunspacePushed : False
Runspace : System.Management.Automation.Runspaces.LocalRunspace
Finished: SUCCESS
But what I got was this:
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\jenkins233354859509300046.ps1'"
An error has occurred which Windows PowerShell cannot handle. A remote session might have ended.
At C:\Windows\TEMP\jenkins233354859509300046.ps1:7 char:1
+ Invoke-Command -Credential $mycreds -VMName Build_VM -ScriptBlock {ho ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (Build_VM:String) [], PSRemotingDataStructureException
+ FullyQualifiedErrorId : PSSessionStateBroken
Build step 'Windows PowerShell' marked build as failure
Finished: FAILURE
After referring to the official microsoft web page regrding this issue, the possible causes are:
- VM exists but not running
- Guest OS does not support PowerShell Direct
Powershell isn;t avaliable in the guest yet:
- Operation system hasn't booted yet
- OS can't boot correctly
- Some boot time event needs user input
- A bug in current builds where credentials must be explicitly passed with -Credential. Run Restart-Service -Name vmicvmsession as a work around.
However, from the output from Jenkins, the VM that I've been trying to connect to is "Running" and it is booted up properly.
Then, I've tried to "Invoke-Command" and "New-PSSession" into the VM from the host directly and I am able to connect to the VM.
I've also tried the same thing in a Jenkins installed in a Windows 10 machine instead of a windows server 2019 and everything works.
As for the user administrative information, the user logged in that is running Jenkins is both the "administrator" and the "hyper-v administrator".
These are some of the references I used to debug and I'm not able to find out what the problem is:
Remote Access With PowerShell and Jenkins, but I'm not able to figure out how exactly this works.
EDITS:
I found a way around this issue. Please mind that this isn't the definite solution but a work around.
Instead of running Invoke-Command -Credential $mycreds -VMName $VMName -ScriptBlock {host}
, run this:
Invoke-Command -ComputerName "MyHostComputer" -ScriptBlock {Invoke-Command -Credential $mycreds -VMName $VMName -ScriptBlock {host}}
This command is essentially invoke-commanding
into the host machine and use the host machine to run the Invoke-Command
into the VM.
It is definitely not the perfect solution, but before anyone has a better solution I'll go with this for now.