Powershell / Powercli script to report on VMs and their VMDKs

Here is a report I put together to quickly view all VMs their VMDKs and the Datastores those VMDKs are sitting on. This is not meant to be a report to view total storage or free space on either the VMs or their Datastores, nor are we looking for orphaned vmdk files. Although I may add those features to this report later on.

Update 3/13/2014: Script now reports on Size and how the data is presented has been improved.

Issue: Review VMDK files for any that don’t have the same name as the VM names in VCenter.

Purpose: Scan and report on VMware VM’s VMDKs and what Datastores they are tied to.

Side Notes:

  • You must have Powercli installed on the machine this report runs off of.
  • The admin account used must have enough permissions to run the given commands.
  • It is possible to have two VMs in vCenter with the same name. So in the report you may see a single server when in fact it is two separate servers.
  • If that happens you’ll see a single instance of that VM’s name with more than the expected number of disk.
#=====================================================================================================#
# Author: Robert Stacks
# Date: 7/18/2012
# Updated: 3/13/2012
# Verson: 1.1
#
# Purpose: 
# Scan and report on Datastores, and related VM's VMDK visible to vCenter
# 
# Updates:
# 3/12/2012
# - Added a column to show the current host ESXi server, Split Folder from VMDK info, and also added size
# - Fixed some spelling and updated comments
# - Fixed some flow logic and adjusted table row color, table padding, and sizing.
#=====================================================================================================#

#Add Snapins
Add-PSSnapin VMware.VimAutomation.Core

#===========================#
#User Adjustable Variables  #
#===========================#

#Vcenter Logon Info
$ESXserver = "vcenterserver.domain.com"
$ESXuser = "username"
$ESXpassword = "password"

#Mail Server Variables
$SMTPserver = "mail.domain.com"
$from = "VMwareReporter@domain.com"
$to = "sysadmins@domain.com"

#===========================#
#Main Script                #
#===========================#

#Determine if already connected to VCenter and if not connect
if ( $DefaultVIServers.Length -lt 1 )
{
  Connect-VIServer -Server $ESXserver -User $ESXuser -Password $ESXpassword -WarningAction SilentlyContinue | Out-Null
}

# Format html report
$htmlReport = @"
<style type='text/css'>
.heading {
 	color:#0B1ABF;
	font-size:14.0pt;
	font-weight:700;
	font-family:Verdana, sans-serif;
	text-align:left;
	vertical-align:middle;
	height:20.0pt;
	width:416pt;
}
.colnames {
 	color:white;
	font-size:11.0pt;
	font-weight:700;
	font-family:Tahoma, sans-serif;
	text-align:center;
	vertical-align:middle;
	border:.5pt solid windowtext;
	background:#730000;
}
.lblueback {
	color:windowtext;
	font-size:10.0pt;
	font-family:Arial;
	text-align:left;
	vertical-align:middle;
	border:.5pt solid windowtext;
	background:#B8CCE4;
}
.greyback {
	color:windowtext;
	font-size:10.0pt;
	font-family:Arial;
	text-align:left;
	vertical-align:middle;
	border:.5pt solid windowtext;
    #background:#D8D8D8;
}

</style>
<table style='border-collapse:collapse;table-layout:auto;width:auto;padding:5px'>
 <tr style='height:15.0pt'>
   <th colspan=6 height=40 width=auto class="heading">
	<center> VM Datastore Report </center></th>
 </tr>
 <tr>
  <th class="colnames">VM Name</th>
  <th class="colnames">Host</th>
  <th class="colnames">DataStore</th>
  <th class="colnames">Folder</th>
  <th class="colnames">FileName</th>
  <th class="colnames">Size/GB</th>
 </tr>
"@

#get a list of VMs
$vmlist = Get-VM -Server $ESXserver | Sort

#counter to manage alternating row color
$colorcounter = 0

#Master part of the script, loops through each VM and creates table with data
ForEach ($vm in $vmlist)
{	
  #If loop to determine color of Rows related to given VM
  if ($colorcounter%2 -eq 0)
	{
		$tablecell = @"
		<td class='lblueback'>
"@
}
  else 
	{ 
		$tablecell = @"
		<td class='greyback'>
"@
}
  
  # Grab VMDK information and the Datastores tied to them.
  $vmdisk = Get-VM $vm | Get-harddisk
  
  # Split out disks where a VM has more than a single disk, also split out the name of the Datastore
  # from the name/path of the vmdk file, then split the Folder Name from the VMDK name.
  $vmdiskDatastore=($vmdisk | %{$_.Filename.Split('[]')[1]})
  $vmdiskfilename=($vmdisk | %{$_.Filename.Split('[]')[2]})
  $vmdiskFolder=($vmdiskfilename | %{$_.Split('/')[0]})
  $vmdiskVMDK=($vmdiskfilename | %{$_.Split('/')[1]})
  $vmdisksize=($vmdisk | %{$_.CapacityKB})
  
  # determine the length of the array so we know if there was more than one hard drive for a given VM.
  $count = $vmdiskfilename.count - 1
  
  # Begin building the html report, inserting the name of the VM in the 1st Column and Host Name into the 2nd 
  $htmlReport = $htmlReport + 
  "<tr>" + $tablecell + $vm.Name + "</td>" +
  $tablecell + $vm.host.Name + "</td>"
  
  # Based on the number of hard drives in the count value the report is generated in one of two ways
  if($count -le 0)
  {
  	# There is only one hard drive so the values will not be in an array we just need to build the table row with data
  	$htmlReport = $htmlReport + 
	$tablecell + $vmdiskDatastore + "</td>" + 
    $tablecell + $vmdiskFolder + "</td>" +
	$tablecell + $vmdiskVMDK + "</td>" +
	$tablecell + $vmdisksize / 1MB + "</tr>"
  }
  else
  {
  	# There is more than one hard drive, because of table formatting we handle the 1st row different from the 2nd row.  Data is in an array.
  	$htmlReport = $htmlReport +
    $tablecell + $vmdiskDatastore[0] + "</td>" + 
    $tablecell + $vmdiskFolder[0] + "</td>" +
	$tablecell + $vmdiskVMDK[0] + "</td>" +
	$tablecell + $vmdisksize[0] / 1MB + "</tr>"
  
  # There is more than one hard drive so we will loop through the array and and place them in the report
 	$x=1
    While($x -le $count)
	{
    	$htmlReport = $htmlReport +
     	"<tr>" + $tablecell + "" + "</td>" + 
		$tablecell + "" + "</td>" +
    	$tablecell + $vmdiskDatastore[$x] + "</td>" + 
    	$tablecell + $vmdiskFolder[$x] + "</td>" +
		$tablecell + $vmdiskVMDK[$x] + "</td>" +
		$tablecell + $vmdisksize[$x] / 1MB + "</tr>"
		$x= $x+1
  	}
   }
   # value used in conjunction with Foreach and if loop to rotate color in table
   $colorcounter = $colorcounter + 1
 }
 
 # We are done gathering data from vCenter so we disconnect
 Disconnect-VIServer -Server $ESXserver -Force:$true -Confirm:$false

