Find out how much space is used / can be used by a virtual machines virtual hard disks [script]

After writing the script to find all virtual hard disks associated with a virtual machine – the next logical step was to answer some questions about these virtual hard disks.  The two obvious questions that I could think of were:

  • How much space is this virtual machine currently using?
  • How much space can this virtual machine use if it “goes crazy” and starts trying to write out as much data as possible?

So I modified yesterdays script to answer these questions:

 # 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 Storage management service
 $ImgService = gwmi Msvm_ImageManagementService -namespace "root\virtualization" -computername $HyperVServer -locale MS_409
  
 # Get the virtual machine object
 $VM = gwmi MSVM_ComputerSystem -namespace "root\virtualization" -computername $HyperVServer -locale MS_409 | where {$_.ElementName -eq $VMName}
  
 # Create an empty hashtable
 $table = @{}
  
 # Set size variables
 $totalSize = 0
  
 # Go over each of the virtual machines "system setting data" objects.  There will be a system setting data
 # for each snapshot associated with the virtual machine, and one for the active virtual machine.
 foreach ($VSSD in @($VM.getRelated("Msvm_VirtualSystemSettingData"))) 
   {
    # Get all the VHDs associated with the current system setting data
    $VHDs = [array]($VSSD.getRelated("Msvm_ResourceAllocationSettingData") | where {$_.ResourceType -eq 21} | where {$_.ResourceSubType -eq "Microsoft Virtual Hard Disk"})
  
    # Only continue if the system setting data actually had virtual hard disks
    if ($VHDs)
       {
       # Intialize index, and get the VHD and VHDPath for the first virtual hard disk      
       $index = 0
       $VHD = $VHDs[$index]
       $VHDPath = $VHD.Connection | select -first 1
  
       # loop through all virtual hard disks
       do      
          {
          # Get the detailed information for the current virtual hard disk
          $xml = [xml]($ImgService.GetVirtualHardDiskInfo($VHDPath)).info
       
          # Only continue if the current virtual hard disk is not in the hashtable
          if (!$table.ContainsKey($VHDPath)) 
             {
             # Store the file size for the virtual hard disk in the table - and add it to $totalSize
             $table[$VHDPath] = [uint64]($xml.Instance.Property | ?{$_.Name -eq "fileSize"}).value
             $totalSize = $totalSize + [uint64]($xml.Instance.Property | ?{$_.Name -eq "fileSize"}).value
             
             # Check to see if the current virtual hard disk has a parent virtual hard disk
             if (($xml.Instance.Property | ?{$_.Name -eq "ParentPath"}).value)
                {
                # if it does - make the parent the next virtual hard disk that we look at
                $VHDPath = ($xml.Instance.Property | ?{$_.Name -eq "ParentPath"}).value
                }
             # If the current virtual hard disk does not have a parent - just move onto the next virtual
             # hard disk in the system settings data object
             else
                {
                # Increase the index - and make sure that we have not gone past the last virtual hard disk
                $index = $index + 1
                if ($index -ne $VHDs.count)
                   {
                   # Setup new values for next time through
                   $VHD = $VHDs[$index]
                   $VHDPath = $VHD.Connection | select -first 1}
                   }
          
                }
  
          # If the current virtual hard disk is already in the hashtable - move onto the next virtual
          # hard disk in the system settings data object         
          else
             {
             # Increase the index - and make sure that we have not gone past the last virtual hard disk
             $index = $index + 1
             if ($index -ne $VHDs.count)
                {
                # Setup new values for next time through
                $VHD = $VHDs[$index]
                $VHDPath = $VHD.Connection | select -first 1
                }
             }
          }
       
       # loop until we have covered all virtual hard disks
       until ($index -eq $VHDs.count)
       }
    }
  
 # Get the VSSD and VHD array for the currently active virtual machine
 $activeVSSD = $VM.getRelated("Msvm_VirtualSystemSettingData") | ?{$_.SettingType -eq 3}
 $activeVHDs = [array]($activeVSSD.getRelated("Msvm_ResourceAllocationSettingData") | where {$_.ResourceType -eq 21} | where {$_.ResourceSubType -eq "Microsoft Virtual Hard Disk"})
  
 # Setup some blank varibles
 $activeVMSize = 0
 $activeVMCapacity = 0
  
 # Calculate the total file size and internal capacity only for the active virtual machine
 foreach ($VHD in $activeVHDs) 
   {
   $VHDPath = $VHD.Connection | select -first 1
   $xml = [xml]($ImgService.GetVirtualHardDiskInfo($VHDPath)).info
   $activeVMSize = $activeVMSize + [uint64]($xml.Instance.Property | ?{$_.Name -eq "fileSize"}).value
   $activeVMCapacity = $activeVMCapacity + [uint64]($xml.Instance.Property | ?{$_.Name -eq "MaxInternalSize"}).value
   }
  
 # Do some math and formatting to get from bytes to gigagytes
 $totalPossibleSize = "{0:N2}" -f (($totalSize - $activeVMSize + $activeVMCapacity) / 1073741824)
 $totalSize = "{0:N2}" -f ($totalSize / 1073741824)
  
 # Display the results
 write-host "Total disk space used by the virtual machine:" $totalSize "GB"
 write-host "Most disk space that can be used by the virtual machine:" $totalPossibleSize "GB"

This script starts by just adding up the file size of all virtual hard disks associated with the virtual machine (this is the value that is stored in $totalSize).  Then it takes this “total size” and removes the file size of the currently active disks – and replaces that with the maximum possible size of the currently active disks.  This second value (stored in $totalPossibleSize) represents the largest amount of disk space that the virtual machine could use – in its current configuration.

Cheers,

Ben

FindVHDSize.zip