Enable Hyper-V on Windows 11 and Create Virtual Machines with PowerShell: Practical Tips for Developers

Virtualization tutorial - IT technology blog
Virtualization tutorial - IT technology blog

The Problem: Windows Dev Machine, but CI/CD Runs Linux

Almost every developer working on Windows has run into this scenario: the CI/CD pipeline runs Ubuntu, the production server is Debian, but the dev machine is Windows 11. The result? “Works on my machine” but the build fails on the server, or a bash script runs fine on your colleague’s Mac but throws an error on the very first line.

The go-to solution is usually WSL2 — and yes, WSL2 is much better than it used to be. But WSL2 isn’t a real VM. There’s no independent kernel, you can’t test the network stack, and you can’t simulate a multi-host environment. Not to mention some services that require a full systemd setup simply won’t install.

I run a homelab with Proxmox VE managing 12 VMs and containers — it’s my playground for testing everything before pushing to production. But I don’t always want to SSH into a homelab server just to quickly test a script. When you need a Linux environment right on your Windows machine without installing extra software, Hyper-V is already there — you just need to turn it on.

Why Hyper-V Instead of VirtualBox?

VirtualBox and VMware Workstation are both Type-2 hypervisors — they run on top of Windows like regular applications. Hyper-V is a Type-1 hypervisor (bare-metal), meaning your Windows 11 actually runs on top of Hyper-V, not the other way around.

A direct comparison on the same hardware:

  • Performance: Hyper-V VMs use CPU virtualization directly, bypassing the emulation layer. Ubuntu 24.04 boots in around 8–10 seconds compared to 20–25 seconds on VirtualBox.
  • PowerShell Integration: The full VM lifecycle — create, snapshot, clone, delete — can all be managed via cmdlets, making it ideal for automation scripts.
  • No conflicts: Running Hyper-V no longer requires disabling WSL2, Docker Desktop, or Android Emulator (Windows 11 fixed this as of build 22H2).

One caveat: Hyper-V is only available on Windows 11 Pro, Enterprise, and Education. If you’re on Windows 11 Home, you’ll need to upgrade your license or fall back to VirtualBox.

Checking and Enabling Hyper-V

Check CPU Virtualization Support

Run PowerShell as Administrator:

# Check if the CPU supports virtualization
Get-ComputerInfo -Property HyperV*

# Or use systeminfo for a quick overview
systeminfo | findstr /C:"Hyper-V"

If you see HyperVisorPresent: False and your CPU supports virtualization, go into BIOS/UEFI and enable Intel VT-x (Intel) or AMD-V/SVM (AMD). The menu name varies by motherboard but is usually under the Advanced → CPU Configuration tab.

Enable Hyper-V via PowerShell

# Enable Hyper-V and its companion tools (requires Admin rights and a reboot)
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All -All

# After rebooting, verify the installation
Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V | Select-Object State

Once the machine restarts, Hyper-V Manager will appear in the Start Menu and the Hyper-V cmdlets will be available in PowerShell immediately.

Creating a Linux Virtual Machine with PowerShell

Setup: Create a Virtual Switch

Before creating a VM, you need a virtual switch for network connectivity. There are two common types:

  • External: The VM gets its own IP on your home LAN and is reachable from other devices. Use this when you need to test your app from a phone or another machine.
  • Internal: The VM can only communicate with the Windows host and isn’t exposed to the outside network. Safer for dev environments.
# List available physical network adapters
Get-NetAdapter | Where-Object {$_.Status -eq "Up"}

# Create an External Switch (replace "Wi-Fi" with your actual adapter name)
New-VMSwitch -Name "ExternalSwitch" -NetAdapterName "Wi-Fi" -AllowManagementOS $true

# Or create an Internal Switch (no physical adapter needed)
New-VMSwitch -Name "InternalSwitch" -SwitchType Internal

Create an Ubuntu 24.04 VM

Download the Ubuntu Server ISO, then run the following commands in order:

# Define variables for cleaner code
$VMName    = "ubuntu-dev"
$VMPath    = "D:\Hyper-V\VMs"
$ISOPath   = "D:\ISOs\ubuntu-24.04-live-server-amd64.iso"
$VHDSize   = 40GB

