hyper-v实战系列:使用powershell创建和复制虚拟机 - 详解

脚本说明

因为我经常需要帮客户配置系统环境(例如开发环境、数据库、github代码复现等),所以我几乎天天都在与虚拟机打交道,使用虚拟机可以非常方便地打快照和还原快照,非常适合调试环境之用。

我经常使用的宿主机(物理机)是windows server 2022,虚拟化平台是其自带的hyper-v, 而客户机(虚拟机中安装的系统)则基本集中上在windows 10, windows 11, windows 7, ubuntu server这几个系统。

所以我在这里贴几个常用的创建虚拟机和复制虚拟机的powershell脚本文件,每个脚本中的变量都需要稍加修改才能使用,这个请注意一下。同时,这些脚本文件其实稍加修改一下或者只需要修改一下系统镜像路径即可用于安装其他的操作系统(例如centos,opensuse等)

重要:这些脚本模板只是方便用于创建虚拟机,虚拟机中的系统还是得手动进行安装(当然你也可以通过应答文件来实现完全自动化安装,但这已经是操作系统安装的范畴了,可自行了解)

示例脚本

一般创建模板

创建虚拟机脚本的大致流程如下

定义需要由用户修改的变量:例如系统iso名称,虚拟机名称及存放路径等

定义一些默认配置的变量:如cpu个数,内存使用量,是否开启安全启动等

调用New-Vm命令创建虚拟机实例等

调用Set-VMFirmware调整虚拟机配置等

具体如下面的create-vm.ps1文件所示

$ErrorActionPreference = "Stop"
$vm_name = "test"
$root_folder = "F:\hyper-v_vms"
$os_iso ="F:\share_data\software\os\Windows 10 Enterprise LTSC 2021 (x64) - DVD (Chinese-Simplified)SW_DVD9_WIN_ENT_LTSC_2021_64BIT_ChnSimp_MLF_X22-84402.ISO" # 系统iso镜像
$os_disk_size = 80 * 1024 * 1024 * 1024  # 系统盘大小
# 默认设置
$version = "9.0"  # hyper-v版本
$vm_folder = Join-Path -Path $root_folder -ChildPath $vm_name  # 虚拟机目录
$os_disk_path = Join-Path -Path $vm_folder -ChildPath "Virtual Hard Disks\os.vhdx"  # 系统盘路径
$cpu_count = 4  # 分配的cpu核心数量
$memory = 4 * 1024 * 1024 * 1024  # 内存大小
$switch =  (Get-VMSwitch | Select-Object -First 1).Name  # 获取默认虚拟交换机
$secure_boot = "Off"  # 安全启动,值为Off或On
#$enable_tpm = $true  # 启动tpm,值为$true或$false
# 具体命令
New-VM -Name $vm_name -MemoryStartupBytes $memory -Generation 2 -Path $root_folder -NewVHDPath $os_disk_path -NewVHDSizeBytes $os_disk_size -SwitchName $switch -Version $version
if ($enable_tpm -eq $true) {
    Set-VMKeyProtector -VMName $vm_name -NewLocalKeyProtector
    Enable-VMTPM -VMName $vm_name
} else {
    Disable-VMTPM -VMName $vm_name
}
Add-VMDvdDrive -VMName $vm_name -Path $os_iso
Set-VMProcessor -VMName $vm_name -Count $cpu_count
Set-VMFirmware -VMName $vm_name -EnableSecureBoot $secure_boot -BootOrder (Get-VMDvdDrive -VMName $vm_name)  # 设置光驱为第一启动项

windows10创建脚本

该脚本与前面模板脚本的主要不同是关闭安全启动

具体如下面的create-win10.ps1文件所示

$ErrorActionPreference = "Stop"
$vm_name = "windows10"
$root_folder = "F:\hyper-v_vms"
$os_iso ="F:\share_data\software\os\Windows 10 Enterprise LTSC 2021 (x64) - DVD (Chinese-Simplified)SW_DVD9_WIN_ENT_LTSC_2021_64BIT_ChnSimp_MLF_X22-84402.ISO" # 系统iso镜像
$os_disk_size = 80 * 1024 * 1024 * 1024  # 系统盘大小
# 默认设置
$version = "9.0"  # hyper-v版本
$vm_folder = Join-Path -Path $root_folder -ChildPath $vm_name  # 虚拟机目录
$os_disk_path = Join-Path -Path $vm_folder -ChildPath "Virtual Hard Disks\os.vhdx"  # 系统盘路径
$cpu_count = 4  # 分配的cpu核心数量
$memory = 4 * 1024 * 1024 * 1024  # 内存大小
$switch =  (Get-VMSwitch | Select-Object -First 1).Name  # 获取默认虚拟交换机
$secure_boot = "Off"  # 安全启动,值为Off或On
#$enable_tpm = $true  # 启动tpm,值为$true或$false
# 具体命令
New-VM -Name $vm_name -MemoryStartupBytes $memory -Generation 2 -Path $root_folder -NewVHDPath $os_disk_path -NewVHDSizeBytes $os_disk_size -SwitchName $switch -Version $version
Add-VMDvdDrive -VMName $vm_name -Path $os_iso
Set-VMProcessor -VMName $vm_name -Count $cpu_count
Set-VMFirmware -VMName $vm_name -EnableSecureBoot $secure_boot -BootOrder (Get-VMDvdDrive -VMName $vm_name)  # 设置光驱为第一启动项

windows11创建脚本

该脚本与前面模板脚本的主要不同是同时开启安全启动和TPM模块

具体如下面的create-win11.ps1文件所示

$ErrorActionPreference = "Stop"
$vm_name = "windows11"
$root_folder = "F:\hyper-v_vms"
$os_iso ="F:\share_data\software\os\zh-cn_windows_11_business_editions_version_24h2_x64_dvd_5f9e5858.iso" # 系统iso镜像
$os_disk_size = 80 * 1024 * 1024 * 1024  # 系统盘大小
# 默认设置
$version = "9.0"  # hyper-v版本
$vm_folder = Join-Path -Path $root_folder -ChildPath $vm_name  # 虚拟机目录
$os_disk_path = Join-Path -Path $vm_folder -ChildPath "Virtual Hard Disks\os.vhdx"  # 系统盘路径
$cpu_count = 4  # 分配的cpu核心数量
$memory = 4 * 1024 * 1024 * 1024  # 内存大小
$switch =  (Get-VMSwitch | Select-Object -First 1).Name  # 获取默认虚拟交换机
$secure_boot = "On"  # 安全启动,值为Off或On
# 具体命令
New-VM -Name $vm_name -MemoryStartupBytes $memory -Generation 2 -Path $root_folder -NewVHDPath $os_disk_path -NewVHDSizeBytes $os_disk_size -SwitchName $switch -Version $version
Set-VMKeyProtector -VMName $vm_name -NewLocalKeyProtector
Enable-VMTPM -VMName $vm_name
Add-VMDvdDrive -VMName $vm_name -Path $os_iso
Set-VMProcessor -VMName $vm_name -Count $cpu_count
Set-VMFirmware -VMName $vm_name -EnableSecureBoot $secure_boot -BootOrder (Get-VMDvdDrive -VMName $vm_name)  # 设置光驱为第一启动项

windows7创建脚本

该脚本与前面模板脚本的主要不同是改为创建第一代的虚拟机(Generation 1),并关闭安全启动

具体如下面的create-win7.ps1文件所示

$ErrorActionPreference = "Stop"
$vm_name = "windows7"
$root_folder = "F:\hyper-v_vms"
$os_iso ="F:\share_data\software\os\cn_windows_7_ultimate_with_sp1_x64_dvd_u_677408.iso" # 系统iso镜像
$os_disk_size = 100 * 1024 * 1024 * 1024  # 系统盘大小
# 默认设置
$version = "9.0"  # hyper-v版本
$vm_folder = Join-Path -Path $root_folder -ChildPath $vm_name  # 虚拟机目录
$os_disk_path = Join-Path -Path $vm_folder -ChildPath "Virtual Hard Disks\os.vhdx"  # 系统盘路径
$cpu_count = 4  # 分配的cpu核心数量
$memory = 4 * 1024 * 1024 * 1024  # 内存大小
$switch =  (Get-VMSwitch | Select-Object -First 1).Name  # 获取默认虚拟交换机
$secure_boot = "Off"  # 安全启动,值为Off或On
#$enable_tpm = $false  # 启动tpm,值为$true或$false
# 具体命令
New-VM -Name $vm_name -MemoryStartupBytes $memory -Generation 1 -Path $root_folder -NewVHDPath $os_disk_path -NewVHDSizeBytes $os_disk_size -SwitchName $switch -Version $version
Add-VMDvdDrive -VMName $vm_name -Path $os_iso
Set-VMProcessor -VMName $vm_name -Count $cpu_count
Set-VMBios $vm_name -StartupOrder @("CD","Floppy", "LegacyNetworkAdapter", "IDE")

