Windows 10, Windows Server

Hyper-V | Assign Graphics Card to Virtual Machine



Microsoft Windows Logo Curious Blue Background

INTRO

A while back I wanted to see how I could get a graphics card installed in my Hyper-V Server 2019 Core host to map to a VM of my choosing. I was curious if a graphics card would add any benefit to the RDP experience or rendering of the display. I also wanted to test emulating the game Jak and Daxter: The Precursor Legacy (OpenGOAL port) in the VM and also use an Xbox controller connected to my laptop by USB which would be redirected into the RDP session to the VM with the graphics card mapped.

INIITIAL RESEARCH

The graphics card of choice for this was a NVIDIA Quadro K2200. The graphics card shows up via Device Manager when remote to my (Hyper-V 2019 Core) server. Device Manager is usable by installing Server Core App Compatibility Feature on Demand (FOD) on the server.

This will be very helpful for this guide. Initial research led to the following article by Microsoft, Deploy graphics devices using RemoteFX vGPU. Which no longer is accurate as it has a security vulnerability.

Additionally, mapping a USB device such as a Xbox controller to a VM worked with the following article, Introducing Microsoft RemoteFX USB Redirection: Part 1. This actually worked just fine, and the controller worked in the VM no problem. Now I just needed to get the graphics card working.

DISCRETE DEVICE ASSIGNMENT

So, to do this we need to use something called Discrete Device Assignment. You can read the following article for more information, Deploy graphics devices using Discrete Device Assignment. Essentially just follow the article and run a few scripts on the Hyper-V server. 

Microsoft explains how to do the steps individually, but at the end they include a script which does it all and is geared for NVIDIA cards. You will need to edit the scripts for your VM name and hardware.

Warning:

If the GPU is physically disconnected from the machine before it’s dismounted from the VM, the VM will fail to start with an error. What I have done below with the help of ChatGPT is have the location path of the GPU placed in a text file. In the case where a GPU fails, you should be able to edit the $LocationPath variable in the dismount script with that value to edit the VM in hope of avoiding the error.

MOUNTING A GPU TO A VM SCRIPT

PowerShell
# Configure the VM for a Discrete Device Assignment
$VM = "WR-CLI-VM-MPS"

# Define the output file path
$OutputFile = "C:\TEMP\discete-device-assignment-mount.txt"

# Set automatic stop action to TurnOff
Set-VM -Name $VM -AutomaticStopAction TurnOff | Out-File -FilePath $OutputFile -Append

# Enable Write-Combining on the CPU
Set-VM -GuestControlledCacheTypes $True -VMName $VM | Out-File -FilePath $OutputFile -Append

# Configure 32-bit MMIO space
Set-VM -LowMemoryMappedIoSpace 3GB -VMName $VM | Out-File -FilePath $OutputFile -Append

# Configure Greater than 32-bit MMIO space
Set-VM -HighMemoryMappedIoSpace 33280MB -VMName $VM | Out-File -FilePath $OutputFile -Append

# Find the Location Path and disable the Device
# Enumerate all PnP Devices on the system
$PnPDevs = Get-PnpDevice -PresentOnly

# Select only those devices that are Display devices manufactured by NVIDIA
$GPUDevs = $PnPDevs | Where-Object { $_.Class -Like "Display" -and $_.Manufacturer -Like "NVIDIA" }

# Select the location path of the first device that's available to be dismounted by the host
$LocationPath = ($GPUDevs | Get-PnpDeviceProperty -KeyName 'DEVPKEY_Device_LocationPaths').Data[0]

# Disable the PnP Device
Disable-PnpDevice -InstanceId $GPUDevs[0].InstanceId -Confirm:$False | Out-File -FilePath $OutputFile -Append

# Dismount the Device from the Host
Dismount-VMHostAssignableDevice -Force -LocationPath $LocationPath | Out-File -FilePath $OutputFile -Append

# Assign the device to the guest VM
Add-VMAssignableDevice -LocationPath $LocationPath -VMName $VM | Out-File -FilePath $OutputFile -Append

# Output the location path of the dismounted device to the console and the file
$LocationOutput = "The dismounted device location path is: $LocationPath"
Write-Output $LocationOutput | Tee-Object -FilePath $OutputFile -Append

REMOVING A GPU AND RETURNING IT BACK TO THE HOST SCRIPT

PowerShell
# Find the Location Path and disable the Device
# Enumerate all PnP Devices on the system
$PnPDevs = Get-PnpDevice

# Select only those devices that are Display devices manufactured by NVIDIA
$GPUDevs = $PnPDevs | Where-Object { $_.Class -Like "Display" -And $_.Manufacturer -Like "NVIDIA" }

# Select the location path of the first device that's available to be dismounted by the host
$LocationPath = ($GPUDevs | Get-PnpDeviceProperty -KeyName 'DEVPKEY_Device_LocationPaths').Data[0]

# Remove the device from the VM
Remove-VMAssignableDevice -LocationPath $LocationPath -VMName "WR-CLI-VM-MPS"

# Mount the device back in the host
Mount-VMHostAssignableDevice -LocationPath $LocationPath

# Enable the PnP Device
Enable-PnpDevice -InstanceId $GPUDevs[0].InstanceId -Confirm:$False

CONCLUSION

Once mapped to the VM you can run Windows Update or install the driver manually. The conclusion to my test was that the game ran just fine but the display lag with RDP session made playing impossible. It was a fun little test, but don’t waste your time ever trying to play a game over an RDP connection. Hopefully this guide will help others out there looking to support some actual business applications.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *