PDC Teaser – Attaching a VHD to A Virtual Machine
PDC is just around the corner now – I am giving the dry run of my talk tomorrow morning, so of course I am working on my demo’s today… Just to give you a bit of a teaser here’s one of the scripts that I am using in one of my demo’s…
This script will take a VHD and attach it to the second port of the first IDE controller, just change the address numbers and you can change where it get’s attached.
Note that I am using the ProcessWMIJob function from Hyper-V WMI: Rich Error Messages for Non-Zero ReturnValue (no more 32773, 32768, 32700…)
$vhdToMount = "c:\test.vhd" $HyperVGuest = "ScriptTest" $VMManagementService = Get-WmiObject -class "Msvm_VirtualSystemManagementService" -namespace "root\virtualization" $Vm = Get-WmiObject -Namespace "root\virtualization" -Query "Select * From Msvm_ComputerSystem Where ElementName='$HyperVGuest'" $VMSettingData = Get-WmiObject -Namespace "root\virtualization" -Query "Associators of {$Vm} Where ResultClass=Msvm_VirtualSystemSettingData AssocClass=Msvm_SettingsDefineState" $VmScsiController = (Get-WmiObject -Namespace "root\virtualization" -Query "Associators of {$VMSettingData} Where ResultClass=Msvm_ResourceAllocationSettingData AssocClass=Msvm_VirtualSystemSettingDataComponent" | ` where-object {$_.ResourceSubType -eq "Microsoft Emulated IDE Controller" -and $_.Address -eq 0}) $DiskAllocationSetting = Get-WmiObject -Namespace "root\virtualization" -Query "SELECT * FROM Msvm_AllocationCapabilities WHERE ResourceSubType = 'Microsoft Synthetic Disk Drive'" $DefaultDiskDrive = (Get-WmiObject -Namespace "root\virtualization" -Query "Associators of {$DiskAllocationSetting} Where ResultClass=Msvm_ResourceAllocationSettingData AssocClass=Msvm_SettingsDefineCapabilities" | ` where-object {$_.InstanceID -like "*Default"}) $DefaultDiskDrive.Parent = $VmScsiController.__Path $DefaultDiskDrive.Address = 1 $NewDiskDrive = ($VMManagementService.AddVirtualSystemResources($Vm.__Path, $DefaultDiskDrive.PSBase.GetText(1)) | ProcessWMIJob $VMManagementService "AddVirtualSystemResources").NewResources $DiskAllocationSetting = Get-WmiObject -Namespace "root\virtualization" -Query "SELECT * FROM Msvm_AllocationCapabilities WHERE ResourceSubType = 'Microsoft Virtual Hard Disk'" $DefaultHardDisk = (Get-WmiObject -Namespace "root\virtualization" -Query "Associators of {$DiskAllocationSetting} Where ResultClass=Msvm_ResourceAllocationSettingData AssocClass=Msvm_SettingsDefineCapabilities" | ` where-object {$_.InstanceID -like "*Default"}) $DefaultHardDisk.Parent = $NewDiskDrive $DefaultHardDisk.Connection = $vhdToMount $VMManagementService.AddVirtualSystemResources($Vm.__Path, $DefaultHardDisk.PSBase.GetText(1)) | ProcessWMIJob $VMManagementService "AddVirtualSystemResources" |
Taylor Brown
Hyper-V Integration Test Lead
https://blogs.msdn.com/taylorb
Comments
Anonymous
December 08, 2008
Cool, now how about a C# sample? =========================================================== Take a look at http://msdn.microsoft.com/en-us/library/cc160705(VS.85).aspx -taylorAnonymous
December 09, 2008
Yeh, I've tried that sample, but having troubles translating that to virtual hard drives. They seem a bit more complicated??? On a side note the referenced sample works great, just not sure how to specify the "network" to attach the nic. ==========================================================
I start my "vacation" next week - I am planning on trying to get cought up on blog posts and I'll add this to the list. -Taylor
p.s. yes that is my idea of a vacation.Anonymous
December 15, 2008
Could you please provide the C# version of above code? We are having problems in executing the MSDN code. Thanks.Anonymous
December 16, 2008
Interesting way to vacation, guess you're a computer geek like the rest of us :-( OK, I figured out the same in C#...guess the secret was to understand how the WMI objects are all related. I did this by creating a VirtualMachineList utility that attempts to dump WMI objects that are related to an existing virtual machine, that helped tons. Anyway, following is a sample of how to attach a virtual hard drive (.VHD) to a virtual machine's SCSI controller in C# ... This sample uses utilities found at http://msdn.microsoft.com/en-us/library/cc723869(VS.85).aspx using System; using System.Management; using System.Collections; using System.Text; ... Interesting way to vacation, guess you're a computer geek like the rest of us :-( OK, I figured out the same in C#...guess the secret was to understand how the WMI objects are all related. I did this by creating a VirtualMachineList utility that attempts to dump WMI objects that are related to an existing virtual machine, that helped tons. Anyway, following is a sample of how to attach a virtual hard drive (.VHD) to a virtual machine's SCSI controller in C#... This sample uses utilities found at http://msdn.microsoft.com/en-us/library/cc723869(VS.85).aspx using System; using System.Management; using System.Collections; using System.Text; ... //******************************************************************************************************************** static UInt32 AddVirtualSystemResource(ManagementScope scope, ManagementObject virtualMachine, ManagementObject resourceToAdd, ref ManagementObject resourceAdded) { UInt32 result = 0; ManagementObject[] resourcesToAddList = new ManagementObject[1]; resourcesToAddList[0] = resourceToAdd; string[] resourcesAddedList = null; result = AddVirtualSystemResources(scope, virtualMachine, resourcesToAddList, ref resourcesAddedList); if ((result == 0) && (resourcesAddedList != null)) { resourceAdded = new ManagementObject(scope, new ManagementPath(resourcesAddedList[0]), null); } return result; } //******************************************************************************************************************** static UInt32 AddVirtualSystemResources(ManagementScope scope, ManagementObject virtualMachine, ManagementObject[] resourcesToAdd, ref string[] resourcesAdded) { UInt32 result = 0; ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService"); ManagementBaseObject inParams = virtualSystemService.GetMethodParameters("AddVirtualSystemResources"); int idx = resourcesToAdd.GetLength(0); string[] resourcesToAddString = new string[idx]; g_dumpData.DumpString("------------------------------------------------------------------------------"); g_dumpData.DumpString("AddedVirtualSystemResources():"); idx = 0; foreach (ManagementObject resource in resourcesToAdd) { resourcesToAddString[idx++] = resource.GetText(TextFormat.CimDtd20); g_dumpData.DumpString("Type=" + resource["ResourceType"] + ", Subtype=" + resource["ResourceSubtype"]); if (resource["Connection"] != null) { foreach (string connection in (string[])resource["Connection"]) { g_dumpData.DumpString("Connection=" + connection); } } } inParams["ResourcesettingData"] = resourcesToAddString; inParams["TargetSystem"] = virtualMachine.Path.Path; resourcesAdded = null; ManagementBaseObject outParams = virtualSystemService.InvokeMethod("AddVirtualSystemResources", inParams, null); resourcesAdded = null; if ((UInt32)outParams["ReturnValue"] == ReturnCode.Started) { if (Utility.JobCompleted(outParams, scope)) { result = 0; resourcesAdded = (string[])outParams["NewResources"]; //syntheticNic = new ManagementObject(addedResources[0]); g_dumpData.DumpString("Resource(s) were added successfully."); } else { result = (UInt32)outParams["ReturnValue"]; g_dumpData.DumpString("Failed to add resource(s)"); } } else if ((UInt32)outParams["ReturnValue"] == ReturnCode.Completed) { result = 0; resourcesAdded = (string[])outParams["NewResources"]; //syntheticNic = new ManagementObject(addedResources[0]); g_dumpData.DumpString("Resource(s) were added successfully."); } else { result = (UInt32)outParams["ReturnValue"]; g_dumpData.DumpString("Add virtual system resource(s) failed with error:" + outParams["ReturnValue"]); } inParams.Dispose(); outParams.Dispose(); return result; } //******************************************************************************************************************** static UInt32 AddVirtualHarddrive(ManagementScope scope, ManagementObject virtualMachine, string newVHDParams) { UInt32 result = 0; string vhdToMount = @"E:test.vhd"; ManagementObject virtualSystemService = Utility.GetServiceObject(scope, "Msvm_VirtualSystemManagementService"); ManagementObject vmSettingsData = Utility.GetVirtualSystemSettingData(virtualMachine); // Locate the SCSI controller on the vm ManagementObject vmDiskController = Utility.GetResourceAllocationsettingData(virtualMachine, ResourceType.ParallelSCSIHBA, ResourceSubType.ParallelSCSIHBA, null); if (vmDiskController == null) { // SCSI controller does not exits on the vm, create it ManagementObject vmDiskControllerDefault = Utility.GetResourceAllocationsettingDataDefault(scope, ResourceType.ParallelSCSIHBA, ResourceSubType.ParallelSCSIHBA, null); result = AddVirtualSystemResource(scope, virtualMachine, vmDiskControllerDefault, ref vmDiskController); } // Create the Synthetic disk drive on the SCSI controller int SCSIfreeLocation = -1; LocateFreeSCSILocation(scope, vmDiskController.Path.ToString(), ref SCSIfreeLocation); ManagementObject syntheticDiskDriveDefault = Utility.GetResourceAllocationsettingDataDefault(scope, ResourceType.Disk, ResourceSubType.DiskSynthetic, null); syntheticDiskDriveDefault["Parent"] = vmDiskController.Path; syntheticDiskDriveDefault["Address"] = SCSIfreeLocation; syntheticDiskDriveDefault["Limit"] = 1; // Not sure what this does??? ManagementObject newDiskDrive = null; result = AddVirtualSystemResource(scope, virtualMachine, syntheticDiskDriveDefault, ref newDiskDrive); // Now create a new virtual hard disk, associate it with the new synthetic disk drive and attach the virtual hard drive to the virtual machine ManagementObject vhdDefault = Utility.GetResourceAllocationsettingDataDefault(scope, ResourceType.StorageExtent, ResourceSubType.VHD, null); vhdDefault["Parent"] = newDiskDrive; string[] connection = new string[1]; connection[0] = vhdToMount; vhdDefault["Connection"] = connection; ManagementObject newVHD = null; result = AddVirtualSystemResource(scope, virtualMachine, vhdDefault, ref newVHD); return result; // maybe return newVHD } //********************************************************************************************************************Anonymous
December 18, 2008
Mark, in your C# example you have LocateFreeSCSILocation(scope, vmDiskController.Path.ToString(), ref SCSIfreeLocation); but "LocateFreeSCSILocation" doesn’t exist anywhere else in the context? -DonAnonymous
June 08, 2011
Hi Thanks works great..Can you provide a similar code to remove an attached VHD. Amit