Save to My DOJO
Table of contents
For IT Pros who run Hyper-V servers, I’d like to think that efficiency is core principal. By nature I’d argue that virtualization is a technology centered on efficiency. I think this principal should extend to provisioning new virtual machines as well. If you are in a larger environment or enjoy a healthy budget, you may be using a product like System Center Virtual Machine Manager (SCVMM). One of this product’s key features is the ability to spin up a new virtual machine based on a hardware profile or template.
This is a terrific way of maintaining server standards and streamlines the required effort. But what if you run a smaller shop or don’t have access to something like SCVMM? As long as you are comfortable with a little PowerShell, it doesn’t take much to create your own template-based provisioning system.
There are a few ways that I can think of that you might build such a provisioning system and I hope to write about other approaches in the future. Today we’ll look at what I think is a simple approach that uses the Hyper-V 3.0 PowerShell cmdlets. Creating a new virtual machine with the New-VM cmdlet is actually pretty straightforward. Once the virtual machine is created you can customize it with Set-VM. The most time consuming part is typing all the parameter values for each cmdlet. This is where a template or profile approach comes into play. In my Hyper-V test lab, I may need to create what I define as small, medium or large virtual machines based on hard disk sizes and memory configurations. I can predefine them with variables.
Switch ($VMType) { "Small" { $MemoryStartup=512MB $VHDSize=10gb $ProcCount=1 $MemoryMinimum=512MB $MemoryMaximum=1GB } "Medium" { $MemoryStartup=512MB $VHDSize=20gb $ProcCount=2 $MemoryMinimum=512MB $MemoryMaximum=2GB } "Large" { $MemoryStartup=1GB $VHDSize=40gb $ProcCount=4 $MemoryMinimum=512MB $MemoryMaximum=4GB } } #end switch
With this all I need to do is pass these values to New-VM and Set-VM, which I can do via splatting.
#define a hash table of parameters for New-VM $newParam = @{ Name=$Name SwitchName=$Switch MemoryStartupBytes=$MemoryStartup Path=$Path NewVHDPath=$VHDPath NewVHDSizeBytes=$VHDSize ErrorAction="Stop" } #define a hash table of parameters for Set-VM $setParam = @{ ProcessorCount=$ProcCount DynamicMemory=$True MemoryMinimumBytes=$MemoryMinimum MemoryMaximumBytes=$MemoryMaximum ErrorAction="Stop" }
From here all I need to do is splat the parameter hash tables to the different cmdlets.
New-VM @newparam | Set-VM @setparam
[optin-monster-shortcode id=”lwzgfpb294pntqna”]
As you might imagine, this is the type of process that works best as a script. Here is my template provisioning script that includes some basic error handling.
#requires -version 3.0 <# .Synopsis Provision a new Hyper-V virtual machine based on a template .Description This script will create a new Hyper-V virtual machine based on a template or hardware profile. You can create a Small, Medium or Large virtual machine. All virtual machines will use the same virtual switch and the same paths for the virtual machine and VHDX file. All virtual machines will be created with dynamic VHDX files and dynamic memory. All virtual machines will mount the same Windows Server 2012 ISO file so that you can start the virtual machine and load an operating system. VM Types Small (default) MemoryStartup=512MB VHDSize=10GB ProcCount=1 MemoryMinimum=512MB MemoryMaximum=1GB Medium MemoryStartup=512MB VHDSize=20GB ProcCount=2 MemoryMinimum=512MB MemoryMaximum=2GB Large MemoryStartup=1GB VHDSize=40GB ProcCount=4 MemoryMinimum=512MB MemoryMaximum=4GB This script requires the Hyper-V 3.0 PowerShell module. .Example PS C:\Scripts\> .\New-VMFromTemplate WEB2012-01 -VMType Small -passthru Name State CPUUsage(%) MemoryAssigned(M) Uptime Status ---- ----- ----------- ----------------- ------ ------ WEB2012-01 Off 0 0 00:00:00 Operating normally .Link New-VM Set-VM #> [cmdletbinding(SupportsShouldProcess)] Param( [Parameter(Position=0,Mandatory,HelpMessage="Enter the name of your new virtual machine")] [ValidateNotNullOrEmpty()] [string]$Name, [ValidateSet("Small","Medium","Large")] [string]$VMType="Small", [switch]$Passthru ) Write-Verbose "Creating new $VMType virtual machine" #universal settings regardless of type #the ISO for installing Windows 2012 $ISO = "G:\iso\9200.16384.WIN8_RTM.120725-1247_X64FRE_SERVER_EVAL_EN-US-HRM_SSS_X64FREE_EN-US_DV5.ISO" #all VMs will be on the same network switch $Switch = "Work Network" #path for the virtual machine. All machines will use the same path. $Path="C:\VMs" #path for the new VHDX file. All machines will use the same path. $VHDPath= Join-Path "F:\VHD" "$($name)_C.vhdx" #define parameter values based on VM Type Switch ($VMType) { "Small" { $MemoryStartup=512MB $VHDSize=10GB $ProcCount=1 $MemoryMinimum=512MB $MemoryMaximum=1GB } "Medium" { $MemoryStartup=512MB $VHDSize=20GB $ProcCount=2 $MemoryMinimum=512MB $MemoryMaximum=2GB } "Large" { $MemoryStartup=1GB $VHDSize=40GB $ProcCount=4 $MemoryMinimum=512MB $MemoryMaximum=4GB } } #end switch #define a hash table of parameters for New-VM $newParam = @{ Name=$Name SwitchName=$Switch MemoryStartupBytes=$MemoryStartup Path=$Path NewVHDPath=$VHDPath NewVHDSizeBytes=$VHDSize ErrorAction="Stop" } #define a hash table of parameters for Set-VM $setParam = @{ ProcessorCount=$ProcCount DynamicMemory=$True MemoryMinimumBytes=$MemoryMinimum MemoryMaximumBytes=$MemoryMaximum ErrorAction="Stop" } if ($Passthru) { $setParam.Add("Passthru",$True) } Try { Write-Verbose "Creating new virtual machine" Write-Verbose ($newParam | out-string) $VM = New-VM @newparam } Catch { Write-Warning "Failed to create virtual machine $Name" Write-Warning $_.Exception.Message #bail out Return } if ($VM) { #mount the ISO file Try { Write-Verbose "Mounting DVD $iso" Set-VMDvdDrive -vmname $vm.name -Path $iso -ErrorAction Stop } Catch { Write-Warning "Failed to mount ISO for $Name" Write-Warning $_.Exception.Message #don't bail out but continue to try and configure virtual machine } Try { Write-Verbose "Configuring new virtual machine" Write-Verbose ($setParam | out-string) $VM | Set-VM @setparam } Catch { Write-Warning "Failed to configure virtual machine $Name" Write-Warning $_.Exception.Message #bail out Return } } #if $VM
This is a script, not a function, so you need to make sure your execution policy allows running scripts. But after that it is pretty easy to create a new virtual machine.
My script puts all the machines on the same network switch and uses the same folders for the virtual machine and VHDX files. It also mounts my Windows Server 2012 ISO file so that I can manually start the machine and load an operating system. With a one line command I can verify the new VM.
get-vm web2012-01 | select Name,Path,DynamicMemoryEnabled,MemoryM*,ProcessorCount,@{Name="HardDisk";Expression={$_.HardDrives.path}},@{Name="DVD";Expression={$_.DVDDrives.path}}
Of course, these are my settings and you can create your own. For example, all of my virtual machines only have a single NIC, but perhaps for a large system you want it to have 2. You’ll need to make that change. Or if enough readers are interested I’m happy to come up with a revised version at some point that might include that or other virtual machine settings that you prefer.
If you can use a tool like SCVMM, I recommend that approach. But PowerShell is a great equalizer and enabler so if SCVMM is out of your reach, you can develop your own template approach. I hope you’ll let me know what you think.
Not a DOJO Member yet?
Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!
6 thoughts on "Create a Virtual Machine from a Template"
Dear sir,
thank you so much for your post.
i am looking for a script to create a vm from a template or from a VDX HD.
any suggestions how to make one ?
Many of my posts on the site include PowerShell scripts and examples for creating Hyper-V virtual machines.
I am looking for a script to create a VM using an existing vm which is installed with an OS. I will copy the existing vhdx to template folder and want to install OS. can u help us with the script
Sorry, but I can’t provide that kind of support. If you need help with PowerShell scripting, I encourage you to use the forums at PowerShell.org.