Virtual machine automation in Windows with PowerShell and Hyper-V
January 19, 2023 | Previous part | Next part |
Introduction
Since we want to perform automation on Windows, we must acquaint ourselves with PowerShell.
We will speed up our VM creation with a re-usable helper script. This tutorial will be taking some configuration tips from Joe Neville’s
Automate Hyper-V VM Creation with Powershell
article.
Check PowerShell version
The version of PowerShell installed with Windows 10 and 11 is PowerShell 5.1 (also known as PowerShell Desktop), but Microsoft has released newer versions called PowerShell Core. The source code available on
GitHub.
It can also be installed using the Windows package managers such as WinGet, Scoop, or Chocolatey.
PowerShell Core is required for some frameworks, such as Hugo. It also supports different operating systems and architectures.
To check which version of PS you’re running, open PowerShell and run $PSVersionTable
.
Desktop example:
PS C:\> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.22621.963
PSEdition Desktop
Core example:
PS C:\> $PSVersionTable
Name Value
---- -----
PSVersion 7.3.3
PSEdition Core
For this tutorial, either version is fine.
Configure your environment
Before we write or run a script, we need to set up our environment. Follow these commands, tailoring them to your system as needed.
-
Create a space for this machine on disk.
mkdir D:\VM\alpine
-
Obtain a copy of the Linux ISO. Get a link for a distro you want and the architecture you’re on.
For example, a version of Alpine Linux is at the following location:
https://dl-cdn.alpinelinux.org/alpine/v3.17/releases/x86_64/alpine-standard-3.17.0-x86_64.iso
With PowerShell, you can run a
wget
command, and specify the output filefile.wget https://dl-cdn.alpinelinux.org/alpine/v3.17/releases/x86_64/alpine-standard-3.17.0-x86_64.iso -OutFile D:\VM\alpine\alpine.iso
This downloads the file and stores it in the directory you created in Step 1.
-
Before creating the VM, gather some information. I have included some sample answers.
- VM name:
alpine
- ISO file location:
D:\VM\alpine\alpine.iso
- Switch name:
- run
Get-VMSwitch
and use the external switch name. - Or better yet, this command can be embedded in the script and gives the name of the switch. We’ll save it in our script.
`Get-VMSwitch -SwitchType External | Select -expand "Name"`
- run
- Number of CPUs, storage size, RAM:
2
,8GB
,4GB
. - Path to virtual disk:
D:\VM\alpine\
- VM name:
-
With the information gathered in Step 3, fill in the following script and save it as
createVM.ps1
. Replace the contents of varilables as necessary.# This script is in two parts. First we declare the variables to be applied. $n = "alpine" $dir = "D:\VM\$n\" <# # Exclude these commands because they were covered in Steps 1 and 2. mkdir $dir cd $dir wget https://releases.ubuntu.com/22.04.1/ubuntu-22.04.1-live-server-amd64.iso -OutFile ubuntu.iso #> $vm = "$n" # name of VM, this just applies in Windows, it isn't applied to the OS guest itself. $image = "$dir$n.iso" $vmswitch = Get-VMSwitch -SwitchType External | Select -expand 'Name' # name of your local vswitch #$port = "port1" # port on the VM #$vlan = 199 # VLAN that VM traffic will be send in $cpu = 2 # Number of CPUs $ram = 4GB # RAM of VM. Note this is not a string, not in quotation marks $path_to_disk = "$dir$n-disk1.vhdx" # Where you want the VM's virtual disk to reside $disk_size = 20GB # VM storage, again, not a string # The following ensure that this script creates a fresh VM instance. Stop-VM $vm Remove-VM $vm -Force rm $path_to_disk # Create a new VM New-VM $vm # Set the CPU and start-up RAM Set-VM $vm -ProcessorCount $cpu -MemoryStartupBytes $ram # Create the new VHDX disk - the path and size. New-VHD -Path $path_to_disk -SizeBytes $disk_size # Add the new disk to the VM Add-VMHardDiskDrive -VMName $vm -Path $path_to_disk # Assign the OS ISO file to the VM Set-VMDvdDrive -VMName $vm -Path $image # Remove the default VM NIC named 'Network Adapter' Remove-VMNetworkAdapter -VMName $vm # Add a new NIC to the VM and set its name Add-VMNetworkAdapter -VMName $vm #-Name $port # Configure the NIC as access and assign VLAN #Set-VMNetworkAdapterVlan -VMName $vm -VMNetworkAdapterName $port -Access -AccessVlanId $vlan # Connect the NIC to the vswitch Connect-VMNetworkAdapter -VMName $vm -SwitchName $vmswitch # Fire it up 🔥 Start-VM $vm Get-VM $vm <# # These commands may be useful later for automation. #[string]$userName = 'root' #[string]$userPassword = 'alpine' #[securestring]$secStringPassword = ConvertTo-SecureString $userPassword -AsPlainText -Force #[pscredential]$credObject = New-Object System.Management.Automation.PSCredential ($userName, $secStringPassword) #(Get-VMGuest -VM (Get-VM -name alpine)).IPAddress #Get-VM alpine | Select -ExpandProperty Networkadapters | Select -VMName -IPAddresses #Get-VM | Select -ExpandProperty Networkadapters | Select VMName, IPAddresses #>
-
Run the PowerShell script:
.\createVM.ps1
-
After the install completes, you log in with the default username and password.
-
Obtain the IP address and log in from another machine on the network via SSH.
Troubleshoot: Script won’t run
If you are unable to run the script, check your execution policy:
Get-ExecutionPolicy -List
To run the script, you may need to change your execution policy:
Set-ExecutionPolicy -ExecutionPolicy unrestricted -Scope CurrentUser
After running it, you should return the setting to a safer one:
Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope CurrentUser
Troubleshoot: Host key verification failed
If you get a Host key verification failed
error, open the .ssh/known_hosts
file and delete the entry with the IP of the VM you want to connect to.