# Send email
$subject = "VMware VM Datastore Report"
$emailbody = $htmlReport
$mailer = New-Object Net.Mail.SMTPclient($SMTPserver)
$msg = New-Object Net.Mail.MailMessage($from, $to, $subject, $emailbody)
$msg.IsBodyHTML = $true
$mailer.send($msg)

Example of output:
datastorereportexample

Advertisements
  1. #1 by Adrian on May 23, 2013 - 12:12 am

    This is awesome, I would love it if you could assist to add the vmdk actual and provisioned sizes to this report!

    • #2 by Robert on March 13, 2014 - 1:49 pm

      Size is now included in the report, feel free to give it a go.

  2. #3 by Adrian on June 6, 2013 - 12:21 am

    hi, found some errors in your code, you need to modify the following lines to include the sizes in the html report.

    Split out disks where a VM has more than a single disk, also split out the name of the Datastore
    # from the name/path of the vmdk file.
    $vmdiskDatastore=($vmdisk | %{$_.Filename.Split(‘[]’)[1]})
    $vmdiskfilename=($vmdisk | %{$_.Filename.Split(‘[]’)[2]})
    $vmdisksize=($vmdisk | %{$_.CapacityGB})

    # determine the length of the array so we know if there was more than one hard drive for a given VM.
    $count = $vmdiskfilename.count – 1

    # Begin building the html report, inserting the name of the VM reporting on
    $htmlReport = $htmlReport +
    “” + $tablecell + $vm.Name + “”

    # Based on the number of hard drives in the count value the report is generated in one of two ways for the 1st item.
    if($count -le 0){
    # There is only one hard drive so we just split the Datastore Name from the vmdk file path/name and place it in the report.
    $htmlReport = $htmlReport +
    $tablecell + $vmdisk.Filename.Split(‘]’)[0].trim(‘[‘) + “” +
    $tablecell + $vmdisk.Filename.Split(‘]’)[1].trim(”) + “” +
    $tablecell + $vmdisksize + “”
    }
    else{
    # THere is more than one hard drive, because of table formating we handle the 1st row different from the 2nd row.
    $htmlReport = $htmlReport +
    $tablecell + $vmdiskDatastore[0] + “” +
    $tablecell + $vmdiskfilename[0] + “” +
    $tablecell + $vmdisksize[0] + “”
    }
    # There is more than one hard drive so we will loop through the array and and place them in the report
    $x=1
    While($x -le $count){
    $htmlReport = $htmlReport +
    “” + $tablecell + “” + “” +
    $tablecell + $vmdiskDatastore[$x] + “” +
    $tablecell + $vmdiskfilename[$x] + “” +
    $tablecell + $vmdisksize[$x] + “”
    $x= $x+1

    • #4 by Robert on July 9, 2013 - 10:38 am

      Don’t think its an error as that was not something I intended to included in the original script but nice addition there.

  3. #5 by bking789 on March 10, 2014 - 1:34 pm

    This is a great Script, but is there a way to add an additional column of the actual ESX Host that the virtual machine is on?

    • #6 by Robert on March 12, 2014 - 4:07 pm

      Sure that feature could be added pretty easily, just have to add a column with the variable $vm.host.Name. I can add that to the script easy enough. I’ll see about posting a update.

    • #7 by Robert on March 13, 2014 - 1:49 pm

      Script has been updated. Give it a go.

  4. #8 by Ali Sarreshteh on March 25, 2014 - 10:57 am

    How do you save the $htmlReport?
    We are not going to use email function and just want to save the HTML report.

  5. #9 by Ali Sarreshteh on March 25, 2014 - 11:27 am

    Would the following suffice at the end of the script?
    write-output $htmlReport > D:\MyReport.html

    • #10 by Robert on March 27, 2014 - 11:09 am

      $htmlReport > D:\MyReport.html should work. You don’t need the write-output part.

  6. #11 by paul on September 16, 2014 - 9:22 am

    Im very new to PS code and its hard for my brain to get it to work, took me a while to get this to work, but it does now. I would like to also include columns for the ProvisionedSpaceGB, UsedSpaceGB, NumCPU, as well as MemoryMB.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: