Hyper-V: Scripting Dynamic VHD Creation

Today I would like to show you some basic scripts for creating a new dynamically expanding virtual hard disk.  The tricky thing about doing this is that the WMI interfaces for creating virtual hard disks expect the size of the new virtual hard disk to be specified as a UINT64.  This requires some special handling - but can be done in both VBScript and PowerShell.

VBScript:

 Option Explicit
  
 'Setup constant to use for getting the right value for the new VHD size
 const Size1G = &H40000000
  
 Dim HyperVServer
 Dim VHDName
 Dim VHDSize
 Dim WMIService
 Dim Msvm_ImageManagementService
 Dim Result
 Dim Job
 Dim InParam
 Dim OutParam
  
 'Prompt for the Hyper-V Server to use
 HyperVServer = InputBox("Specify the Hyper-V Server to create the dynamic virtual hard disk on:")
  
 'Get name for VHD
 VHDName = InputBox("Specify the name of the new dynamic virtual hard disk:")
  
 'Get size for VHD
 VHDSize = InputBox("Specify the size of the new dynamic virtual hard disk (in GB):") * Size1G
  
 'Get an instance of the WMI Service in the virtualization namespace.
 Set WMIService = GetObject("winmgmts:\\" & HyperVServer & "\root\virtualization")
  
 'Get the Msvm_ImageManagementService object
 Set Msvm_ImageManagementService = WMIService.ExecQuery("SELECT * FROM Msvm_ImageManagementService").ItemIndex(0)
  
 'Setup the input parameter list
 Set InParam = Msvm_ImageManagementService.Methods_("CreateDynamicVirtualHardDisk").InParameters.SpawnInstance_()
 InParam.Path = VHDName 
 InParam.MaxInternalSize = VHDSize
  
 'Execute the method and store the results in OutParam
 Set OutParam = Msvm_ImageManagementService.ExecMethod_("CreateDynamicVirtualHardDisk", InParam) 
  
 'Check to see if the job completed synchronously
 if (OutParam.ReturnValue = 0) then
    Wscript.Echo "The virtual hard disk has been created."
 elseif (OutParam.ReturnValue <> 4096) then
    Wscript.Echo "The virtual hard disk has not been created."
 else   
  
    'Get the job object
    set Job = WMIService.Get(OutParam.Job)
  
     'Wait for the job to complete (3 == starting, 4 == running)
    while (Job.JobState = 3) or (Job.JobState = 4)
       Wscript.Echo "Creating VHD. " & Job.PercentComplete & "% complete"
       WScript.Sleep(1000)
  
       'Refresh the job object
       set Job = WMIService.Get(OutParam.Job)
    Wend
  
    'Provide details if the job fails (7 == complete)
    if (Job.JobState <> 7) then
       Wscript.Echo "The virtual hard disk has not been created."
       Wscript.Echo "ErrorCode:" & Job.ErrorCode
       Wscript.Echo "ErrorDescription:" & Job.ErrorDescription
    else
       Wscript.Echo "The virtual hard disk has been created."
    end If
 end if
  

PowerShell:

 # Setup constant to use for getting the right value for the new VHD size
 [UInt64]$Size1G = 0x40000000
  
 # Prompt for the Hyper-V Server to use
 $HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
  
 # Get name for VHD
 $VHDName = Read-Host "Specify the name of the new dynamic virtual hard disk"
  
 # Get size for VHD
 [UInt64]$VHDSize = Read-Host "Specify the size of the new dynamic virtual hard disk (in GB)" 
  
 # Get the Msvm_ImageManagementService object
 $ImageManagementService = gwmi Msvm_ImageManagementService -namespace "root\virtualization" -computername $HyperVServer
  
 # Compact the VHD
 $result = $ImageManagementService.CreateDynamicVirtualHardDisk($VHDName, $VHDSize * $Size1G)
  
 #Return success if the return value is "0"
 if ($Result.ReturnValue -eq 0)
    {write-host "The virtual hard disk has been created."} 
  
 #If the return value is not "0" or "4096" then the operation failed
 ElseIf ($Result.ReturnValue -ne 4096)
    {write-host "The virtual hard disk has not been created.  Error value:" $Result.ReturnValue}
  
   Else
    {#Get the job object
     $job=[WMI]$Result.job
  
     #Provide updates if the jobstate is "3" (starting) or "4" (running)
     while ($job.JobState -eq 3 -or $job.JobState -eq 4)
       {write-host "Creating. "$job.PercentComplete "% complete"
        start-sleep 1
  
        #Refresh the job object
        $job=[WMI]$Result.job}
  
      #A jobstate of "7" means success
     if ($job.JobState -eq 7)
        {write-host "The virtual hard disk has been created."}
       Else
        {write-host "The virtual hard disk has not been created."
         write-host "ErrorCode:" $job.ErrorCode
         write-host "ErrorDescription" $job.ErrorDescription}
    }

Cheers,

Ben