Hyper-V Windows 虚拟机共享显卡脚本

2025年3月30日 15点热度

在 Hyper-V Windows 虚拟机中共享物理机的显卡算力,是提升虚拟机能力的重要手段。尽管互联网上能查到相关教程,但是实际体验下来,并不容易。本文介绍一个一键脚本,帮助你轻松完成共享显卡的操作。

最近在研究 Hyper-V 中安装 Ubuntu 并开启 VGPU 的方法。尽管还没有掌握这个技术,但是意外发现了一个神级脚本,可以轻松安装 Hyper-V Windows 系统 VGPU。 这个脚本的项目名称是 1。在 DeepSeek 的帮助下,修订了原始脚本中的一个小错误。 脚本的突出特点是,通过部分窗体可视化,简化了操作流程。

一、系统环境要求

  • 操作系统

    • 宿主机:Windows 10/11 专业版(21H2或更新)或 Windows Server 2022
    • 虚拟机:Windows 10/11 企业版(需启用Hyper-V集成服务)
  • 硬件要求

    • 支持DirectX 12的独立显卡(NVIDIA 10系+/AMD RX 5000+)
    • 预留至少2GB显存空间
    • 虚拟机内存≥8GB

二、操作流程详解

步骤1:物理机操作

  1. 在物理机上安装好显卡驱动,确保能正常使用
  2. 在物理机上安装好虚拟机,确保能正常运行
  3. 将本文提供的代码保存为 PowerShell 脚本,名称为 ,保存到物理机任意目录
  4. 在物理机上运行
  5. 按提示选择虚拟机、显卡,等待脚本运行

步骤2:虚拟机操作

  1. 在虚拟机 C 盘根目录找到
  2. 文件名上点击右键,选择“以管理员身份运行”

PowerShell 脚本

#region 初始化配置
# 修改执行策略允许运行签名脚本(需管理员权限)
Set-ExecutionPolicy RemoteSigned -Force

# 设置错误处理模式:遇到错误立即停止执行
$ErrorActionPreference = "Stop"

#region 本地化配置
# 定义心跳服务和状态标签的默认值(英语)
$signalLabel = "HeartBeat"
$okLabel = "OK"

# 检测系统区域设置,如果是简体中文环境则替换为中文标签
if ((Get-WinSystemLocale).Name -eq "zh-CN") {
    $signalLabel = "检测信号"
    $okLabel = "确定"
}
#endregion

#region 虚拟机选择与预处理
# 通过图形界面选择目标虚拟机(单选框)
$vmobject = Get-VM | Out-GridView -Title "Select VM to setup GPU-P" -OutputMode Single
$vmid = $vmobject.VMId

# 停止虚拟机并进行预处理
Write-Host "Stopping VM"
$vmobject | Stop-VM -Force  # 强制停止确保状态变更

Write-Host "Disabling checkpoints for VM"
$vmobject | Set-VM -CheckpointType Disabled  # 禁用检查点

Write-Host "Enabling heartbeat service for VM"
$vmobject | Enable-VMIntegrationService -Name $signalLabel  # 启用心跳服务

# 清理现有GPU分区适配器(如果存在)
if ($vmobject | Get-VMGpuPartitionAdapter) { 
    $vmobject | Remove-VMGpuPartitionAdapter 
}

# 启动虚拟机并等待心跳服务就绪
Write-Host "Starting VM"
$vmobject | Start-VM
do {
    Start-Sleep 2
    $status = ($vmobject | Get-VMIntegrationService -Name $signalLabel).PrimaryStatusDescription
} while ($status -ne $okLabel)  # 轮询等待服务状态变为"OK"
#endregion

#region 建立远程会话
Write-Host "Connecting to VM"
$vmsess = New-PSSession -VMId $vmid  # 创建与虚拟机的PowerShell会话
#endregion

#region 物理GPU选择与驱动处理
# 通过图形界面选择物理GPU设备(单选框)
$dev = Get-PnpDevice -Class Display -Status OK | Out-GridView -Title "Select Card to setup GPU-P" -OutputMode Single

# 提取设备驱动信息
$props = $dev | Get-PnpDeviceProperty
$pnpinf = ($props | Where-Object {$_.KeyName -eq "DEVPKEY_Device_DriverInfPath"}).Data      # 获取INF文件路径
$infsection = ($props | Where-Object {$_.KeyName -eq "DEVPKEY_Device_DriverInfSection"}).Data  # 获取INF文件段落
$cbsinf = (Get-WindowsDriver -Online | Where-Object {$_.Driver -eq "$pnpinf"}).OriginalFileName  # 获取系统驱动路径

