Use Hyper-V and Powershell to provision new Virtual Machine

Hyper-V, a virtualization platform developed by Microsoft, has become increasingly popular among IT professionals due to its ability to create and manage virtual machines. However, provisioning new virtual machines can be a time-consuming process. Fortunately, PowerShell, a command-line shell and scripting language, can be used to automate this task. With PowerShell, IT professionals can quickly and easily provision new virtual machines in Hyper-V environments. In this article, we will explore how to use Hyper-V and PowerShell to provision new virtual machines and simplify the process of creating and managing virtual environments for testing purposes.

LAB network & IP Addressing

Many of us have internet access at home, and we usually rely on a router to set up the right configuration for all our devices to connect to the internet. Most of the time, we use a private IP Address Class C range for this purpose. For example, we might use 192.168.1.1 with a subnet mask of 255.255.255.0. However, I don’t like to “mix” my personal devices like my computer, tablet or TV with my testing environment. That’s why I prefer to use a different range within the Private Class C address space.

To begin with, we need to “open” the subnet mask, changing it from 255.255.255.0 (24 bit mask) to 255.255.254.0 (23 bit mask). This will allow us to have a separate Class C network exclusively for our lab environment.

Now that we have our 192.168.0.0/24 for our virtual machines, we can distribute them accordingly. The following table does explains

On our Class C network we have up to 254 available host (first is the network address and last one is the broadcast address, so none of them are used).
I wanted to “distribute” the host evenly through all these IPs, having them as Sub-network, and try to have same last IP octet (hard task).
And within these 4 subnets, define which of those hosts are Tier0, Tier1 or Tier2.
These list does considers 3 AD forest sitting on the same IP Class C (and remember this is diferent from the one where your SmatTV- PS5, and your computer is located).
Even after defining 98 host, we still have more than 50% available for future usage… but then bigger Hyper-V machines will be required!

Powershell data file

Once we have clarified the IP Address distribution, we have to store this information on a file. This file will be parsed to our PowerShell scripts, so it can extract the corresponding values. This file was originally used as a Module Manifest file, but its ability to host data makes it a good choice. A module manifest is a PowerShell data file (.psd1) containing a hash table. The keys-value pairs in the hash table describe the contents and attributes of the module, define the prerequisites, and control how the components are processed.

as PSD1 file is a Hashtable, we can nest hash tables inside of it. First, we have to define it as a hashtable

Then we can start with, at least, one nested hashtable. Here I’m adding 2 arrays which will contain the nested hashtables, one for defining computers, and the other one defining the roles that a computer can have.

And now we can start defining the nodes, each representing a computer… but we still have one “joker” node that will apply to all of those. This one is represented with asterisk as the NodeName

So the final table will be something like:

The file is located in my GithubRepository @ EguibarIT.AutoLabSetup/VM-provissioning/MainData.psd1 at main · vreguibar/EguibarIT.AutoLabSetup (github.com)

Setting up Master Images

Virtual Machines grant us the possibility to have a “master” image and use a “differential” disk that will store every single byte changed from the master. This is really helpful when fast deploying is required and it helps to save a lost of space. For example, a Windows 2022 Core image is about 14 GB on a fresh install; if we copy this disk to create 10 VMs, the used space will be around 140 GB. If instead of copying the disk, we just create a differential disk per VM, the overall size will be below 15 GB.

Doing this is very simple, and I will not explain in in detail of this post. The process is something like:

  • Create a new VM
  • Install Windows (any version you like)
  • Fully update and patch
  • Install any software you need
  • Make any configuration
  • Clean up image and delete temporary/unneeded files
  • Run Sysprep for OOBE (Out of Box Experience). Seal the image.
  • Mark the VHDX disk as “read Only”

We will do this for each OS we would like to automatically provision (Win 10, Win 11, Windows Server 2019, 2022, GUI and Core). All those masters will be located on a separated folder, just for simplicity. Those master files must be defined on the provisioning script.

This folder structure is able to host the “Master” folder, containing all the VHDX Sysprep images, and all the actual Hyper-V VM folders of deployed images.

New-LabVM script

Now we should have all needed for starting deploying new VMs using the script. The file is located in my GithubRepository @ EguibarIT.AutoLabSetup/VM-provissioning/New-LabVm.ps1 at main · vreguibar/EguibarIT.AutoLabSetup (github.com)

The script will build the corresponding paths to master images, depending on the OS selected. BTW, OS selection is validated on the parameter name “vmOsType” and as for now it contains ‘Win10’, ‘Win11’, ‘W2k19’, ‘W2k19-CORE’, ‘W2022’, ‘W2022-CORE’. This is a mandatory parameter.

The script will be getting the required information from the PSD1 file described above

The Master images and associated differential disks will be defined in the following code, among other specific VM parameters. The Switch statement will define the Master image to be used based on the VmOsType parameter.

One of the key points on this provisioning, is the ability to set ComputerName, Ip stack (IP, DNS, Default Gateway), domain join with target OU. All this is done by generating an unattend.xml file with the correct values

And identifying the target OU to be used when joining the computer to the domain

Before finalizing the VM setup and powering it on, ensure that Windows (this part residing on the newly generated differential disk of the VM) is mounted on the VHDX disk, transfer the previously mentioned Unattend.xml file, set Windows to utilize the file during the next boot, and then dismount the VHDX disk.

Here’s another way to easily provision VMs, incorporating them into my automated deployment setup. While there are various methods available for this task, feel free to explore and enhance them further. It’s all about embracing opportunities for more enjoyment!

Social network sharing