Mastering Hyper-V 2016 Book Resources




Chapter 1 – Introduction to Virtualization and Microsoft Solutions



History of Hyper-V

Chapter 2 – Virtual Machine Resource Fundamentals



Get the worker process ID for a VM (getvmwpforvm.ps1)

(Get-WmiObject -q "SELECT * FROM Msvm_ComputerSystem WHERE ElementName = 'vmname'" -n rootvirtualizationv2).ProcessID

Enable Processor Compatibility (EnableProcessorCompatibility.ps1)

Set-VMProcessor -CompatibilityForMigrationEnabled $true

Enable Legacy Processor (EnableLegacyProcessor.ps1)

Set-VMProcessor -CompatibilityForOlderOperatingSystemsEnabled $true

View VMCX properties with PowerShell (ViewVMCXProp.ps1)

$tempVM = (Compare-VM -Copy -Path .yourvmcxfile.vmcx -GenerateNewID).VM

A number of PowerShell commands for VHDX management (VHDCommands.ps1)

#Create fixed VHDX file

New-VHD -Path D:Virtualsnewfix.vhdx -Fixed -SizeBytes 10GB

#To create a dynamic VHDX fi le, use this command:

New-VHD -Path D:Virtualsnewdyn.vhdx -Dynamic -SizeBytes 1TB

#The command to create a differencing VHDX fi le is as follows:

New-VHD -ParentPath D:Virtualsnewfix.vhdx `

-Path D:Virtualsnewdif.vhdx -Differencing `

-SizeBytes 1000000000

#Here is the command to create a VHDX using very large block sizes:

New-VHD –Path D:VirtualsLargeBlockSize.vhdx –BlockSizeBytes 128MB `

–LogicalSectorSize 4KB –SizeBytes 1TB

#A virtual hard disk can be added to a virtual machine using the Add-VMHardDiskDrive

#PowerShell cmdlet, as in this example:

Add-VMHardDiskDrive -VMName Demo1 -Path D:Virtualsnewdyn.vhdx `

-ControllerType SCSI


Generation 1 vs Generation 2 VMs

Virtual Processor Configuration

Dynamic Memory

Creating a virtual disk

Chapter 3 – Virtual Networking



Create virtual switch (CreateVirtSwitch.ps1)

#Create new external (implicit external as adapter passed)

New-VMSwitch -Name "External Switch" -Notes "External Connectivity" `

-NetAdapterName "VM NIC" -AllowManagementOS $false

#Create new internal (visible on host) and private (vm only)

New-VMSwitch -Name "Internal Switch" -SwitchType Internal

New-VMSwitch -Name "Private Switch" -SwitchType Private

Set vmNIC VLAN (setvmnicvlan.ps1)

Set-VMNetworkAdapterVlan –VMName test1 –Access –VlanId 173

Set vmNIC PVLAN (setpvlan.ps1)

#To set a VM in isolated mode, use this command:

Set-VMNetworkAdapterVlan –VMName testvm –Isolated –PrimaryVlanId 100 `

–SecondaryVlanId 200

#Use this command to set a VM in community mode (note that the secondary VLAN ID sets the

#community the VM is part of):

Set-VMNetworkAdapterVlan –VMName testvm2 –Community –PrimaryVlanId 100 `

–SecondaryVlanId 201

#Use this command to set a VM in promiscuous mode (note that the secondary VLAN is now

#a list of all VLAN IDs used in community and for the isolated):

Set-VMNetworkAdapterVlan –VMName testvm3 –Promiscuous –PrimaryVlanId 100 `

–SecondaryVlanIdList 200-400

#To check the confi guration of a virtual machine, use the Get-VMNetworkAdapterVlan cmdlet,

#as in this example:

Get-VMNetworkAdapterVlan –VMName testvm | fl *

Create PVLAN with SCVMM (scvmmpvlanCreate.ps1)

$logicalNetwork = New-SCLogicalNetwork -Name "Production - PVLAN Isolated Mode" `

-LogicalNetworkDefinitionIsolation $true -EnableNetworkVirtualization $false `

-UseGRE $false -IsPVLAN $true

$allHostGroups = @()

$allHostGroups += Get-SCVMHostGroup -ID ""

$allSubnetVlan = @()

$allSubnetVlan += New-SCSubnetVLan -Subnet "" -VLanID 120 `

-SecondaryVLanID 200

$allSubnetVlan += New-SCSubnetVLan -Subnet "" -VLanID 110 `

-SecondaryVLanID 200

New-SCLogicalNetworkDefinition -Name "Lab Cloud - Production - PVLAN Isolated" `

-LogicalNetwork $logicalNetwork -VMHostGroup $allHostGroups `

-SubnetVLan $allSubnetVlan -RunAsynchronously

Create logical networks with SCVMM (scvmmlognetCreate.ps1)

$logicalNetwork = New-SCLogicalNetwork -Name "Corp" `

-LogicalNetworkDefinitionIsolation $false -EnableNetworkVirtualization $false `

-UseGRE $false -IsPVLAN $false -Description "Corporate, connected network"

