Inventorying Virtual Hard Disk Files on a Server or Domain

Use these scripts to list the VHD or VMDK files on any system

Chris: I'm starting to get worried about VM sprawl. Many of the users on my network are using Virtual PC and Virtual Server 2005 R2, and I want to be able to find VHD files on my servers or on any user's system. Can I do this with a tool or script?

Jason, while many enterprise storage resource management (SRM) tools can audit files by extension, this can also be done using a vbscript. For example, the script below will show you all Virtual PC or Virtual Server (VHD) and VMware (VMDK) virtual hard disk files. Also, the script will display any files greater than 800MB (838,860,800 bytes), which is useful for the crafty user that decides to create virtual disk files using a custom file extension.

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\cimv2")

Set colFiles = objWMIService. _
    ExecQuery("Select * from CIM_DataFile " & _
    "where Extension = 'vhd' or Extension =" & _
    " 'vmdk' or FileSize > 838860800")

For Each objFile in colFiles
    Wscript.Echo objFile.Name & " -- " & _
    objFile.FileSize & " bytes"

Note that if you wanted to list all files greater than 100MB in size, for example, you would change "838860800" in the "Set colFiles" statement to "104857600." There are plenty of online calculators that can convert megabytes to bytes, so if you're looking to audit a particular file size, you can use this Conversion Calculator, for example.

I have saved a copy of vhdaudit.vbs on my Web site and you can download it here. Note that it is saved as a text file, so you will need to change its extension to .vbs in order to run it. Also, since the script uses wscript.echo to list the virtual hard disk files that are found, you should run it using the cscripting host. To do this, you would run the command cscript vhdaudit.vbs from the directory containing the vhdaudit.vbs file.

If you would like to find virtual hard disk files on every computer in your domain, you can run the DomainVHDaudit.vbs script shown below.

On Error Resume Next
Const ForWriting = 2
' Format date/time stamp for output file
strTimeDate = Year(Date) & "-" & Month(Date) & _
 "-" & Day(Date) & "~~" & Hour(Time) & "-" & _
' Output file name and path
strLogFile = "C:\VHDaudit-" & strTimeDate & _

wscript.echo("Audit started. This may take " & _
 "several minutes to hours to complete. You " & _
 "will receive a message once the script is finished.")

'Create Log File
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile (strLogFile, _
    ForWriting, True)
' Connect to domain and collect computer accounts
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
set objRootDSE = GetObject("LDAP://RootDSE")
objCommand.CommandText = _
 "SELECT Name, Location FROM 'LDAP://" & _
 objRootDSE.Get("defaultNamingContext") & "'" _
 & "WHERE objectClass='computer'"
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Timeout") = 30
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.Properties("Cache Results") = False
Set objRecordSet = objCommand.Execute

' Output domain computer accounts, connect to each
' computer, and enumerate virtual disk files or
' files larger than 800 MB
Do Until objRecordSet.EOF
 strComputer = objRecordSet.Fields("Name").Value
 objFile.WriteLine "System: " & strComputer
 Set objWMIsvc = GetObject("winmgmts:" &_
   "{impersonationlevel=impersonate}!\\" & _
   strComputer & "\root\cimv2")
 'Check for connection error. If systems are
 'unreachable, ensure that a software firewall
 'is not blocking WMI connections.
 If Err = 462 Then
   objFile.Writeline("*** System Unreachable ***")
  'Enumerate VHDs and VMDKs
   set colFiles = objWMIsvc.ExecQuery _
    ("Select * from CIM_DataFile where Extension =" & _
    " 'vhd' or Extension = 'vmdk' or FileSize " & _
    "> 838860800")
  ' Note: 838860800 is the byte value of 800 MB
  'List VHDs on host
   For Each objVHD In colFiles
     objFile.WriteLine(objVHD.Name & " -- " & _
      objVHD.FileSize & " bytes")
 End If
' All done!
WScript.Echo("Audit Complete!")

Note that the file audit may take up to several minutes to complete per computer. So running this script in a domain with hundreds to thousands of computers can conceivably take hours. The script will write its output to a text file on the C drive on the computer in which it is run. Note that the script uses the naming convention "VHDaudit-year-month-day~~time.txt" for its output file. The script works by querying Active Directory to collect all computer and domain controller objects. It will then connect to each object and look for VHD, VMDK or files larger than the size specified in the "FileSize" parameter. The complete audit will be written to a single text file and computers that cannot be contacted will be noted in the text file with a "*** System Unreachable ***" message. Computers that cannot be reached are likely those that are not connected to the LAN or have their software firewall set to refuse WMI queries.

Hopefully, one of these two scripts will help solve your problem. The vhdaudit.vbs script is ideal for performing local audits on each of your file servers. To audit your entire domain, domainvhdaudit.vbs should "git 'r done."

About the Author

Chris Wolf is VMware's CTO, Global Field and Industry.


Subscribe on YouTube