Create a Virtual Machine from a Template

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.

 

Altaro Hyper-V Backup
Share this post

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"

  • Julien says:

    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 ?

Leave a comment or ask a question

Your email address will not be published. Required fields are marked *

Your email address will not be published. Required fields are marked *

Notify me of follow-up replies via email

Yes, I would like to receive new blog posts by email

What is the color of grass?

Please note: If you’re not already a member on the Dojo Forums you will create a new account and receive an activation email.