# 验证驱动可用性
if (-not $cbsinf) {
    Write-Host "Device not supported: $dev, inf: $pnpinf, cbs: $cbsinf"
    exit 1
}

#region GPU路径处理
# 转换设备实例ID为Hyper-V可识别的路径格式
$gpuName = $dev.FriendlyName
$path = $dev.InstanceId.Replace('\', '#').ToLower()  # 替换反斜杠并转小写

# 遍历可分区GPU列表进行路径匹配
$pvs = Get-VMHostPartitionableGpu
foreach ($pv in $pvs) {
    $name = $pv.Name.ToLower()
    if ($name.Contains($path)) {
        $path = $pv.Name  # 获取完整的设备路径
        break
    }
}

# 打印调试信息
Write-Host "============================"
Write-Host "Selected GPU: $gpuName"
Write-Host "INF File: $pnpinf"
Write-Host "Adapter Path: $path"
Write-Host "============================"
#endregion

#region 驱动文件复制
# 获取驱动文件信息
$inffile = (Get-Item -LiteralPath $cbsinf)
$drvpkg = $inffile.Directory  # 驱动包目录

# 在虚拟机中创建驱动存储目录
$hostdrvstorepath = Invoke-Command -Session $vmsess {
    New-Item -Path "$env:SystemRoot\System32\HostDriverStore\FileRepository" -ItemType Directory -Force
}

# 复制驱动文件到虚拟机
Write-Host "Copying driver package [$($drvpkg.FullName)] to VM..."
Copy-Item -LiteralPath $drvpkg.FullName -ToSession $vmsess -Destination $hostdrvstorepath -Recurse -Force

# 构建虚拟机内的完整INF文件路径
$vminfpath = Join-Path (Join-Path $hostdrvstorepath $drvpkg.Name) $inffile.Name
#endregion

#region 生成自动化脚本
# 在虚拟机系统盘创建初始化批处理文件
Invoke-Command -Session $vmsess -ScriptBlock {
    if (-not $prologWritten) {
        # 批处理文件头:创建临时目录
        Set-Content -LiteralPath "$env:SystemDrive\GPUPAdditionalSetup.bat" -Encoding UTF8 -Value @"
cd /d %TEMP%
set dirname=gpupaddlsetup%RANDOM%
mkdir %dirname%
cd %dirname%
"@
        $prologWritten = $true
    }
    # 添加驱动安装命令
    Add-Content -LiteralPath "$env:SystemDrive\GPUPAdditionalSetup.bat" -Encoding UTF8 -Value "start `"`" /wait rundll32 advpack.dll,LaunchINFSectionEx $using:vminfpath,$using:infsection,,4"
}

# 添加批处理文件尾部清理命令
$scriptWritten = Invoke-Command -Session $vmsess -ScriptBlock {
    if ($prologWritten) {
        Add-Content -LiteralPath "$env:SystemDrive\GPUPAdditionalSetup.bat" -Encoding UTF8 -Value @"
cd ..
rmdir /s /q %dirname%
"@
    }
    return $prologWritten
}
#endregion

#region 最终配置
# 再次停止虚拟机进行GPU分区配置
Write-Host "Stopping VM"
$vmobject | Stop-VM -Force

# 配置GPU-P分区适配器
Write-Host "Configuring GPU-P for VM"
$vmobject | Add-VMGpuPartitionAdapter -InstancePath "$path"  # 添加GPU分区适配器

# 设置VRAM、编解码和计算资源分配(单位:字节)
$vmobject | Set-VMGpuPartitionAdapter `
    -MinPartitionVRAM 80000000 `
    -MaxPartitionVRAM 100000000 `
    -OptimalPartitionVRAM 100000000 `
    -MinPartitionEncode 80000000 `
    -MaxPartitionEncode 100000000 `
    -OptimalPartitionEncode 100000000 `
    -MinPartitionDecode 80000000 `
    -MaxPartitionDecode 100000000 `
    -OptimalPartitionDecode 100000000 `
    -MinPartitionCompute 80000000 `
    -MaxPartitionCompute 100000000 `
    -OptimalPartitionCompute 100000000

# 配置虚拟机内存映射参数
$vmobject | Set-VM `
    -GuestControlledCacheTypes $true `
    -LowMemoryMappedIoSpace 1GB `
    -HighMemoryMappedIoSpace 32GB

Write-Host "Done"

# 显示后续操作提示
if ($scriptWritten) {
    Write-Host "重要提示:请以管理员身份在虚拟机中运行系统盘根目录的 GPUPAdditionalSetup.bat 文件以完成驱动安装。"
    Write-Host "该操作将启用视频编解码器和图形计算API支持。"
}
#endregion

泊松

人工智能爱好者,野生技术研究僧