$allHostGroups = @()

$allHostGroups += Get-SCVMHostGroup -ID "0e3ba228-a059-46be-aa41-2f5cf0f4b96e"

$allSubnetVlan = @()

$allSubnetVlan += New-SCSubnetVLan -VLanID 10

New-SCLogicalNetworkDefinition -Name "Corp Trunk" `

-LogicalNetwork $logicalNetwork `

-VMHostGroup $allHostGroups -SubnetVLan $allSubnetVlan -RunAsynchronously

Bulk create VLANs in SCVMM (BulkVLANCreate.ps1)

Import-Module virtualmachinemanager

Get-VMMServer -ComputerName scvmm

#Replace this with actual ID of the Logical Network. Get-SCLogicalNetwork | ft name, id

$logicalNetwork = Get-SCLogicalNetwork -ID "1064012f-fc6a-49c4-98be-ba44914b5b8f"

$startNumber = 150

$endNumber = 190

$vlanID = $startNumber



    $allHostGroups = @()

    $allHostGroups += Get-SCVMHostGroup -ID "0e3ba228-a059-46be-aa41-2f5cf0f4b96e"

    $allSubnetVlan = @()

    $allSubnetVlan += New-SCSubnetVLan -Subnet "10.7.$vlanID.0/24" -VLanID $vlanID

    $logicalNetworkDefinition = New-SCLogicalNetworkDefinition -Name "VLAN_$vlanID" -LogicalNetwork $logicalNetwork -VMHostGroup $allHostGroups -SubnetVLan $allSubnetVlan -RunAsynchronously

    # Gateways

    $allGateways = @()

    $allGateways += New-SCDefaultGateway -IPAddress "10.7.$vlanID.1" -Automatic

    # DNS servers 

    $allDnsServer = @("10.7.$vlanID.10", "10.7.$vlanID.11")

    # DNS suffixes

    $allDnsSuffixes = @()

    # WINS servers

    $allWinsServers = @()

    $NewVLANName = "VLAN_" + $vlanID + "_IP_Pool"

    New-SCStaticIPAddressPool -Name $NewVLANName -LogicalNetworkDefinition $logicalNetworkDefinition -Subnet "10.7.$vlanID.0/24" -IPAddressRangeStart "10.7.$vlanID.10" -IPAddressRangeEnd "10.7.$vlanID.11" -DefaultGateway $allGateways -DNSServer $allDnsServer -DNSSuffix "" -DNSSearchSuffix $allDnsSuffixes -RunAsynchronously

    #Now create VM Network for each

    $vmNetwork = New-SCVMNetwork -Name "Customer_VLAN_$vlanID" -LogicalNetwork $logicalNetwork -IsolationType "VLANNetwork" -Description "VM Network for Customer VLAN $vlanID"

    Write-Output $vmNetwork

    $logicalNetworkDefinition = Get-SCLogicalNetworkDefinition -Name "VLAN_$vlanID"

    $subnetVLAN = New-SCSubnetVLan -Subnet "10.7.$vlanID.0/24" -VLanID $vlanID

    $VMSubnetName = "Customer_VLAN_" + $vlanID + "_0"

    $vmSubnet = New-SCVMSubnet -Name $VMSubnetName -LogicalNetworkDefinition $logicalNetworkDefinition -SubnetVLan $subnetVLAN -VMNetwork $vmNetwork

    #Increment the VLAN number

    $vlanID += 1


until ($vlanID -gt $endNumber)

Useful Network Virtualization SCVMM (NetworkVirtualizationCommands.ps1)


#Show the virtual network address space

Get-NetVirtualizationLookupRecord | Sort-Object VMName | Format-Table CustomerAddress,VirtualSubnetID,ProviderAddress,VMName -AutoSize

#View virtual network routing


#Find MAC of next hop

Select-NetVirtualizationNextHop -SourceCustomerAddress `

-DestinationCustomerAddress -SourceVirtualSubnetID 6864375

#Test virtual network communication

Test-VMNetworkAdapter -Sender -SenderIPAddress `

-ReceiverIPAddress -VMName "Blue-VM-1" `

-NextHopMacAddress "00508c125f46" -SequenceNumber 100

#Create a lookup record


$vsid = 6864375

$DHCPClientMAC = "020203030404"

New-NetVirtualizationLookupRecord -CustomerAddress `

-VirtualSubnetID $vsid -MACAddress $DHCPClientMAC `

-ProviderAddress $ProviderAddressHost -Type L2Only `

-Rule TranslationMethodEncap

Get VMQ information (getvmqinfo.ps1)

Get-NetAdapterVmq |ft Name, InterfaceDescription,Enabled,NumberOfReceiveQueues -AutoSize

Create NIC team (createnicteam.ps1)

New-NetLbfoTeam -Name "HostSwitchTeam" -TeamMembers NICTeam3,NICTeam4 -TeamingMode SwitchIndependent -LoadBalancingAlgorithm Dynamic -Confirm:$false

Create Mgmt OS vNICs with QOS (MgmtVNicLBFO.ps1)

New-NetLbfoTeam -Name "HostSwitchTeam" -TeamMembers NICTeam3,NICTeam4 `

-TeamingMode Static -Confirm:$false

New-VMSwitch "MgmtSwitch" -MinimumBandwidthMode weight `

-NetAdapterName "HostSwitchTeam" –AllowManagement $false

Add-VMNetworkAdapter -ManagementOS -Name "LiveMigration" -SwitchName "MgmtSwitch"

Set-VMNetworkAdapter -ManagementOS -Name "LiveMigration" `

-MinimumBandwidthWeight 50

Add-VMNetworkAdapter -ManagementOS -Name "Cluster" -SwitchName "MgmtSwitch"

Set-VMNetworkAdapter -ManagementOS -Name "Cluster" -MinimumBandwidthWeight 50


SDNv2 Overview and Deployment with SCVMM

Networking and IPv4 Overview

NIC Teaming and Virtual Switch on Server

3-1 Network Configuration with SCVMM

3-2 Network Virtualization using SCVMM

3-3 HNV Gateway with SCVMM

Monitor Hyper-V Traffic

Chapter 4 – Storage Configuration



Various cmdlets for VHD[x] management (VariousVHDCmds.ps1)

#PowerShell provides an easy way to mount and unmount a VHDX fi le:

Mount-VHD -Path D:Virtualsnewdyn.vhdx

Dismount-VHD -Path D:Virtualsnewdyn.vhdx

#Create VHDs (source option just allows data from one VHD to be copied into the new)

New-VHD -Path D:Virtualsnewfix.vhdx -Fixed -SizeBytes 1000000000

New-VHD -Path D:Virtualsnewdyn.vhdx -Dynamic -SizeBytes 10GB

New-VHD -ParentPath D:Virtualsnewfix.vhdx -Path D:Virtualsnewdif.vhdx -Differencing -SizeBytes 1000000000

#Convert a VHD to VHDX

Convert-VHD -Path d:tempsource.vhd -DestinationPath d:tempdestination.vhdx

#Resize to minimum possible size

Resize-VHD .win81nondomain.vhdx -ToMinimumSize

#Mount a VHD on native OS

Mount-VHD -Path D:Virtualsnewdyn.vhdx

#Now visible in Disk Manager, can init, create volumes etc

Dismount-VHD -Path D:Virtualsnewdyn.vhdx

Storage Space management (StorageSpaces.ps1)

#Create a storage Space            


#List all disks that can be pooled and output in table format (format-table)            

Get-PhysicalDisk -CanPool $True | ft FriendlyName,OperationalStatus,Size,MediaType            


#Store all physical disks that can be pooled into a variable, $pd            

$pd = (Get-PhysicalDisk -CanPool $True | Where MediaType -NE UnSpecified)            

#Create a new Storage Pool using the disks in variable $pd with a name of My Storage Pool            

New-StoragePool -PhysicalDisks $pd –StorageSubSystemFriendlyName “Storage Spaces*” -FriendlyName “My Storage Pool”            

#View the disks in the Storage Pool just created            

Get-StoragePool -FriendlyName "My Storage Pool" | Get-PhysicalDisk | Select FriendlyName, MediaType            


#Create two tiers in the Storage Pool created. One for SSD disks and one for HDD disks            

$ssd_Tier = New-StorageTier -StoragePoolFriendlyName "My Storage Pool" -FriendlyName SSD_Tier -MediaType SSD            

$hdd_Tier = New-StorageTier -StoragePoolFriendlyName "My Storage Pool" -FriendlyName HDD_Tier -MediaType HDD                        


#New-VirtualDisk –SNtoragePoolFriendlyName “My Storage Pool” –ResiliencySettingName Simple –Size 10TB –Provisioningtype Thin –FriendlyName “Documents”             

#Create a new virtual disk in the pool with a name of TieredSpace using the SSD (50GB) and HDD (300GB) tiers            

$vd1 = New-VirtualDisk -StoragePoolFriendlyName "My Storage Pool" -FriendlyName TieredSpace -StorageTiers @($ssd_tier, $hdd_tier) -StorageTierSizes @(50GB, 300GB) -ResiliencySettingName Mirror -WriteCacheSize 1GB   #cannot also specify -size if using tiers and also cannot use provisioning type, e.g. Thin            


#Online, initialize and create volume            

Get-Disk | Where-Object BusType -Eq Spaces | Where-Object PartitionStyle –Eq "RAW"| Initialize-Disk -PartitionStyle GPT            

Get-Disk | Where-Object IsOffline –Eq $True | Set-Disk –IsOffline $False            

Get-Disk | Where-Object BusType -Eq Spaces | New-Partition -UseMaximumSize -DriveLetter M | Format-Volume -FileSystem NTFS -NewFileSystemLabel "Mirror" -Confirm:$False            

New-Item M:Important -ItemType directory            

Copy-Item C:TestTest.jpg M:Important            


#Pin an item to SSD tier            

Set-FileStorageTier –FilePath M:Importanttest.jpg -DesiredStorageTier ($vd1 | Get-StorageTier –MediaType SSD)            

#Force an optimization to move the data to SSD tier just pinned            

Optimize-Volume –DriveLetter M –TierOptimize #forces the move of pinned files now. Normally this happens in the background on schedule 1am by default            


#View the automated optimization task            

Get-ScheduledTask | Where-Object TaskPath -EQ "MicrosoftWindowsStorage Tiers Management" | fl

Create SMB Share for Hyper-V (SMBShare.ps1)

MD G:VMStore

New-SmbShare -Name VMStore -Path G:VMStore `