# Create a Generation 2 VM (UEFI, for modern Linux)
New-VM `
  -Name $VMName `
  -Path $VMPath `
  -Generation 2 `
  -MemoryStartupBytes 2GB `
  -SwitchName "ExternalSwitch"

# Create a virtual hard disk (dynamic VHDX)
New-VHD -Path "$VMPath\$VMName\$VMName.vhdx" -SizeBytes $VHDSize -Dynamic
Add-VMHardDiskDrive -VMName $VMName -Path "$VMPath\$VMName\$VMName.vhdx"

# Attach the ISO
Add-VMDvdDrive -VMName $VMName -Path $ISOPath

# Set DVD as the first boot device
$DVDDrive = Get-VMDvdDrive -VMName $VMName
Set-VMFirmware -VMName $VMName -FirstBootDevice $DVDDrive

# Disable Secure Boot (required for Linux without a shim)
Set-VMFirmware -VMName $VMName -EnableSecureBoot Off

# Enable Dynamic Memory (saves RAM when the VM is idle)
Set-VMMemory -VMName $VMName -DynamicMemoryEnabled $true -MinimumBytes 512MB -MaximumBytes 4GB

# Assign 2 CPU cores
Set-VMProcessor -VMName $VMName -Count 2

# Start the VM
Start-VM -Name $VMName

# Open the console for installation
VMConnect localhost $VMName

Important Tip: Enable Integration Services

A commonly skipped but critical step: inside the freshly installed Ubuntu VM, run the commands below to enable Hyper-V Integration Services. Without them, copy-paste won’t work, the VM clock will drift, and the host won’t be able to perform a graceful shutdown:

# On the Ubuntu guest
sudo apt update && sudo apt install -y linux-image-virtual linux-tools-virtual linux-cloud-tools-virtual
sudo systemctl enable hv_kvp_daemon hv_vss_daemon
sudo reboot

Day-to-Day VM Management with PowerShell

This is the part I use most — instead of clicking through Hyper-V Manager, write a script once and use it forever:

# View the status of all VMs
Get-VM | Select-Object Name, State, CPUUsage, MemoryAssigned, Uptime

# Start / Stop / Suspend
Start-VM -Name "ubuntu-dev"
Stop-VM -Name "ubuntu-dev" -Force          # Hard power off
Stop-VM -Name "ubuntu-dev" -TurnOff:$false  # Clean shutdown (requires integration services)
Suspend-VM -Name "ubuntu-dev"               # Hibernate the VM

# Snapshots (checkpoints)
Checkpoint-VM -Name "ubuntu-dev" -SnapshotName "before-upgrade-$(Get-Date -Format 'yyyyMMdd')"
Get-VMSnapshot -VMName "ubuntu-dev"
Restore-VMSnapshot -VMName "ubuntu-dev" -Name "before-upgrade-20260616"

# Delete old snapshots (free up disk space)
Remove-VMSnapshot -VMName "ubuntu-dev" -Name "before-upgrade-20260616"

# Clone a VM via export/import
Export-VM -Name "ubuntu-dev" -Path "D:\Hyper-V\Exports"
Import-VM -Path "D:\Hyper-V\Exports\ubuntu-dev\Virtual Machines\*.vmcx" -Copy -GenerateNewId

The Best Approach: Combining Hyper-V with Automation Scripts

Creating a VM manually like that takes 15–20 minutes every time — mostly clicking through wizards. I wrapped everything into a New-DevVM.ps1 script that gets the whole process down to about 2 minutes:

# New-DevVM.ps1 — Quickly spin up an Ubuntu dev environment VM
param(
  [string]$Name = "ubuntu-$(Get-Date -Format 'MMdd')",
  [int]$CPUCount = 2,
  [long]$RAMBytes = 2GB,
  [long]$DiskBytes = 40GB,
  [string]$ISOPath = "D:\ISOs\ubuntu-24.04-live-server-amd64.iso",
  [string]$VMBasePath = "D:\Hyper-V\VMs",
  [string]$SwitchName = "InternalSwitch"
)

$VHDPath = "$VMBasePath\$Name\$Name.vhdx"

New-VM -Name $Name -Path $VMBasePath -Generation 2 -MemoryStartupBytes $RAMBytes -SwitchName $SwitchName
New-VHD -Path $VHDPath -SizeBytes $DiskBytes -Dynamic
Add-VMHardDiskDrive -VMName $Name -Path $VHDPath
Add-VMDvdDrive -VMName $Name -Path $ISOPath
Set-VMFirmware -VMName $Name -FirstBootDevice (Get-VMDvdDrive -VMName $Name) -EnableSecureBoot Off
Set-VMProcessor -VMName $Name -Count $CPUCount
Set-VMMemory -VMName $Name -DynamicMemoryEnabled $true -MinimumBytes 512MB -MaximumBytes ($RAMBytes * 2)

Write-Host "[OK] VM '$Name' created. Starting..."
Start-VM -Name $Name
VMConnect localhost $Name

Call it like this:

# Create a VM with an auto-generated name
.\New-DevVM.ps1

# Create a custom VM
.\New-DevVM.ps1 -Name "test-nginx" -CPUCount 4 -RAMBytes 4GB

Connect via SSH Instead of the Console

The Hyper-V Manager console is pretty clunky — there’s input lag and you can’t scroll through command history. Enable SSH inside the VM and connect from Windows Terminal instead:

# On the Ubuntu guest — enable SSH
sudo apt install -y openssh-server
sudo systemctl enable --now ssh

# Get the VM's IP address
ip -4 addr show eth0
# On the Windows host — get the VM's IP via PowerShell
(Get-VMNetworkAdapter -VMName "ubuntu-dev").IPAddresses

# SSH into the VM
ssh [email protected]

Common Errors and How to Fix Them

  • “Hyper-V cannot be installed: A hypervisor is already running”: This is usually caused by Docker Desktop using the WSL2 backend. Try restarting your machine or check Task Manager to see if any vmwp.exe processes are running.
  • VM won’t boot from ISO after creation: With Generation 2 and Linux, remember to disable Secure Boot (Set-VMFirmware -EnableSecureBoot Off) or select the appropriate CA certificate.
  • VM loses network after suspend: An old Hyper-V bug that still pops up occasionally. Fix it by restarting the network adapter inside the VM (sudo ip link set eth0 down && sudo ip link set eth0 up) or by loading the hv_netvsc driver.
  • VHDX bloats after many snapshots: Run Optimize-VHD -Path path\to.vhdx -Mode Full periodically to compact the file.

Share: