PowerShell Script to Create Hyper-V Virtual Machines from Templates

4 min read

Introduction

When creating a virtual machine on Hyper-V, configuring everything manually in the GUI is time-consuming and makes it easy to miss settings. This article introduces a PowerShell script that automatically creates a virtual machine from a template VHDX file. The script helps you build consistent VM environments.

Script

# ==============================
# 1. Variable settings
# ==============================
# VM name
$VMName               = "test-vm"
# Template VHDX path
$TemplateFilePath     = "D:\Hyper-V\ubuntu22.04-template\Virtual Hard Disks\ubuntu22.04-template.vhdx"
# Root folder where the VM is placed
$DestinationRootPath  = "D:\Hyper-V"
# Virtual switch name
$SwitchName           = "Bridge"
# Generation
$Generation           = 2
# Boot memory (e.g. 2GB)
$MemoryStartupBytes   = 8GB
# Number of CPU cores (number of virtual processors)
$CPUCount             = 12
# Disk size (GB)
$DiskSize             = 40GB

# ==============================
# 2. Execution
# ==============================
try {
    # --- 2-1. Pre-check ---
    # Check whether the VM already exists
    if (Get-VM -Name $VMName -ErrorAction SilentlyContinue) {
        throw "VM '$VMName' already exists"
    }

    # Check whether the template file exists
    if (-not (Test-Path $TemplateFilePath)) {
        throw "Template file not found: $TemplateFilePath"
    }

    # --- 2-2. Create new folder & copy template file ---
    $VMFolderPath = Join-Path $DestinationRootPath $VMName
    $VHDFolderPath = Join-Path $VMFolderPath "Virtual Hard Disks"
    
    Write-Host "■ Create a new folder: $VHDFolderPath"
    New-Item -ItemType Directory -Path $VHDFolderPath -Force | Out-Null

    # Destination VHDX path
    $NewVhdxPath = Join-Path $VHDFolderPath "$VMName.vhdx"
    
    Write-Host "■ Copy template file:"
    Write-Host " From: $TemplateFilePath"
    Write-Host " Destination: $NewVhdxPath"
    Copy-Item -Path $TemplateFilePath -Destination $NewVhdxPath -Force
    

    # --- 2-3. Create a virtual machine ---
    Write-Host "■ Create a new virtual machine: $VMName"
    $VM = New-VM `
        -Name $VMName `
        -Generation $Generation `
        -MemoryStartupBytes $MemoryStartupBytes `
        -VHDPath $NewVhdxPath `
        -SwitchName $SwitchName `
        -Path $DestinationRootPath `
        -ErrorAction Stop

    # --- 2-4. Detailed settings ---
    # Set the number of CPU cores
    Write-Host "■ Set the number of CPU cores to $CPUCount"
    $VM | Set-VMProcessor -Count $CPUCount

    # Disable Secure Boot (Gen2 only)
    if ($Generation -eq 2) {
        Write-Host "■ Disable Secure Boot (Generation 2)"
        $VM | Set-VMFirmware -EnableSecureBoot Off
    }

    # Enable MAC address spoofing
    Write-Host "■ Enable MAC address spoofing"
    $VM | Get-VMNetworkAdapter | Set-VMNetworkAdapter -MacAddressSpoofing On

    # Disable checkpoint
    Write-Host "■ Disable checkpoint"
    $VM | Set-VM -CheckpointType Disabled

    # Enable nested virtualization
    Write-Host "■ Enable nested virtualization"
    $VM | Set-VMProcessor -ExposeVirtualizationExtensions $true

    # Dynamic memory settings (optional: uncomment if needed)
    Write-Host "■ Disable dynamic memory"
    $VM | Set-VMMemory -DynamicMemoryEnabled $false

    Write-Host "`n■ Work completed: [$VMName] successfully created"
    Write-Host "Path: $VMFolderPath"

    # Expand disk
    Write-Host "■ Expand disk"
    Resize-VHD -Path $NewVhdxPath -SizeBytes ($DiskSize)
}
catch {
    Write-Host "`nAn error occurred:" -ForegroundColor Red
    Write-Host $_.Exception.Message -ForegroundColor Red
    exit 1
}

Script Explanation

The script consists of two main sections.

1. Variable settings

At the beginning of the script, define the following main configuration items as variables:

  • $VMName: Name of the virtual machine to create
  • $TemplateFilePath: Path to the VHDX file to use as the template
  • $DestinationRootPath: Root folder where the virtual machine will be placed
  • $SwitchName: Name of the virtual switch to use
  • $Generation: Virtual machine generation (Generation 1 or 2)
  • $MemoryStartupBytes: Startup memory
  • $CPUCount: Number of CPU cores to allocate
  • $DiskSize: Disk size

2. Execution

The execution section creates a virtual machine with the following steps:

  1. Pre-check

    • Confirm that a virtual machine with the same name does not already exist
    • Confirm that the template file exists
  2. File preparation

    • Create the folder structure for the virtual machine
    • Copy the template VHDX file to the new folder
  3. Create virtual machine

    • Basic settings (name, generation, memory, virtual switch, etc.)
    • Advanced settings
      • Set the number of CPU cores
      • Disable Secure Boot for Generation 2
      • Enable MAC address spoofing
      • Disable checkpoints
      • Enable nested virtualization
      • Disable dynamic memory
      • Expand the disk

How to use

  1. Save the script anywhere (e.g. Create-VM.ps1)

  2. Modify the variables at the beginning of the script to suit your environment:

    $VMName = "Virtual machine name you want to create"
    $TemplateFilePath = "Template VHDX file path"
    $DestinationRootPath = "Virtual machine location path"
    $SwitchName = "Virtual switch name to use"
  3. Start PowerShell with administrator privileges and run the script:

    powershell.exe -ExecutionPolicy Bypass .\Create-VM.ps1
  4. When the script finishes running, a virtual machine is created with the settings you specified.

Conclusion

By using this script, you can automate virtual machine creation and build consistent environments more efficiently. The script is also easy to customize, so you can add or adjust functionality as needed.

I hope this script helps make your virtual environment management more efficient.