Contents

Building a home lab, the PowerShell way

I haven’t posted here in a while, but for a good reason: I started a new job! As of May 1th, I started working as a Senior IT Consultant at Hands On.

Partly because of the job change, I wanted to build a home lab for some testing an practicing for certification exams.

Introduction

My lab will run an Intel NUC, the sixth generation, with 32GB of RAM and a 500GB M.2 SSD drive. This box currently runs Windows 10 Pro, mainly because that means I can also use it as workstation while working at home. Perhaps in the future I’ll switch over to running a server OS, with a workstation as a VM; Still thinking about what the best option is.

Anyway, the box runs Hyper-V and because using it as a lab means I’ll frequently be installing new servers or reinstalling existing ones, I wanted a workflow to speed up this process. And of course I will use PowerShell to do so πŸ™‚ I’ll share my setup and scripts in this post, but please note that this is (as always) work in progress and is by no means a perfect solution. However, because I received some requests to share my work, I decided to put them online already πŸ™‚

Networking setup

First, a small look at the networking setup for Hyper-V. I wanted to isolate my guests from my main network. And because the NUC is such a nice, portable little box, I want to have the ability to take it with me and use it somewhere else, without the need to change my entire network configuration. To realize this, I decided to go with a NAT-switch in Hyper-V. This way, the guests can use there entire own subnet and still have internet-access through the host machine. For more information on this, check this out.

Disk setup

To save up on disk space needed for the servers, I wanted to use differencing disks. This way, there is one ‘main’ disk, with each VM having it’s own differencing disk with just the changes / delta’s to the main disk. So, I installed a plain Windows Server 2012 R2, installed all available updates and ran sysprep so I can use this as a base image. After this, i copied the VHDX for this machine to seperate folder and marked it as read-only. Once it is used as a base disk for all other servers, changing this disk directly would break all underlying VM’s, so the read-only part is just for security.

Scripting it together

After this, the ground work for the lab is done. Now i’ll need to build a PowerShell script to do the actual deployment. I’ll break down the script piece by piece, to show what work is being done by the script.

Variables setup

1
2
3
4
5
#region define variables
# User defined variables
$VMName = 'LAB-EXH01'
$VMIP = '172.29.92.26/24'
$DNSIP = '172.29.92.20'

This first part is where I’ll define the variables that I change whenever I run the script. I set the desired name for the VM, the IP-address I want it to use and the IP-address for the DNS server. In the future, I’ll most likely change this script into a function so I can just supply them as paramaters. For now, I’ll just manually change the script each time I run it. Like I said: work in progress πŸ˜‰

1
2
3
4
5
6
# Script Variables
$diskpath = "D:\VHD\$VMName.vhdx"
$ParentDisk = 'D:\VHD\BASE\Server2012R2Base.vhdx'
$VMSwitch = 'CertLab'
$SourceXML = 'D:\DATA\Scripts\Lab VMs\unattend.xml'
#endregion

These are static variables that contain stuff as file paths. These won’t change each time the script is run, but I think setting them here is nicer that just hardcoding them in the script. The CertLab VM-Switch is the NAT-switch I created earlier.

Creating the differencing disk

1
2
3
4
#region create diff disk
# Create new differencing disk
New-VHD -ParentPath $ParentDisk -Path $diskpath -Differencing
#endregion

The real work starts off with creating the VHD-file for the new server. The disk is created as a differencing disk, with the base image I created earlier as the parent disk.

Copy the answer file

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#region copy adjusted answer file
# mount VHD
$VHD = (Mount-VHD -Path $diskpath -Passthru |
Get-Disk |
Get-Partition |
Where-Object -FilterScript {
$_.Type -eq 'Basic' 
}).DriveLetter
# add XML Content
[xml]$Unattend = Get-Content $SourceXML
$Unattend.unattend.settings[1].component[2].ComputerName = $VMName
$Unattend.unattend.settings[1].component[3].Interfaces.Interface.UnicastIpAddresses.IpAddress.'#text' = $VMIP
$Unattend.unattend.settings[1].component[4].Interfaces.Interface.DNSServerSearchOrder.IpAddress.'#Text' = $DNSIP
$Unattend.Save("${VHD}:\\Unattend.xml")
# dismount VHD
Dismount-VHD $diskpath
#endregion

This part of the script mounts the newly created VHD-file for the new-VM, and then copies an unattend.xml to this disk. I use some scripting to add content to the XML-file. This way I change the hostname, IP-address and DNS server address for the new server, based on the variables I defined in the beginning of the script.

Creating and starting the VM

1
2
3
4
#region create new vm
# Create VM with new VHD
New-VM -Name $VMName -MemoryStartupBytes 2048MB -SwitchName $VMSwitch -VHDPath $diskpath -Generation 2 -BootDevice VHD
#endregion

Here, I just create the new VM. I set the MemoryStartupBytes paramater here hardcoded in the script, but ofcourse you can always choose to specify this as a variable (or a parameter if you create a function) to be able to easily change this.

1
2
3
4
#region start new vm
# Start VM
Start-VM $VMName
#endregion

Finaly, I simply start the new VM.

Wrap-up

That’s it! By using this script, I’m able to set up a new VM in my lab with just a few clicks. Like I said, it’s work in progress. I’d like to implement PowerShell DirectΒ to do some final configuration on the guest machine, such as adding certain roles. At this time, however, PowerShell direct requires the guest to run a Server 2016 TP OS, and as I’m also using this lab for certification and training purposes, I’m sticking with Server 2012 R2 for now. I could set up PowerShell Remoting (Robert has a great blogpost on this), but that’s something for the future πŸ˜‰

If you have any comments on my code, or if you would like to add something to the script, please feel free to do so!