Creating Hyper-V VM’s with Desired State Configuration

I'm looking to automate the build of my test environment that runs as Hyper-V virtual machines on my Windows 8.1 Laptop computer. To get started, I thought I would take a look at the xHyper-V DSC resource to create the actual VM's. There's also no reason this shouldn't work on a Windows Server that's running the Hyper-V role.

The Hyper-V role has already been added to my Windows 8.1 computer. I also have a previously created virtual hard drive (vhdx) file that has been loaded with the Windows Server 2012 R2 operating system and all of the available Windows updates. That OS has been syspreped, an unattend.xml file has been added to it to set the local administrator password when a new VM is created using a differencing disk based on this parent vhdx, and the vhdx has been marked as read only.

I've downloaded the DSC Resource Kit Wave 9 which contains the most recent versions of all of the Microsoft created DSC resources to include the xHyper-V DSC resource. What's the x stand for? Experimental.

The xHyper-V resource has been extracted from the downloaded DSC Resource Kit Wave 9 zip file and added to the C:\Program Files\WindowsPowerShell\Modules folder on my Windows 8.1 computer that I want to create the VM's on.

I've created a configuration as shown in the following example:

 1Configuration MrHyperV_VM {
 2
 3    param (
 4        [Parameter(Mandatory)]
 5        [string]$VMName,
 6
 7        [Parameter(Mandatory)]
 8        [string]$baseVhdPath,
 9
10        [Parameter(Mandatory)]
11        [string]$ParentPath,
12
13        [Parameter(Mandatory)]
14        [string]$VMSwitchName
15    )
16
17    Import-DscResource -module xHyper-V
18
19    xVMSwitch switch {
20        Name = $VMSwitchName
21        Ensure = 'Present'
22        Type = 'Internal'
23    }
24
25    xVHD DiffVHD {
26        Ensure = 'Present'
27        Name = $VMName
28        Path = $baseVhdPath
29        ParentPath = $ParentPath
30        Generation = 'vhdx'
31    }
32
33    xVMHyperV CreateVM {
34        Name = $VMName
35        SwitchName = $VMSwitchName
36        VhdPath = Join-Path -Path $baseVhdPath -ChildPath "$VMName.vhdx"
37        ProcessorCount = 1
38        MaximumMemory = 2GB
39        MinimumMemory = 512MB
40        RestartIfNeeded = 'True'
41        DependsOn = '[xVHD]DiffVHD', '[xVMSwitch]switch'
42        State = 'Running'
43        Generation = 'vhdx'
44    }
45}

I've run this configuration so it's loaded in memory in my current PowerShell session:

1Get-Command -CommandType Configuration

dsc-xhyperv1b.jpg

I'll now call the configuration along with the necessary parameters and values which creates the MOF file:

1MrHyperV_VM -VMName Test01 -baseVhdPath 'D:\Hyper-V\Virtual Hard Disks' -ParentPath 'D:\Hyper-V\Virtual Hard Disks\Template\Server2012R2Core-Template_011915.vhdx' -VMSwitchName 'Internal Virtual Switch'

dsc-xhyperv2b.jpg

The MOF file is applied to my local computer using the Start-DscConfiguration cmdlet:

1Start-DscConfiguration -Wait -Path .\MrHyperV_VM -Verbose

dsc-xhyperv3b.jpg

A new virtual machine named Test01 has been created as specified in the configuration:

1Get-VM -Name Test01

dsc-xhyperv4b.jpg

Piping a few cmdlets together, allows you to see the virtual hard drive information for the newly created VM to include its location, type (differencing), and its parent:

1Get-VM -Name Test01 | Get-VMHardDiskDrive | Get-VHD

dsc-xhyperv5b.jpg

As shown here, the IP address of the VM can easily be obtained from the Hyper-V host:

1Get-VM -Name Test01 | Get-VMNetworkAdapter

dsc-xhyperv6b.jpg

Now to add the IPv4 address to the trusted host list on my pc so I can run commands on the VM via PowerShell remoting. This is necessary because of Kerberos mutual authentication not being available due to the new VM being in a workgroup by default. For security reasons, the IP should be removed from the trusted host list once the new VM is added to the domain. You should NEVER add "*" to the trusted host list <period>.

1Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value "$((Get-VM -Name Test01 | Get-VMNetworkAdapter).ipaddresses -match '\d{1,3}(\.\d{1,3}){3}')" -Concatenate -Force

dsc-xhyperv7b.jpg

You can see that it has indeed been added:

1Get-Item -Path WSMan:\localhost\Client\TrustedHosts

dsc-xhyperv8b.jpg

Now to test running a command on the VM from my pc with PowerShell remoting:

1Invoke-Command -ComputerName 192.168.29.108 {
2  $PSVersionTable.PSVersion
3} -Credential (Get-Credential)

dsc-xhyperv9b.jpg

One thing to note is that PowerShell remoting is enabled by default on Windows Server 2012 and higher which is why no changes had to be made on the VM to accomplish this.

At this point, I should be able to create a DSC configuration to add the VM to the domain and make all of the configuration changes I want to it. I wrote about that process in a previous blog article on Use a certificate with PowerShell DSC to add a server to Active Directory without hard coding a password.

If Desired State Configuration is something that you're interested in, you should definitely take a look at the video from the January Mississippi PowerShell User Group meeting.

µ