In this post I will explain how you can retrieve information about a Hyper-V host from a guest virtual machine after booting from a WinPE 10 boot WIM.
The steps in this post draw from the guidance provided on Keith's Consulting Blog, which in turn was inspired by an article from Johan Arwidmark.
I will start by assuming you have an existing WinPE 10 boot WIM. This can be generated manually using the Deployment Tools installed via the ADK, or it could be generated via MDT or SCCM.
For the sake of simplicity, I will assume the following steps are performed on a server with the ADK installed, and with the boot WIM conveniently located at C:\Temp\winpe.wim
. I'll also assume you have access to a Windows Server 2012 R2 server with the Hyper-V role enabled.
- Let's start by creating a "mount point" for the boot WIM:
mkdir C:\Mount
- We will now mount the boot WIM:
dism /mount-wim /wimfile:C:\Temp\winpe.wim /index:1 /mountdir:C:\Mount
- At this point you will need to download and install the Microsoft Windows 10 Driver Kit, and copy devcon.exe to the %windir% directory of the mounted image. Note: You will need to change the source path for devcon.exe from x64 to x86 if you are working with a 32-bit boot WIM.
copy "C:\Program Files (x86)\Windows Kits\10\Tools\x64\devcon.exe" C:\Mount\Windows\devcon.exe
- Create a file named
C:\Mount\Windows\wvmic.vbs
with the content shown below. This script performs two primary tasks; firstly, it creates a fake service named TermServ, and secondly, it installs the VmIcKvpExchange driver. As explained by Johan, Hyper-V Data Exchange Services will only start if it can verify the existence of the Terminal Services service (even though it isn't actually required for Data Exchange Service to operate).
Function CreateFakeService(sName, sDisplayName, sPathName)
Dim objService
Dim objInParam
' Obtain the definition of the Win32_Service class.
Set objService = GetObject("winmgmts:root\cimv2").Get("Win32_Service")
' Obtain an InParameters object specific to the Win32_Service.Create method.
Set objInParam = objService.Methods_("Create").inParameters.SpawnInstance_()
' Add the input parameters.
objInParam.Properties_.item("Name") = sName
objInParam.Properties_.item("DisplayName") = sDisplayName
objInParam.Properties_.item("PathName") = sPathName
objInParam.Properties_.item("ServiceType") = 16
objInParam.Properties_.item("ErrorControl") = 0
objInParam.Properties_.item("StartMode") = "Manual"
objInParam.Properties_.item("DesktopInteract") = False
' Execute the method and obtain the return status.
CreateFakeService = objService.ExecMethod_("Create", objInParam).ReturnValue
End function
CreateFakeService "TermService", "Remote Desktop Service", "FakeService.exe"
Set oShell = CreateObject("Wscript.Shell")
oShell.Run "devcon install " & Chr(34) & "X:\Windows\System32\DriverStore\FileRepository\wvmic.inf_amd64_dc7abc857325efe9\wvmic.inf" & Chr(34) & " " & Chr(34) & "vmbus\{242ff919-07db-4180-9c2e-b86cb68c8c55}" & Chr(34), 0, 1
oShell.Run "cmd /c net start vmickvpexchange", 0, 1
Copy
C:\Windows\vmguest\support\amd64\Windows6.x-HyperVIntegrationServices-x64.cab
from an existing Windows Server 2012 R2 server with the Hyper-V role installed toC:\Temp\Windows6.x-HyperVIntegrationServices-x64.cab
. Note: You will need to copy the x86 version of the cabinet if you are working with a 32-bit boot WIM.Create
C:\Temp\Extacted
:
mkdir C:\Temp\Extracted
- Extract the content of
C:\Temp\Windows6.x-HyperVIntegrationServices-x64.cab
toC:\Temp\Extracted
:
expand C:\Temp\Windows6.x-HyperVIntegrationServices-x64.cab -f:* C:\Temp\Extracted
- Add wvmic.inf from the extracted cabinet to the WIM, being sure to reference DISM.exe from the ADK:
"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\DISM\dism.exe" /image:C:\Mount /add-driver /driver:C:\Temp\Extracted\amd64_wvmic.inf_31bf3856ad364e35_6.3.9600.16385_none_f2a11f2920629934\wvmic.inf
- Commit the changes to the WIM:
dism /unmount-wim /mountdir:C:\Mount /commit
At the point the boot WIM has been successfully configured, however, to ensure the Hyper-V Data Exchange Services are invoked, you must run C:\Windows\vmvic.vbs
after booting the WIM.
In my case, the WIM was used as part of an SCCM task sequence, so I added a step at the beginning of the sequence (after restating in WinPE) to invoke the script:
cscript.exe X:\Windows\wvmic.vbs
To ensure the script was only initiated when the task sequence was run on a Hyper-V guest, I applied two filters (the first evaluates the value of a built-in task sequence variable, and the second is a WMI query against the root\cimv2
namespace:
_SMSTSInWinPE=TRUE
SELECT model FROM win32_computersystem WHERE model = 'Virtual Machine'
Finally, we can return to our original goal: retrieving information about the Hyper-V host from the guest within WinPE. After running wvmic.vbs to install the Hyper-V Data Exchange Services, we can return the name of the Hyper-V host by reading the following registry value:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters\PhysicalHostName
For example, the following VBScript could be called from a task sequence to assign the name of the Hyper-V host to a variable named sHostName:
Set oShell = CreateObject("WScript.Shell")
sHostName = UCase(oShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters\PhysicalHostName"))