General DVD script [Hyper-V]

After digging up and posting my script for connecting an ISO to a virtual machine last week – I decided to spend some time fleshing out that script into a more generic one that allows you to do anything “DVD related” that you could want to do with a virtual machine.  I ended up with a script that allows you to select a virtual machine and then choose to either:

  • View the current DVD configuration
  • Connect an ISO file
  • Connect a physical DVD
  • Eject the current media

Here is a screen shot of it running on my computer:

image

And here is the code for the script.

Note – this is a pretty huge script (so large as to break the color coding functionality of the code snippet plug-in that I use with Windows Live Writer) but I have attached a copy of the original to the end of this post.  I am not going to write much about the script itself – as it is heavily commented and you should be able to figure out what is going on inside it.

 # Function for handling WMI jobs / return values
 Function ProcessResult($result, $successString, $failureString)
 {
    #Return success if the return value is "0"
    if ($result.ReturnValue -eq 0)
       {write-host $successString} 
  
    #If the return value is not "0" or "4096" then the operation failed
    ElseIf ($result.ReturnValue -ne 4096)
       {write-host $failureString "  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 $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 $successString}
        Else
           {write-host $failureString
           write-host "ErrorCode:" $job.ErrorCode
           write-host "ErrorDescription" $job.ErrorDescription}
        }
 }
  
 # Function for ejecting the DVD
 Function EjectDVD()
 {
  
    # If there is media in the drive - eject it
    if ($existingRASD) {
       $result = $VMMS.RemoveVirtualSystemResources($VM, @($existingRASD))
       ProcessResult $result "The DVD drive has been ejected." "Failed to clear the DVD drive."}
 }
  
 # Function for connecting media to the DVD
 Function ConnectDVDMedia($media)
 {
 # Create a new object for a DVD media, connected to the DVD drive
 $DVDAllocationCapabilities = (gwmi -computername $HyperVServer -namespace root\virtualization Msvm_AllocationCapabilities `
                               -filter "ResourceType=21 and ResourceSubType='Microsoft Virtual CD/DVD Disk'").__Path.Replace('\', '\\')
 $DVDSettingsData = [wmi](gwmi -computername $HyperVServer -namespace root\virtualization Msvm_SettingsDefineCapabilities `
                          -filter "GroupComponent='$DVDAllocationCapabilities' and ValueRange=0").PartComponent
 $DVDSettingsData.Connection = $media
 $DVDSettingsData.Parent = $DVDDrive.__Path
  
 # Add the media to the virtual machine
 $result = $VMMS.AddVirtualSystemResources($VM, $DVDSettingsData.GetText(1))
  
 ProcessResult $result "The DVD media has been connected." "Failed to connect the DVD media."
 }
  
 # Prompt for the Hyper-V Server to use
 $HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
  
 # Prompt for the virtual machine to use
 $VMName = Read-Host "Specify the name of the virtual machine"
  
 # Get the management service
 $VMMS = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService -computername $HyperVServer
  
 # Get the virtual machine object
 $VM = gwmi MSVM_ComputerSystem -filter "ElementName='$VMName'" -namespace "root\virtualization" -computername $HyperVServer
  
 # SettingType = 3 ensures that we do not get snapshots
 $SystemSettingData = $VM.getRelated("Msvm_VirtualSystemSettingData") | where {$_.SettingType -eq 3}
  
 # Get the first DVD drive in the system
 $DVDDrive = $SystemSettingData.getRelated("Msvm_ResourceAllocationSettingData") | where{$_.ResourceType -eq 16} | select -first 1
  
 # Make sure the DVD actually exists
 if ($DVDDrive -eq $null) 
    {write-host "No DVD drive exists on that virtual machine"
     exit}
  
 # Setup parameters for main menu prompt
 $message = "What do you want to do with the DVD drive?"
 $info = New-Object System.Management.Automation.Host.ChoiceDescription "&Display Information", "Display information about the current contents of the DVD drive."
 $eject = New-Object System.Management.Automation.Host.ChoiceDescription "&Eject", "Eject the current contents of the DVD drive."
 $iso = New-Object System.Management.Automation.Host.ChoiceDescription "Connect &ISO", "Connect an ISO file to the DVD drive."
 $physical = New-Object System.Management.Automation.Host.ChoiceDescription "Connect &Physical Disc", "Connect a physical disc to the DVD drive."
 $quit = New-Object System.Management.Automation.Host.ChoiceDescription "&Quit", "Exit the DVD Tools script."
 $options = [System.Management.Automation.Host.ChoiceDescription[]]($info, $eject, $iso, $physical, $quit)
  
 do 
    {
    
    # Check to see if there is already media in the DVD drive
    $existingRASD = $SystemSettingData.getRelated("Msvm_ResourceAllocationSettingData") | where {$_.Parent -eq $DVDDrive.__Path}
  
    # Ask the user what they want to do with the DVD drive
    write-host
    $promptResult = $host.ui.PromptForChoice("", $message, $options, 0)
    write-host 
  
    switch ($promptResult)
       {
          0  {# Display information
         
              # If there is media in the drive - display key information
              if ($existingRASD) {
                 write-host "Media type: " $existingRASD.ElementName
                
                 # Check to see if this is an ISO or a physical disk
                 if ($existingRASD.caption -eq "ISO Disk Image") {write-host "Media     : " $existingRASD.Connection}
                
                 # Do some wrangling to get the drive letter for the physical disk case
                 else {$DiskObject = gwmi Win32_CdromDrive -computername $HyperVServer | where {$_.DeviceID -eq $existingRASD.Connection}
                       write-host "Media     : " $DiskObject.Drive}
                 }
              else {
                 write-host "No DVD disk is configured."
                 }
              }
      
          1 {# Eject the DVD
             EjectDVD
             }
            
          2 {# Connect an ISO file
            
             # Prompt for the ISO file to connect
             $isoPath = Read-Host "Specify the ISO file to connect to the virtual machine"
             EjectDVD
             ConnectDVDMedia @($isoPath)
             }
            
          3 {# Connect a physical disk
            
             # Prompt for the physical disk to connect
             $DiskPath = Read-Host "Specify the Disk file to connect to the virtual machine"
             $DiskObject = gwmi Win32_CdromDrive -computername $HyperVServer | where {$_.Drive -eq $DiskPath}
            
             if ($DiskObject) 
                {EjectDVD
                 ConnectDVDMedia $DiskObject.DeviceID}
             else {Write-Host "Invalid CD / DVD drive letter specified"}
             }
        }
    }
    
 until ($promptResult -eq 4)

Cheers,
Ben

DVDTools.zip