ubuntu创建脚本

该脚本与前面模板脚本的主要不同也是关闭安全启动

具体如下面的create-ubuntu.ps1文件所示

$ErrorActionPreference = "Stop"
$vm_name = "ubuntu"
$root_folder = "F:\hyper-v_vms"
$os_iso ="F:\share_data\software\os\ubuntu-22.04-live-server-amd64.iso" # 系统iso镜像
$os_disk_size = 80 * 1024 * 1024 * 1024  # 系统盘大小
# 默认设置
$version = "9.0"  # hyper-v版本
$vm_folder = Join-Path -Path $root_folder -ChildPath $vm_name  # 虚拟机目录
$os_disk_path = Join-Path -Path $vm_folder -ChildPath "Virtual Hard Disks\os.vhdx"  # 系统盘路径
$cpu_count = 4  # 分配的cpu核心数量
$memory = 4 * 1024 * 1024 * 1024  # 内存大小
$switch =  (Get-VMSwitch | Select-Object -First 1).Name  # 获取默认虚拟交换机
$secure_boot = "Off"  # 安全启动,值为Off或On
#$enable_tpm = $true  # 启动tpm,值为$true或$false
# 具体命令
New-VM -Name $vm_name -MemoryStartupBytes $memory -Generation 2 -Path $root_folder -NewVHDPath $os_disk_path -NewVHDSizeBytes $os_disk_size -SwitchName $switch -Version $version
Add-VMDvdDrive -VMName $vm_name -Path $os_iso
Set-VMProcessor -VMName $vm_name -Count $cpu_count
Set-VMFirmware -VMName $vm_name -EnableSecureBoot $secure_boot -BootOrder (Get-VMDvdDrive -VMName $vm_name)  # 设置光驱为第一启动项

复制虚拟机脚本

复制虚拟机主要分别两个步骤:一是导出待复制的虚拟机,二是重新导入刚导出的虚拟机并重命名。

具体如下面的copy-vm.ps1文件所示

$source_vm_name = "immortalwrt"
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$clone_vm_name = "$source_vm_name-$timestamp"
$temp_export_folder = "F:\hyper-v_export"  # 导出虚拟机时用的临时目录
$dest_folder = "F:\VMs\$clone_vm_name"  # 克隆后的虚拟机时存放目录
If (Test-Path $dest_folder){
    Write-Warning "目标文件夹已存在: $dest_folder"
    Break
}
# 清空导出目录
$temp_vm_folder = "$temp_export_folder\$source_vm_name"
If (Test-Path $temp_vm_folder) { Remove-Item -Path $temp_vm_folder -Recurse -Force }
# 导出虚拟机
Export-VM $source_vm_name -Path $temp_export_folder
# 导入虚拟机(复制并创建新ID)
$clone_config_file = (Get-ChildItem "$temp_export_folder\$($source_vm_name)\Virtual Machines" -Filter *.vmcx -Recurse | Select -First 1).Fullname
Write-host $clone_config_file
$export_vm_folder = "$temp_export_folder\$source_vm_name"
$clone_vm_config = @{
    Path = $clone_config_file;
    SnapshotFilePath = $dest_folder;
    VhdDestinationPath = Join-Path $dest_folder "Virtual Hard Disks";
    VirtualMachinePath = $dest_folder;
}
Write $clone_vm_config.SnapshotFilePath
$result = Import-VM -Copy -GenerateNewID @clone_vm_config
# 改名
$result | Rename-VM -NewName $clone_vm_name
# 删除导出虚拟机的目录
#If (Test-Path $export_vm_folder) { Remove-Item -Path $export_vm_folder  -Recurse -Force }

如果上面的脚本在保存或执行时出现乱码,可将其保存为utf-8 bom格式试试,可参考我的这篇博文:powershell脚本文件输出中文乱码解决办法-CSDN博客

后记

视时间是否允许,我可能用WPF(C#语言)开发图型化的工具

参考

Import, Export and Clone Virtual Machines in Hyper-V | Windows OS Hub

Cloning Hyper-V VMs with PowerShell - Deployment Research

posted on 2025-10-15 11:31  ljbguanli  阅读(19)  评论(0)    收藏  举报