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

clip_image001

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 -taylor

  • Anonymous
    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? -Don

  • Anonymous
    June 08, 2011
    Hi Thanks works great..Can you provide a similar code to remove an attached VHD. Amit