-FullAccess domainadministrator, `

domainHV01$, domainHV02$, domainHVCLUS$

#If 2012 R2

Set-SmbPathAcl -ShareName VMStore

#If 2012 and this needs to be done in command prompt (replaces Set-SmbPathAcl)

ICACLS G:VMStore /Inheritance:R

ICACLS G:VMStore /Grant "domainadministrator:(CI)(OI)F"

ICACLS G:VMStore /Grant domainHV01$:(CI)(OI)F

ICACLS G:VMStore /Grant domainHV02$:(CI)(OI)F

ICACLS G:VMStore /Grant domainHVCLUS$:(CI)(OI)F

Use Shared VHDX (ShardVHDX.ps1)

New-VHD -Path C:ClusterStorageVolume1SharedVHDXSavdalfcshared1.vhdx `

-Fixed -SizeBytes 25GB

Add-VMHardDiskDrive -VMName savdalfc01 -Path `

C:ClusterStorageVolume1SharedVHDXSavdalfcshared1.vhdx -ShareVirtualDisk

Add-VMHardDiskDrive -VMName savdalfc02 -Path `

C:ClusterStorageVolume1SharedVHDXSavdalfcshared1.vhdx -ShareVirtualDisk

#To check if a virtual disk is using a shared VHDX, the SupportPersistentReservations

#property can be examined. If it is set to True, then it is a shared VHDX.

Get-VMHardDiskDrive -VMName savdalfc01 | ft vmname, path, `

controllertype, SupportPersistentReservations -auto


4-1 Dynamic VHDX Resize

4-2 Guest Cluster Storage Options

Storage Space Overview

Clustered Storage Spaces

Storage Spaces Direct Demo

Chapter 5 – Managing Hyper-V



GUI to Server Core (GUI2core.ps1)

Uninstall-WindowsFeature Server-Gui-Mgmt-Infra –Restart

Server Core to GUI (core2GUI.ps1)

Install-WindowsFeature Server-Gui-Mgmt-Infra,Server-Gui-Shell –Restart

Enable Hyper-V Role (InstallHyperVRole.ps1)

Install-WindowsFeature -Name Hyper-V -Restart

Basic VM Management (VMMgmt.ps1)

#List all Hyper-V Nouns

Get-Command -Module Hyper-V | Select -Unique Noun | Sort Noun

#List all cmdlets for a certain Noun, in this example VM

Get-Command -Module Hyper-V -Noun VM

#The first cmdlet gets all virtual machines, the second part identifi es the VMs in the

#Off state, and then only those VMs are passed to the fi nal cmdlet, which exports them.

Get-VM | where-object {$_.State -EQ "Off"} | Export-VM -Path D:Backups

#The following code just looks for XML files (which is the format

#for virtual machine confi gurations) and then imports:

Get-ChildItem e:virtuals*.xml -recurse | Import-VM

#In another case, I wanted to configure all virtual machines that were set to automatically

#start to not start if they were running when the Hyper-V server shut down. That’s easy with

Get-VM | Where-Object {$_.AutomaticStartAction -eq "StartIfRunning"} |`

Set-VM -AutomaticStartAction Nothing -AutomaticStopAction ShutDown

VM Group Creation (vmgroups.ps1)

#Create new VM Collection Groups

New-VMGroup -Name VMCGroup1 -GroupType VMCollectionType

New-VMGroup -Name VMCGroup2 -GroupType VMCollectionType

New-VMGroup -Name VMCGroup3 -GroupType VMCollectionType

#Add VMs to the VM Collection Groups

Add-VMGroupMember -VMGroup (Get-VMGroup VMCGroup1) -VM (Get-VM VM1)

Add-VMGroupMember -VMGroup (Get-VMGroup VMCGroup2) -VM (Get-VM VM2)

Add-VMGroupMember -VMGroup (Get-VMGroup VMCGroup2) -VM (Get-VM VM3)

Add-VMGroupMember -VMGroup (Get-VMGroup VMCGroup3) -VM (Get-VM VM4)

#View the membership of the groups

Get-VM | ft Name, Groups -AutoSize

Get-VMGroup -Name VMCGroup2

#Perform actions on the group as if it were a VM

#Enable-VMReplication -VM (Get-VMGroup VMCGroup2).VMMembers ......

Start-VM -VM (Get-VMGroup VMCGroup2).VMMembers

#Create VM Management Group with VMCGroup2 and VMCGroup3 in it

New-VMGroup -Name MgmtGroup1 -GroupType ManagementCollectionType

Add-VMGroupMember -VMGroup (Get-VMGroup MgmtGroup1) `

-VMGroupMember (Get-VMGroup VMCGroup2)

Add-VMGroupMember -VMGroup (Get-VMGroup MgmtGroup1) `

-VMGroupMember (Get-VMGroup VMCGroup3)

#Create VM Management Group with VMCGroup1 and MgmtGroup1 to show nesting

New-VMGroup -Name MgmtGroup2 -GroupType ManagementCollectionType

Add-VMGroupMember -VMGroup (Get-VMGroup MgmtGroup2) `

-VMGroupMember (Get-VMGroup VMCGroup1)

Add-VMGroupMember -VMGroup (Get-VMGroup MgmtGroup2) `

-VMGroupMember (Get-VMGroup MgmtGroup1)

Get-VMGroup MgmtGroup2 | Select-Object -ExpandProperty VMGroupMembers

VM mode Sysprep (syspreppc.bat)

Sysprep.exe /generalize /oobe /shutdown /mode:VM

Module for patch injection (Install-Patch.psm1)

function Install-Patch


    <#     .SYNOPSIS         Patches a WIM or VHD file     .DESCRIPTION         Applies downloaded patches to a VHD or WIM file     .NOTES         File Name: Install-Patch.psm1         Author: John Savill         Requires: Tests on PowerShell 3 on Windows Server 2012         Copyright (c) 2013 John Savill     .LINK     .PARAMETER updateTargetPassed         File (WIM, VHD or VHDX) to be patched     .PARAMETER patchpath         Path containing the updates     .EXAMPLE         Install-Patch d:filestest.vhd d:updateswin2012         Install-Patch d:filesinstall.wim:4 d:updateswin2012     #>





    #$updateTargetPassed = "G:TempWin2012DatacenterRTM.vhdx"


    #$updateTargetPassed = "d:sourcesinstall.wim:4"

    #$patchpath = "D:softwareWindows 2012 Updates"

    if(($updateTargetPassed.ToLower().Contains(".vhd")) -eq $true) # if its VHD or VHDX. Contains is case sensitive so have to convert to lower when comparing 


        $isVHD = $true




        $isVHD = $false





        if ((Test-Path $updateTarget) -eq $false) #if not found


            write-output "Source not found ($updateTarget)"





            mount-vhd -path $updateTarget

            $disks = Get-CimInstance -ClassName Win32_DiskDrive | where Caption -eq "Microsoft Virtual Disk"            

            foreach ($disk in $disks)


                $vols = Get-CimAssociatedInstance -CimInstance $disk -ResultClassName Win32_DiskPartition             

                foreach ($vol in $vols)


                    $updatedrive = Get-CimAssociatedInstance -CimInstance $vol -ResultClassName Win32_LogicalDisk |            

                    where VolumeName -ne 'System Reserved'          



            $updatepath = $updatedrive.DeviceID + ""



    if(!$isVHD)  #its a WIM file


        #Need to extract the WIM part and the index

        #extract file name and the index number

        $updateTargetPassedSplit = $updateTargetPassed.Split(":")

        if($updateTargetPassedSplit.Count -eq 3) #one for drive letter, one for folder and one for image number so would have been two colons in it c:tempinstall.wim:4


            $updateTarget = $updateTargetPassedSplit[0] + ":" + $updateTargetPassedSplit[1]   #There are two colons. The first is drive letter then the folder!

            $updateTargetIndex = $updateTargetPassedSplit[2]

            $updatepath = "c:wimmount"

            #check if exists and if not create it

            if ((Test-Path $updatepath) -eq $false) #if not found


                Write-Host "Creating folder " + $updatepath

                New-Item -Path $updatepath -ItemType directory

                #could have also used []::CreateDirectory($updatepath)


            # Mount it as folder

            #dism /get-wiminfo /wimfile:install.wim

            dism /Mount-Wim /wimfile:$updateTarget /index:$updateTargetIndex /mountdir:$updatepath 




            write-output "Missing index number for WIM file. Example: c:tempinstall.wim:4"




    # For WIM or VHD

    $updates = get-childitem -path $patchpath -Recurse | where {($_.extension -eq ".msu") -or ($_.extension -eq ".cab")} | select fullname

    foreach($update in $updates)


        write-debug $update.fullname

        $command = "dism /image:" + $updatepath + " /add-package /packagepath:'" + $update.fullname + "'"

        write-debug $command

        Invoke-Expression $command


    $command = "dism /image:" + $updatepath + " /Cleanup-Image /spsuperseded"

    Invoke-Expression $command



        dismount-vhd -path $updateTarget -confirm:$false




        dism /Unmount-Wim /mountdir:$updatepath /commit 

        #dism /Unmount-Wim /mountdir:$updatepath /discard



Check Integration Service version of VMs (getisvmver.bat)

Get-VM | ft Name, IntegrationServicesVersion

Read guest FQDN from host (readguestfqdn.ps1)

$vmName = "savdaldc02"

$vm = Get-WmiObject -Namespace rootvirtualizationv2 `

-Class Msvm_ComputerSystem `

-Filter "ElementName='$vmName'"

$vm.GetRelated("Msvm_KvpExchangeComponent").GuestIntrinsicExchangeItems | `

% {$GuestExchangeItemXml = ([XML]$_).SelectSingleNode(`


if ($GuestExchangeItemXml -ne $null)


    $GuestExchangeItemXml.SelectSingleNode( `





NANO Server Overview and Creation

Windows Server 2016 Top Ten Features

Inject patches to VHD or WIM

Using checkpoints for image management

Shielded VM Overview

Chapter 6 – Maintaining a Hyper-V Environment



Create a checkpoint (CreateCheckpoint.ps1)

Checkpoint-VM -Name "TestVM10" -SnapshotName "Before change"

Apply a checkpoint (ApplyCheckpoint.ps1)

Get-VM -Name "TestVM10" | Get-VMSnapshot | Restore-VMSnapshot

Resource metering examples (resourcemetering.ps1)

#To enable resource metering for a virtual machine, use this command:

Enable-VMResourceMetering -VMName 

#To view the current measurements for a virtual machine in a detailed list format

Measure-VM -VMName  | fl

#The metrics for a virtual machine never resets unless you either disable metering or perform

#a manual reset. Use this command to perform a manual reset:

Reset-VMResourceMetering -VMName 

#Finally, to disable the metering, use this command:

Disable-VMResourceMetering -VMName 

#To check which virtual machines have metering enabled, run the following command:

Get-VM | Format-Table Name, ResourceMeteringEnable

#Get detailed metrics

$report = Measure-VM -VMName savdalfs01



Creating a resource pool (CreateResourcePool.ps1)

New-VMResourcePool -Name GroupA -ResourcePoolType Processor

New-VMResourcePool -Name GroupA -ResourcePoolType Memory

New-VMResourcePool -Name GroupA -ResourcePoolType Ethernet

New-VMResourcePool -Name GroupA -ResourcePoolType VHD `

-Paths @("\savdalfs01HVShare")

Add-VMSwitch -ResourcePoolName GroupA -Name "External Switch"

Set-VMProcessor -VMName savdal08R2 -ResourcePoolName GroupA

Set-VMMemory -VMName savdal08R2 - ResourcePoolName Group A

Add-VMHardDiskDrive -VMName savdal08R2 -ControllerType SCSI `

-ResourcePoolName GroupA `

-Path "\savdalfs01HVSharesavdal08R2data1.vhdx"

Add-VMNetworkAdapter -VMName savdal08R2 -ResourcePoolName GroupA

#Enable metering of a pool

Enable-VMResourceMetering -ResourcePoolName GroupA


6-1 Hyper-V Performance Monitor View

VM Monitoring

Cluster Aware Updating

Chapter 7 – Failover Clustering and Migration Technologies



View node dynamic weight (ViewDynamicWeight.ps1)

Get-ClusterNode | ft Name, DynamicWeight -AutoSize

Add a VM service monitor (AddVMServMonitor.ps1)

Add-ClusterVMMonitoredItem -VirtualMachine savdaltst01 -Service spooler

View Cluster Network Details (ViewClusterNetwork.ps1)

Get-ClusterNetwork | ft Name, Role, AutoMetric, Metric -AutoSize

Test Cluster commands (TestCluster.ps1)

Test-Cluster -Cluster  -Disk "<disk, for example Cluster Disk 5>" -Include Storage

Specify Live Migration Network (LiveMigNetwork.ps1)

Get-ClusterResourceType -Name "Virtual Machine" | Set-ClusterParameter -Name MigrationExcludeNetworks -Value ([String]::Join(";",(Get-ClusterNetwork | Where-Object {$_.Name -ne "Migration Network"}).ID))

Custom VM Move (MoveVMCustom.ps1)

Move-VMStorage -VMName  -SmartPagingFilePath d `

-SnapshotFilePath  -VirtualMachinePath  `

-Vhds @(@{ "SourceFilePath " = "C:vmvhd1.vhdx "; `

"DestinationFilePath " = "D:VHDsvhd1.vhdx "},`

@{ "SourceFilePath " = "C:vmvhd2.vhdx ";`

"DestinationFilePath " = "E:VHDsvhd2..vhdx "}, `

@{ "SourceFilePath " = "C:vmvhd3.vhdx ";`

"DestinationFilePath " = "F:VHDsvhd3.vhdx "})

#Check state of migrations

Get-WmiObject -Namespace rootvirtualizationv2 -Class Msvm_MigrationJob| `

ft Name, JobStatus, PercentComplete, VirtualSystemName

View IP Listener for migration (ViewIPListener.ps1)

gwmi -n rootvirtualizationv2 Msvm_VirtualSystemMigrationService | select MigrationServiceListenerIPAddressList

Perform parallel Live Migrations (ParallelLM.ps1)

Workflow Invoke-ParallelLiveMigrate


    $VMLIST = get-vm blank1,blank2,blank3

    ForEach -Parallel ($VM in $VMLIST)


        Move-VM -Name $VM.Name -DestinationHost savdalhv02





Setting up Shared Nothing Live Migration

Failover Clustering in Windows Server 2016

Cluster Dynamic Quorum

Chapter 8 – Hyper-V Replica and Cloud Orchestration



Enable Server for Hyper-V Replica (EnableHyperVReplicaOnServer.ps1)

Set-VMReplicationServer -ReplicationEnabled 1 -ComputerName savdalhv24

View Hyper-V Replica Properties (ViewHyperVReplicaproperties.ps1)

get-vmreplicationserver -computername savdalhv24 | fl

Add Hyper-V Replica Auth Entry (AddReplicaEntry.ps1)

New-VMReplicationAuthorizationEntry -AllowedPrimaryServer  -ReplicaStorageLocation  -TrustGroup

Inject IP into VM (InjectVMIP.ps1)

$vmName = "win81g2" 

 #Retrieve the Hyper-V Management Service, ComputerSystem class for the VM and the VM’s SettingData class. 

$Msvm_VirtualSystemManagementService = Get-WmiObject -Namespace rootvirtualizationv2 `

      -Class Msvm_VirtualSystemManagementService 

$Msvm_ComputerSystem = Get-WmiObject -Namespace rootvirtualizationv2 `

      -Class Msvm_ComputerSystem -Filter "ElementName='$vmName'" 

$Msvm_VirtualSystemSettingData = ($Msvm_ComputerSystem.GetRelated("Msvm_VirtualSystemSettingData", `

     "Msvm_SettingsDefineState", `

      $null, `

      $null, ` 

     "SettingData", `

     "ManagedElement", `

      $false, $null) | % {$_})

$Msvm_SyntheticEthernetPortSettingData = $Msvm_VirtualSystemSettingData.GetRelated("Msvm_SyntheticEthernetPortSettingData")

$Msvm_GuestNetworkAdapterConfiguration = ($Msvm_SyntheticEthernetPortSettingData.GetRelated(

    "Msvm_GuestNetworkAdapterConfiguration", "Msvm_SettingDataComponent", `

    $null, $null, "PartComponent", "GroupComponent", $false, $null) | % {$_})

$Msvm_GuestNetworkAdapterConfiguration.DHCPEnabled = $false

$Msvm_GuestNetworkAdapterConfiguration.IPAddresses = @("")

$Msvm_GuestNetworkAdapterConfiguration.Subnets = @("")

$Msvm_GuestNetworkAdapterConfiguration.DefaultGateways = @("")

$Msvm_GuestNetworkAdapterConfiguration.DNSServers = @("", "")

$Msvm_VirtualSystemManagementService.SetGuestNetworkAdapterConfiguration( `

    $Msvm_ComputerSystem.Path, $Msvm_GuestNetworkAdapterConfiguration.GetText(1))

View health of VM replication (MeasureVMReplication.ps1)

Measure-VMReplication -ComputerName savdalhv21 -VMName savdalapp01 | fl

Hyper-V Replica Failover commands (ReplicaFailover.ps1)


#List all snapshots and perform a testfailover

$VMSnapshots = Get-VMSnapshot -VMName  -SnapshotType Replica

Start-VMFailover -Confirm:$false -VMRecoverySnapshot $VMSnapshots[0] -AsTest


#A planned failover is a bit more involved and involves running commands against the primary

#VM to prepare it for failover and then activating on the replica VM. On the primary VM,

#the following commands are run:


Start-VMFailover -VMName  –prepare

#Next, on the replica VM, the following commands are run to actually perform the failover,

#reverse the replication, and then start the replica VM.

Start-VMFailover -VMName 

Set-VMReplication -reverse -VMName 



$VMSnapshots = Get-VMSnapshot -VMName  -SnapshotType Replica

Start-VMFailover -Confirm:$false -VMRecoverySnapshot $VMSnapshots[0]

#At this point, you would check that the virtual machine is in the desired state and then complete

#the failover using this command:

Complete-VMFailover -VMName  -Confirm:$false


Setting up Hyper-V Replica

Chapter 9 – Implementing the Private Cloud, SCVMM and Microsoft Azure Stack



Create SCVMM Private Cloud (SCVMMPrivCloudCreate.ps1)

Set-SCCloudCapacity -JobGroup "XXXXXX" -UseCustomQuotaCountMaximum $true `

-UseMemoryMBMaximum $false -UseCPUCountMaximum $false -UseStorageGBMaximum $false `

-UseVMCountMaximum $true -MemoryMB 36864 -CPUCount 40 -StorageGB 1024

$resources = @()

$resources += Get-SCLogicalNetwork -Name "Hyper-V Network Virtualization PA" -ID `


$resources += Get-SCLogicalNetwork -Name "Lab" -ID " XXXXXX "

$resources += Get-SCStorageClassification -Name "Gold" -ID " XXXXXX "

$addCapabilityProfiles = @()

$addCapabilityProfiles += Get-SCCapabilityProfile -Name "Hyper-V"

Set-SCCloud -JobGroup " XXXXXX" -RunAsynchronously -AddCloudResource $resources `

-AddCapabilityProfile $addCapabilityProfiles

$hostGroups = @()

$hostGroups += Get-SCVMHostGroup -ID " XXXXXX "

New-SCCloud -JobGroup " XXXXXX " -VMHostGroup $hostGroups -Name "Test Cloud" `

-Description "" -RunAsynchronously -DisasterRecoverySupported $false


VM Creation through Service Catalog

Chapter 10 – Containers and Docker




Overview of containers

Demo of containers

Chapter 11 – Remote Desktop Services



VDI Deployment using RDS

RDP on iOS and Android

Simple RDS App Publishing

RemoteFX Example

Chapter 12 – Azure IaaS and Storage



Fetch Azure RDP file (AzureRDPFile.ps1)

$mySvc = "MasteringHyper-V2012R2-CS"

$myVM = "Test42"

Get-AzureRemoteDesktopFile -ServiceName $mySvc -Name $myVM -Launch

Commands for VM creation and management (AzureVMCreate.ps1)

Import-Module "C:Program Files (x86)Microsoft SDKsWindows AzurePowerShellAzureAzure.psd1"


Import-AzurePublishSettingsFile 'C:Usersadministrator.SAVILLTECHDownloadsWindows Azure MSDN - Visual Studio Ultimate-9-30-2013-credentials.publishsettings'



Set-AzureSubscription -SubscriptionName "Windows Azure MSDN - Visual Studio Ultimate" -CurrentStorageAccount "savtechstorage"

Get-AzureVMImage | ft Label,ImageName,LogicalSizeInGB


$images = Get-AzureVMImage

$locations = Get-AzureLocation

$mySvc = "SavillTechTest"

$myPwd = "P@ssw0rd"

New-AzureQuickVM -Windows -name "Sav2012VM" -ImageName $images[25].ImageName -ServiceName $mySvc -Location $locations[7].Name  -AdminUserName AdminJohn -Password $myPwd

#Another Example

$images = Get-AzureVMImage

$mySvc = "MasteringHyper-V2012R2-CS"

$myAG = "MasteringHyper-V2012R2-EastUS"

$myPwd = "P@ssw0rd"

New-AzureQuickVM -Windows -name "Test43" -ImageName $images[46].ImageName -ServiceName $mySvc -AffinityGroup $myAG –AdminUserName AdminJohn -Password $myPwd

#Adding disks

$mySvc = "MasteringHyper-V2012R2-CS"

$myVM = "Test43"

Get-AzureVM -Name $myVM -ServiceName $mySvc |

    Add-AzureDataDisk -CreateNew -DiskSizeInGB 1023 -DiskLabel 'datadisk1' -LUN 0 |

    Add-AzureDataDisk -CreateNew -DiskSizeInGB 1023 -DiskLabel 'datadisk2' -LUN 1 |


#Moving a VHD into Azure and attaching to a VM

$sourceVHD = "D:SoftwareVHDswin2k3.vhd"

$destinationVHD = ""

Add-AzureVhd -LocalFilePath $sourceVHD -Destination $destinationVHD `

             -NumberOfUploaderThreads 5

Add-AzureDisk -DiskName 'win2k3' -MediaLocation $destinationVHD `

               -Label 'win2k3' -OS "Windows"

#Add a disk to Azure VM

$mySvc = "MasteringHyper-V2012R2-CS"

$myVM = "Test42"

Get-AzureVM -Name $myVM -ServiceName $mySvc |

    Add-AzureDataDisk -Import -DiskName vhdtst -LUN 2 |


# Get VM Details for all VMs in a specific cloud

Get-AzureVM -ServiceName $mySvc

# Restart a VM

Restart-AzureVM -ServiceName $mySvc -Name $myVM

# Shutdown a VM 

Stop-AzureVM -ServiceName $mySvc -Name $myVM

# Start a VM

Start-AzureVM -ServiceName $mySvc -Name $myVM

Fetch configuration of virtual network (GetNetConfig.ps1)

Get-AzureVNetConfig | select -ExpandProperty xmlconfiguration

Initiate VPN connect (ConnectVPN.ps1)

Connect-VpnS2SInterface -Name

Configure VM with static IP in Azure fabric (SetAzureStaticIP.ps1)

Test-AzureStaticVNetIP -VNetName SavillTechVN -IPAddress

Test-AzureStaticVNetIP -VNetName SavillTechVN -IPAddress

$staticVM = Get-AzureVM -ServiceName SavillTechCS -Name staticiptest 

Set-AzureStaticVNetIP -VM $staticVM -IPAddress | Update-AzureVM

Get-AzureStaticVNetIP -VM $staticVM


Create Minecraft Server in Azure

Custom VM Creation with PowerShell

Azure IaaS Overview

Snapshots and Azure IaaS

Using PowerShell with Azure

Fault Domains and Availability Sets

Network Security Groups

Azure Site Recovery

%d bloggers like this: