For large Hyper-V infrastructure, IT people use often Virtual Machine Manager (VMM) to automate tasks as VM deployment. VMM provides profiles (hardware, operating system and application) and then we use these profiles to build a VM Template. Most of the time, a VM Template contains a VM hardware configuration and the OS configuration (join the domain, product key and so on). Then VMs are deployed from templates which decrease the time to deploy a working VM.
The convenient about VMM is its price. VMM is expensive and it is often medium/large business which implement VMM. So for other companies which can’t buy VMM, are they forced to do without VM deployment automation? Of course no. Other tools can help us to make automation without VMM and it is called PowerShell.
Since Windows Server 2012, a lot of Hyper-V PowerShell commands (in Hyper-V module) have been added. Now easily we can create, configure and manage VM from PowerShell.
For large Hyper-V infrastructure, IT people use often Virtual Machine Manager (VMM) to automate tasks as VM deployment. VMM provides profiles (hardware, operating system and application) and then we use these profiles to build a VM Template. Most of the time, a VM Template contains a VM hardware configuration and the OS configuration (join the domain, product key and so on). Then VMs are deployed from templates which decrease the time to deploy a working VM.
The convenient about VMM is its price. VMM is expensive and it is often medium/large business which implement VMM. So for other companies which can’t buy VMM, are they forced to do without VM deployment automation? Of course no. Other tools can help us to make automation without VMM and it is called PowerShell.
Since Windows Server 2012, a lot of Hyper-V PowerShell commands (in Hyper-V module) have been added. Now easily we can create, configure and manage VM from PowerShell.
In this topic we will see how to create and set a Virtual Machine from PowerShell. The scripts presented are examples. They can be changed, modified and improved regarding your needs. They are here for explanation.
To follow this topic, I assume that you have knowledge about Hyper-V and PowerShell.
Create a VM
To create a Virtual Machine from PowerShell, you can run the New-VM PowerShell cmdlet as below:
1 2 3 4 5 6 7 |
New-VM -Name <VMName> -Path <VMPath> -NewVHDPath <VHD Path> -NewVHDSizeBytes <VHD(X) size> -Generation <VM Gen (1 or 2)> -MemoryStartupBytes <Startup Memory> -SwitchName <VM Switch Name> |
- Name: Name of the Virtual Machine
- Path: Path where will be stored VM files
- NewVHDPath: Create a VHD(X) file to the specified path (Dynamic disk)
- New-VHDSizeBytes: Size of the VHD(X) file
- Generation: VM generation (1 or 2)
- MemoryStartupBytes: Memory assigned to the VM (static Memory)
- SwitchName: switch name where the network adapter will be connected
Below you can find an example of VM creation with the above command:
If you don’t want to attach now a VHD(x) with your VM because you have a syspreped VHDX, you can run the below command:
1 2 3 4 5 6 |
New-VM -Name <VMName> -Path <VMPath> -NoVHD -Generation <VM Gen (1 or 2)> -MemoryStartupBytes <Startup Memory> -SwitchName <VM Switch Name> |
Configure a VM
To configure deeply a VM, you can use the Set-VM PowerShell cmdlet. Below an example:
1 2 3 4 5 6 7 8 9 |
Set-VM -Name <VM Name> -ProcessorCount <number of vCPU> -DynamicMemory -MemoryMinimumBytes <Minimum Memory> -MemoryStartupBytes <Startup Memory> -MemoryMaximumBytes <Maximum Memory> -AutomaticStartAction <automatic Start Action> -AutomaticStartDelay <Automatic Start Delay in second> -AutomaticStopAction <Automatic stop action> |
- Name: Name of the VM you would like to edit
- ProcessorCount: number of vCPU that you want to assign to the VM
- DynamicMemory: Enable the Dynamic Memory
- MemoryMinimumBytes: set the minimum memory value
- MemoryStartupBytes: set the startup memory value
- MemoryMaximumBytes: set the maximum memory value
- AutomaticStartAction: action which is run when the Hyper-V service is starting (Nothing, Start, StartIfRunning)
- AutomaticStartDelay: number of second to wait before the automatic start action is run
- AutomaticStopAction: action which is run when the Hyper-V service is stopping (Save, Shutdown, TurnOff)
Below you can find an example of VM configuration with the above command:
If you want to configure the VM with static memory you can use the below command:
1 2 3 4 5 6 |
Set-VM -Name <VM Name> -ProcessorCount <number of vCPU> -StaticMemory -AutomaticStartAction <automatic Start Action> -AutomaticStartDelay <Automatic Start Delay in second> -AutomaticStopAction <Automatic stop action> |
Manage VM Storage
Add the OS disk and set the primary boot
If you have run the below command to create a VM without VHD(X), maybe you would like to attach now your syspreped VHD(X):
1 2 3 4 5 6 |
New-VM -Name <VMName> -Path <VMPath> -NoVHD -Generation <VM Gen (1 or 2)> -MemoryStartupBytes <Startup Memory> -SwitchName <VM Switch Name> |
To attach the VHD(x) to the VM, you have just to run Add-VMHardDiskDrive PowerShell command:
1 2 |
Add-VMHardDiskDrive -VMName <VMName> -Path <VHD(X) path> |
- VMName: Name of the related VM
- Path: Path to the VHD(X) file
Below you can find an example of attaching a VHD(X) file to a VM:
Now you can set this disk to primary boot by using the Set-VMFirmware PowerShell cmdlet:
1 2 |
$OsVirtualDrive = Get-VMHardDiskDrive -VMName <VM Name> -ControllerNumber 0 Set-VMFirmware -VMName <VM Name> -FirstBootDevice $OSVirtualDrive |
- VMName: VM of the related VM
Below you can find an example of the using of the above command:
Adding additional VHD(X)
To create a new VHD(X) you can use the New-VHD cmdlet as below:
1 2 3 |
New-VHD -Path <Path of the VHD(X)> -SizeBytes <Disk Size> -Dynamic |
- Path: absolute path to the VHD(X) file
- SizeBytes: Size of the VHD(X)
- Dynamic (can be replace by fixed): Dynamic or fixed VHD(X)
Once you have created the disk, you can attach it by using Add-VMHardDiskDrive as below:
1 2 |
Add-VMHardDiskDrive -VMName <VM Name> -Path <Path of the VHD(X)> |
Manage network adapters
Add network adapters
To add a network adapter, you can run the below command:
1 2 3 |
Add-VMNetworkAdapter -VMName <VM Name> -SwitchName <VM Switch Name> -Name <Network Adapter Name> |
- VMName: name of the VM
- SwitchName: Name of the VM Switch to connect to
- Name: Name of the network adapter
Below you can find an example of the above command:
Configure network adapters
There are a lot of options in network adapters configuration. You can configure all of them by using PowerShell but I present only some of them. You can find the help of these PowerShell cmdlet in TechNet. To configure the Network Adapter, you can run the below command:
1 2 3 |
Set-VMNetworkAdapter -MacAddressSpoofing <on/off> -DHCPGuard <on/off> -RouterGuard <on/off> |
- MacAddressSpoofing: Enable or disable Mac Spoofing
- DHCPGuard: Enable or disable DHCP Guard
- RouterGuard: Enable or disable router guard
Below you can find an example of the use of this PowerShell cmdlet:
Set the VLAN
To set the VLAN on a network adapter, you can use the Set-VMNetworkAdapterVLAN PowerShell cmdlet:
1 |
Set-VMNetworkAdapterVLAN -Access -VlanId <VlanId> |
- Access: Set the Access mode on the network adapter
- VlanId: set the VLAN ID value
To leave untagged the network adapter, you can run the below command:
1 |
Set-VMNetworkAdapterVLAN -untagged |
Below you can find an example of this PowerShell command:
Script to automatically deploy a VM
Below you can find a script that I have written to deploy several VMs from the same configuration. This script is not perfect and can be improved by adding try/catch. You can also modify parameters to be passed in command line as arguments. In this way you will be able to make a loop to deploy quickly several VMs. To use this script you need a sysprep VHD(X).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
###################################################### ### Template Definition ### ###################################################### # VM Name $VMName = "MyNewVM01" # Automatic Start Action (Nothing = 0, Start =1, StartifRunning = 2) $AutoStartAction = 1 # In second $AutoStartDelay = 10 # Automatic Start Action (TurnOff = 0, Save =1, Shutdown = 2) $AutoStopAction = 2 ###### Hardware Configuration ###### # VM Path $VMPath = "D:\" # VM Generation (1 or 2) $Gen = 2 # Processor Number $ProcessorCount = 4 ## Memory (Static = 0 or Dynamic = 1) $Memory = 1 # StaticMemory $StaticMemory = 8GB # DynamicMemory $StartupMemory = 2GB $MinMemory = 1GB $MaxMemory = 4GB # Sysprep VHD path (The VHD will be copied to the VM folder) $SysVHDPath = "D:\OperatingSystem-W2012R2DTC.vhdx" # Rename the VHD copied in VM folder to: $OsDiskName = $VMName ### Additional virtual drives $ExtraDrive = @() # Drive 1 $Drive = New-Object System.Object $Drive | Add-Member -MemberType NoteProperty -Name Name -Value Data $Drive | Add-Member -MemberType NoteProperty -Name Path -Value $($VMPath + "\" + $VMName) $Drive | Add-Member -MemberType NoteProperty -Name Size -Value 10GB $Drive | Add-Member -MemberType NoteProperty -Name Type -Value Dynamic $ExtraDrive += $Drive # Drive 2 $Drive = New-Object System.Object $Drive | Add-Member -MemberType NoteProperty -Name Name -Value Bin $Drive | Add-Member -MemberType NoteProperty -Name Path -Value $($VMPath + "\" + $VMName) $Drive | Add-Member -MemberType NoteProperty -Name Size -Value 20GB $Drive | Add-Member -MemberType NoteProperty -Name Type -Value Fixed $ExtraDrive += $Drive # You can copy/delete this below block as you wish to create (or not) and attach several VHDX ### Network Adapters # Primary Network interface: VMSwitch $VMSwitchName = "LS_VMWorkload" $VlanId = 0 $VMQ = $False $IPSecOffload = $False $SRIOV = $False $MacSpoofing = $False $DHCPGuard = $False $RouterGuard = $False $NicTeaming = $False ## Additional NICs $NICs = @() # NIC 1 $NIC = New-Object System.Object $NIC | Add-Member -MemberType NoteProperty -Name VMSwitch -Value "LS_VMWorkload" $NIC | Add-Member -MemberType NoteProperty -Name VLAN -Value 10 $NIC | Add-Member -MemberType NoteProperty -Name VMQ -Value $False $NIC | Add-Member -MemberType NoteProperty -Name IPsecOffload -Value $True $NIC | Add-Member -MemberType NoteProperty -Name SRIOV -Value $False $NIC | Add-Member -MemberType NoteProperty -Name MacSpoofing -Value $False $NIC | Add-Member -MemberType NoteProperty -Name DHCPGuard -Value $False $NIC | Add-Member -MemberType NoteProperty -Name RouterGuard -Value $False $NIC | Add-Member -MemberType NoteProperty -Name NICTeaming -Value $False $NICs += $NIC #NIC 2 $NIC = New-Object System.Object $NIC | Add-Member -MemberType NoteProperty -Name VMSwitch -Value "LS_VMWorkload" $NIC | Add-Member -MemberType NoteProperty -Name VLAN -Value 20 $NIC | Add-Member -MemberType NoteProperty -Name VMQ -Value $False $NIC | Add-Member -MemberType NoteProperty -Name IPsecOffload -Value $True $NIC | Add-Member -MemberType NoteProperty -Name SRIOV -Value $False $NIC | Add-Member -MemberType NoteProperty -Name MacSpoofing -Value $False $NIC | Add-Member -MemberType NoteProperty -Name DHCPGuard -Value $False $NIC | Add-Member -MemberType NoteProperty -Name RouterGuard -Value $False $NIC | Add-Member -MemberType NoteProperty -Name NICTeaming -Value $False $NICs += $NIC # You can copy/delete the above block and set it for additional NIC ###################################################### ### VM Creation and Configuration ### ###################################################### ## Creation of the VM # Creation without VHD and with a default memory value (will be changed after) New-VM -Name $VMName ` -Path $VMPath ` -NoVHD ` -Generation $Gen ` -MemoryStartupBytes 1GB ` -SwitchName $VMSwitchName if ($AutoStartAction -eq 0){$StartAction = "Nothing"} Elseif ($AutoStartAction -eq 1){$StartAction = "Start"} Else{$StartAction = "StartIfRunning"} if ($AutoStopAction -eq 0){$StopAction = "TurnOff"} Elseif ($AutoStopAction -eq 1){$StopAction = "Save"} Else{$StopAction = "Shutdown"} ## Changing the number of processor and the memory # If Static Memory if (!$Memory){ Set-VM -Name $VMName ` -ProcessorCount $ProcessorCount ` -StaticMemory ` -MemoryStartupBytes $StaticMemory ` -AutomaticStartAction $StartAction ` -AutomaticStartDelay $AutoStartDelay ` -AutomaticStopAction $StopAction } # If Dynamic Memory Else{ Set-VM -Name $VMName ` -ProcessorCount $ProcessorCount ` -DynamicMemory ` -MemoryMinimumBytes $MinMemory ` -MemoryStartupBytes $StartupMemory ` -MemoryMaximumBytes $MaxMemory ` -AutomaticStartAction $StartAction ` -AutomaticStartDelay $AutoStartDelay ` -AutomaticStopAction $StopAction } ## Set the primary network adapters $PrimaryNetAdapter = Get-VM $VMName | Get-VMNetworkAdapter if ($VlanId -gt 0){$PrimaryNetAdapter | Set-VMNetworkAdapterVLAN -Access -VlanId $VlanId} else{$PrimaryNetAdapter | Set-VMNetworkAdapterVLAN -untagged} if ($VMQ){$PrimaryNetAdapter | Set-VMNetworkAdapter -VmqWeight 100} Else {$PrimaryNetAdapter | Set-VMNetworkAdapter -VmqWeight 0} if ($IPSecOffload){$PrimaryNetAdapter | Set-VMNetworkAdapter -IPsecOffloadMaximumSecurityAssociation 512} Else {$PrimaryNetAdapter | Set-VMNetworkAdapter -IPsecOffloadMaximumSecurityAssociation 0} if ($SRIOV){$PrimaryNetAdapter | Set-VMNetworkAdapter -IovQueuePairsRequested 1 -IovInterruptModeration Default -IovWeight 100} Else{$PrimaryNetAdapter | Set-VMNetworkAdapter -IovWeight 0} if ($MacSpoofing){$PrimaryNetAdapter | Set-VMNetworkAdapter -MacAddressSpoofing on} Else {$PrimaryNetAdapter | Set-VMNetworkAdapter -MacAddressSpoofing off} if ($DHCPGuard){$PrimaryNetAdapter | Set-VMNetworkAdapter -DHCPGuard on} Else {$PrimaryNetAdapter | Set-VMNetworkAdapter -DHCPGuard off} if ($RouterGuard){$PrimaryNetAdapter | Set-VMNetworkAdapter -RouterGuard on} Else {$PrimaryNetAdapter | Set-VMNetworkAdapter -RouterGuard off} if ($NicTeaming){$PrimaryNetAdapter | Set-VMNetworkAdapter -AllowTeaming on} Else {$PrimaryNetAdapter | Set-VMNetworkAdapter -AllowTeaming off} ## VHD(X) OS disk copy $OsDiskInfo = Get-Item $SysVHDPath Copy-Item -Path $SysVHDPath -Destination $($VMPath + "\" + $VMName) Rename-Item -Path $($VMPath + "\" + $VMName + "\" + $OsDiskInfo.Name) -NewName $($OsDiskName + $OsDiskInfo.Extension) # Attach the VHD(x) to the VM Add-VMHardDiskDrive -VMName $VMName -Path $($VMPath + "\" + $VMName + "\" + $OsDiskName + $OsDiskInfo.Extension) $OsVirtualDrive = Get-VMHardDiskDrive -VMName $VMName -ControllerNumber 0 # Change the boot order to the VHDX first Set-VMFirmware -VMName $VMName -FirstBootDevice $OsVirtualDrive # For additional each Disk in the collection Foreach ($Disk in $ExtraDrive){ # if it is dynamic if ($Disk.Type -like "Dynamic"){ New-VHD -Path $($Disk.Path + "\" + $Disk.Name + ".vhdx") ` -SizeBytes $Disk.Size ` -Dynamic } # if it is fixed Elseif ($Disk.Type -like "Fixed"){ New-VHD -Path $($Disk.Path + "\" + $Disk.Name + ".vhdx") ` -SizeBytes $Disk.Size ` -Fixed } # Attach the VHD(x) to the Vm Add-VMHardDiskDrive -VMName $VMName ` -Path $($Disk.Path + "\" + $Disk.Name + ".vhdx") } $i = 2 # foreach additional network adapters Foreach ($NetAdapter in $NICs){ # add the NIC Add-VMNetworkAdapter -VMName $VMName -SwitchName $NetAdapter.VMSwitch -Name "Network Adapter $i" $ExtraNic = Get-VM -Name $VMName | Get-VMNetworkAdapter -Name "Network Adapter $i" # Configure the NIC regarding the option if ($NetAdapter.VLAN -gt 0){$ExtraNic | Set-VMNetworkAdapterVLAN -Access -VlanId $NetAdapter.VLAN} else{$ExtraNic | Set-VMNetworkAdapterVLAN -untagged} if ($NetAdapter.VMQ){$ExtraNic | Set-VMNetworkAdapter -VmqWeight 100} Else {$ExtraNic | Set-VMNetworkAdapter -VmqWeight 0} if ($NetAdapter.IPSecOffload){$ExtraNic | Set-VMNetworkAdapter -IPsecOffloadMaximumSecurityAssociation 512} Else {$ExtraNic | Set-VMNetworkAdapter -IPsecOffloadMaximumSecurityAssociation 0} if ($NetAdapter.SRIOV){$ExtraNic | Set-VMNetworkAdapter -IovQueuePairsRequested 1 -IovInterruptModeration Default -IovWeight 100} Else{$ExtraNic | Set-VMNetworkAdapter -IovWeight 0} if ($NetAdapter.MacSpoofing){$ExtraNic | Set-VMNetworkAdapter -MacAddressSpoofing on} Else {$ExtraNic | Set-VMNetworkAdapter -MacAddressSpoofing off} if ($NetAdapter.DHCPGuard){$ExtraNic | Set-VMNetworkAdapter -DHCPGuard on} Else {$ExtraNic | Set-VMNetworkAdapter -DHCPGuard off} if ($NetAdapter.RouterGuard){$ExtraNic | Set-VMNetworkAdapter -RouterGuard on} Else {$ExtraNic | Set-VMNetworkAdapter -RouterGuard off} if ($NetAdapter.NicTeaming){$ExtraNic | Set-VMNetworkAdapter -AllowTeaming on} Else {$ExtraNic | Set-VMNetworkAdapter -AllowTeaming off} $i++ } |
Conclusion
If you can’t buy VMM and you want to deploy automatically VM, it is still possible by using PowerShell. All examples presented are not exhaustive. There are several other combinations possible. All cmdlet documentation can be found in the TechNet.