Scripting VM Creation with Hyper-V

People have been bugging me for this for a while - so here we go.

Here are the VBScripts / PowerShell scripts to create a basic virtual machine:

VBScript:

 Option Explicit
  
 Dim HyperVServer
 Dim VMName
 Dim WMIService
 Dim VSManagementService
 Dim VSGlobalSettingData
 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 virtual machine on:")
  
 'Prompt for the new VM name
 VMName = InputBox("Specify the name for the new virtual machine:")
  
 'Get an instance of the WMI Service in the virtualization namespace.
 Set WMIService = GetObject("winmgmts:\\" & HyperVServer & "\root\virtualization")
  
 'Get the VirtualSystemManagementService object
 Set VSManagementService = WMIService.ExecQuery("SELECT * FROM Msvm_VirtualSystemManagementService").ItemIndex(0)
  
 ' Initialize a new global settings for the VM
 Set VSGlobalSettingData = WMIService.Get("Msvm_VirtualSystemGlobalSettingData").SpawnInstance_()
  
 'Set the VM name
 VSGlobalSettingData.ElementName = VMName
  
 'Setup the input parameter list
 Set InParam = VSManagementService.Methods_("DefineVirtualSystem").InParameters.SpawnInstance_()
 InParam.SystemSettingData = VSGlobalSettingData.GetText_(1) 
  
 'Execute the method and store the results in OutParam
 Set OutParam = VSManagementService.ExecMethod_("DefineVirtualSystem", InParam) 
  
 'Check to see if the job completed synchronously
 if (OutParam.ReturnValue = 0) then
    Wscript.Echo "Virtual machine created."
 elseif (OutParam.ReturnValue <> 4096) then
    Wscript.Echo "Failed to create virtual machine"
 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 Job.PercentComplete
       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 "Failed to create virtual machine"
       Wscript.Echo "ErrorCode:" & Job.ErrorCode
       Wscript.Echo "ErrorDescription:" & Job.ErrorDescription
    else
       Wscript.Echo "Virtual machine created."
    end If
 end if

PowerShell:

 # Prompt for the Hyper-V Server to use
 $HyperVServer = Read-Host "Specify the Hyper-V Server to create the virtual machine on"
  
 # Get name for new VM
 $VMName = Read-Host "Specify the name for the new virtual machine"
  
 # Create new MSVM_VirtualSystemGlobalSettingData object
 $wmiClassString = "\\" + $HyperVServer + "\root\virtualization:Msvm_VirtualSystemGlobalSettingData"
 $wmiClass = [WMIClass]$wmiClassString
 $newVSGlobalSettingData = $wmiClass.CreateInstance()
  
 # wait for the new object to be populated
 while ($newVSGlobalSettingData.psbase.Properties -eq $null) {}
  
 # Set the VM name
 $newVSGlobalSettingData.psbase.Properties.Item("ElementName").value = $VMName
  
 # Get the VirtualSystemManagementService object
 $VSManagementService = gwmi MSVM_VirtualSystemManagementService -namespace "root\virtualization" -computername $HyperVServer
  
 # Create the VM
 $result = $VSManagementService.DefineVirtualSystem($newVSGlobalSettingData.psbase.GetText(1))
  
 #Return success if the return value is "0"
 if ($Result.ReturnValue -eq 0)
    {write-host "Virtual machine created."} 
  
 #If the return value is not "0" or "4096" then the operation failed
 ElseIf ($Result.ReturnValue -ne 4096)
    {write-host "Failed to create virtual machine"}
  
   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 $job.PercentComplete
        start-sleep 1
  
        #Refresh the job object
        $job=[WMI]$Result.job}
  
      #A jobstate of "7" means success
     if ($job.JobState -eq 7)
        {write-host "Virtual machine created."}
       Else
        {write-host "Failed to create virtual machine"
         write-host "ErrorCode:" $job.ErrorCode
         write-host "ErrorDescription" $job.ErrorDescription}
    }

The basic concept here is that you need to create a new instance of Msvm_VirtualSystemGlobalSettingData and then pass it to the DefineVirtualSystem method on the MSVM_VirtualSystemManagementService object.

This will create a new blank virtual machine with no virtual hard disks, network adapters, etc... (I will dig into creating virtual machines with all these bits later).

Note that both of these scripts allow you to specify a remote Hyper-V server to create the virtual machine on.

Cheers,

Ben