Ok, so far we have created, modified, and added resources (memory, processor, disks, and network) to virtual machines. Now, we want to take that information and build a complete virtual machine.
# Set up variables
$VHD = "f:\VHDs\win2k8.vhd"
$GuestVM = "Win2k8"
$Namespace = "root\virtualization"
$Computer = "HyperV"
$VHDSize = "10GB"
$VMSwitchName = "Hyper-V External Switch"
$VMSwitchPortName = "MyPort"
$VMNICAddress = "00155D9290FF"
$VMSvc = Get-WmiObject -class "Msvm_VirtualSystemManagementService" -namespace $Namespace -ComputerName $Computer
$VM = Get-WmiObject -Namespace $Namespace -ComputerName $Computer -Query "Select * From Msvm_ComputerSystem Where ElementName='$GuestVM'"
$VMSettingData = Get-WmiObject -Namespace $Namespace -Query "Associators of {$VM} Where ResultClass=Msvm_VirtualSystemSettingData AssocClass=Msvm_SettingsDefineState"
# Give the new virtual machine a name
$VMGlobalSettingClass = [WMIClass]"\\$Computer\root\virtualization:Msvm_VirtualSystemGlobalSettingData"
$NewVMGS = $VMGlobalSettingClass.psbase.CreateInstance()
while ($NewVMGS.psbase.Properties -eq $null) {}
$NewVMGS.psbase.Properties.Item("ElementName").value = $GuestVM
# Create a virtual disk
$VMDiskSvc = Get-WmiObject -Class "Msvm_ImageManagementService" -Namespace "root\virtualization"
$DiskCreate = $VMDiskSvc.CreateFixedVirtualHardDisk($VHD, 10GB)
$DiskJob = [WMI]$DiskCreate.job
while (($DiskJob.JobState -eq "2") -or ($DiskJob.JobState -eq "3") -or ($DiskJob.JobState -eq "4")) {Start-Sleep -m 100 $DiskJob = [WMI]$DiskCreate.job}
#Create memory resource
$VMMem = (Get-WmiObject -Namespace $Namespace -Query "Associators of {$VMSettingData} Where ResultClass = Msvm_VirtualSystemSettingDataComponent" | where-object -FilterScript {$_.ResourceSubType -eq "Microsoft Virtual Machine Memory"})
$VMMem.VirtualQuantity = [string]2048
$VMMem.Reservation = [string]2048
$VMMem.Limit = [string]2048
# Create processor resource
$VMProc = (Get-WmiObject -Namespace $Namespace -Query "Associators of {$VMSettingData} Where ResultClass = Msvm_ProcessorSettingData" | where-object -FilterScript {$_.ResourceSubType -eq "Microsoft Processor"})
$VMProc.VirtualQuantity = [string]1
$VMProc.Reservation = [string]0
$VMProc.Limit = [string]100000
$VMProc.Weight = [string]100
# Create network interface
$DefaultNet = Get-WmiObject -Namespace $Namespace -Class Msvm_SyntheticEthernetPortSettingData | Where-Object -FilterScript {$_.InstanceID -like "*Default*"}
$GUID1 = [GUID]::NewGUID().ToString()
$GUID2 = [GUID]::NewGUID().ToString()
$VMSwitchQuery = Get-WmiObject -Class "Msvm_VirtualSwitchManagementService" -Namespace $Namespace
# $VMSvc = Get-WmiObject -Class "Msvm_VirtualSystemManagementService" -namespace $Namespace -ComputerName $Computer
$VMSwitch = Get-WmiObject -Namespace $Namespace -Query "Select * From Msvm_VirtualSwitch Where ElementName = '$VMSwitchName'"
$ReturnObject = $VMSwitchQuery.CreateSwitchPort($VMSwitch, [guid]::NewGuid().ToString(), $VMSwitchPortName, "")
$NewSwitchPort1 = $ReturnObject.CreatedSwitchPort
$ReturnObject = $VMSwitchQuery.CreateSwitchPort($VMSwitch, [guid]::NewGUID().ToString(), $VMSwitchPortName, "")
$NewSwitchPort2 = $ReturnObject.CreatedSwitchPort
$StaticNet = $DefaultNet.psbase.Clone()
$StaticNet.VirtualSystemIdentifiers = "{GUID1}"
$StaticNet.StaticMacAddress = $true
$StaticNet.Address = $VMNICAddress
$StaticNet.Connection = $NewSwitchPort1
$DynNet = $DefaultNet.psbase.Clone()
$DynNet.VirtualSystemIdentifiers = "{GUID2}"
$DynNet.Connection = $NewSwitchPort2
#Add the network interface resources to Resource Allocation Settings
$VMRASD = @()
$VMRASD += $StaticNet.psbase.gettext(1)
$VMRASD += $DynNet.psbase.gettext(1)
$VMRASD += $VMMem.psbase.gettext(1)
$VMRASD += $VMProc.psbase.gettext(1)
# Time to create the virtual machine
$VMSvc.DefineVirtualSystem($NewVMGS.psbase.GetText(1), $VMRASD)
# Add our disk to the virtual machine
# $VM = Get-WmiObject -Namespace $Namespace -ComputerName $Computer -Query "Select * From Msvm_ComputerSystem Where ElementName = '$GuestVM'"
# $VMSettingData = Get-WmiObject -Namespace $Namespace -Query "Associators of {$VM} Where ResultClass = Msvm_VirtualSystemSettingData AssocClass = Msvm_SettingsDefineState"
$VMIDECtrl = (Get-WmiObject -Namespace $Namespace -Query "Associators of {$VMSettingData} Where ResultClass = Msvm_ResourceAllocationSettingData AssocClass = Msvm_VirtualSystemSettingDataComponent" | where-object -FilterScript {$_.ResourceSubType -eq "Microsoft Emulated IDE Controller" -and $_.Address -eq 0})
$DiskAllocationSetting = Get-WmiObject -Namespace $Namespace -Query "Select * From Msvm_AllocationCapabilities Where ResourceSubType = 'Microsoft Synthetic Disk Drive'"
$DefaultDiskDrive = (Get-WmiObject -Namespace $Namespace -Query "Associators of {$DiskAllocationSetting} Where ResultClass = Msvm_ResourceAllocationSettingData AssocClass = Msvm_SettingsDefineCapabilities" | where-object -FilterScript {$_.InstanceID -like "*Default*"})
$DefaultDiskDrive.Parent = $VMIDECtrl._Path
$DefaultDiskDrive.Address = 0
$NewDiskDrive = ($VMSvc.AddVirtualSystemResources($VM._Path, $DefaultDiskDrive.PSBase.GetText(1))).NewResources
$DiskAllocationSetting = Get-WmiObject -Namespace $Namespace -Query "Select * From Msvm_AllocationCapabilities Where ResourceSubType = 'Microsoft Virtual Hard Disk'"
$DefaultHardDisk = (Get-WmiObject -Namespace $Namespace -Query "Associators of {$DiskAllocationSetting} Where ResultClass = Msvm_ResourceAllocationSettingData AssocClass = Msvm_SettingsDefineCapabilities" | where-object -FilterScript {$_.InstanceID -like "*Default"})
$DefaultHardDisk.Parent = $NewDiskDrive
$DefaultHardDisk.Connection = $VHD
$VMSvc.AddVirtualSystemResources($VM._Path, $DefaultHardDisk.PSBase.GetText(1))
#Now, we add a DVD
$DVDAllocationSetting = Get-WmiObject -Namespace $Namespace -Query "Select * From Msvm_AllocationCapabilities Where ResourceSubType = 'Microsoft Synthetic DVD Drive'"
$DefaultDVDDrive = (Get-WmiObject -Namespace $Namespace -Query "Associators of {$DVDAllocationSetting} Where ResultClass = Msvm_ResourceAllocationSettingData AssocClass = Msvm_SettingsDefineCapabilities" | where-object -FilterScript {$_.InstanceID -like "*Default"})
$DefaultDVDDrive.Parent = $VMIDECtrl._Path
$DefaultDVDDrive.Address = 1
$NewDVDDrive = $DefaultDVDDrive.psbase.Clone()
$VMSvc.AddVirtualSystemResources($VM._Path, $NewDVDDrive.psbase.GetText(1))
In this code, I am using a data array to contain all of the resources that will be used to create the virtual machine.
$VMRASD = @()
$VMRASD += $StaticNet.psbase.gettext(1)
$VMRASD += $DynNet.psbase.gettext(1)
You will notice that the hard disk and DVD drive are not included in this array. This is because they are added to a virtual IDE port. These ports do not exist until after the virtual machine is created, so we add them after it is.
That wraps up this session for automating Hyper-V virtual machine creation through scripts. As always, any comments or questions, let me know.
6 comments:
This doesn't work as is... In fact I'm still trying to get it to work...
Errors:
$VMSettingData = Get-WmiObject -Namespace $Namespace –Query “Associators of {$VM} Where ResultClass = Msvm_VirtualSystemSettingData AssocClass = Msvm_SettingDefineState”
$VM is used, but doesn't get declared until the bottom of the script and the above is line #2 of actual code.
I've also got an error with "10GB" being a string and not a UINT64....
There are other errors as well, but these are the 1st errors.
Thanks for pointing those out. The $VMSettingData was left in by mistake for the final script. It is being set later in the script when I add the disk.
For the 10GB in a string. I was playing around with passing it as a variable, but apparently did not set it back in the script when all of that failed.
On a quick run through the code, I found another typo that I corrected as well. Thanks for keeping me honest.
$VMMem and $VMProc both use $VMSettingData (which uses $VM) and both are setting these up before the VM is created...
Did you update the code and I'm just blind or did you make a new post?
My bad. Apparently my edits autosaved, but did not update in the post. I just restored the autosave and posted. This time I checked to make sure the proper code is displaying. Thanks for your patience.
W00t! Thanks! It looks better... I have another question...
#Create memory resource
$VMMem = (Get-WmiObject -Namespace $Namespace -Query "Associators of {$VMSettingData} Where ResultClass = Msvm_VirtualSystemSettingDataComponent" | where-object -FilterScript {$_.ResourceSubType -eq "Microsoft Virtual Machine Memory"})
This references $VMSettingData and it's now declared after this line... On my script, that I derived from yours, I just made mine ALTER the machine after it's created.
Altering is good workaround for my faltering script. I sat down with it and threw it into Scriptomatic for Powershell to help me pinpoint other errors and typos. Boy, were there a lot of typos. Misplaced {} and () along with spaces that WMI just does not like at all. I also moved $VMSettingData back to the top of the script, where I am also declaring $VM. These are global variables that are set once and used multiple times in the script. Check out the updated script in the post and let me know how it works out for you.
Post a Comment