PowerCLI script to report Guest OS disk usage


[Update, December 2nd, 2014]

You might be also interested in an revised version of this script, that I posted here


Anybody can have a bad day, some people claim it is best to clean one’s desk on a day like that, but I personally prefer to chase customers of my virtual infrastructure for resources they are ab-using.

On many occasions projects request a lot of disk space for their virtual machines and then under-utilize these disks which is just “not cool”, especially if they require thick provisioned vmdks (which I always prefer for servers).

Even if you don’t want to chase anybody for hoarding disk space it is always good to know how much of these hundreds of GBs you provisioned is actually used by Guest OS and applications running inside the virtual machine – this gives you information on how much of disk space can be potentially reclaimed if you really need to clean-up your datastore.
Gathering such information is really easy if you have vCOPS deployed, but for smaller environments you need to do it yourself and this is where the script I’m about to share comes handy.

   Script generates .csv file containing information about diskspace usage as seen from guest OS
   Script connects to vCenter server passed as parameter and enumerates virtual machines from datastore also passed as parameter.
   VM Templates and vms without Vmware Tools running are excluded cause it is impossible to retrieve disk usage from them.
   For remaining vms disk capacity, free space and percent of free space are retrieved and saved to .csv file, one vm per line.
.PARAMETER vCenterServer
   Mandatory parameter indicating vCenter server to connect to (FQDN or IP address)
.PARAMETER DatastoreName
   Mandatory parameter indicating datastore to generate report for
   check-guestdiskspace.ps1 -vCenterServer vcenter.seba.local -DatastoreName Production-Datastore
   check-guestdiskspace.ps1 -vcenter -datastore development-datastore


$ScriptRoot = Split-Path $MyInvocation.MyCommand.Path
$csvfile = "$ScriptRoot\guest_diskspace_report_for_$($DatastoreName)_cluster.csv"
#array of objects containing disk information per vm
$all_guestOSdisks_info [email protected]()

$vmsnapin = Get-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue
if ($vmsnapin -eq $null) 	
	Add-PSSnapin VMware.VimAutomation.Core
	if ($error.Count -eq 0)
		write-host "PowerCLI VimAutomation.Core Snap-in was successfully enabled." -ForegroundColor Green
		write-host "ERROR: Could not enable PowerCLI VimAutomation.Core Snap-in, exiting script" -ForegroundColor Red
	Write-Host "PowerCLI VimAutomation.Core Snap-in is already enabled" -ForegroundColor Green

#connect vCenter from parameter
Connect-VIServer -Server $vCenterServer -ErrorAction SilentlyContinue | Out-Null

#execute only if connection successful
if ($error.Count -eq 0){
	write-host "Processing disk information for vms in datastore $DatastoreName" -ForegroundColor Yellow
	#get vm objects from datastore passed as parameter, exclude templates and machines where Vmware Tools are not running
	$vms_in_datastore = get-datastore -name $DatastoreName | get-vm | where-object { (-not $_.Config.Template) -and ($_.ExtensionData.Guest.ToolsRunningStatus -match ‘guestToolsRunning’) }

	#we need to sort vms so that vm with most number of disks is first, this is because information about disks will be displayed as columns 
	#and export-csv cmdlet formats the csv with the number of columns of the first object in the pipeline (if subsequent objects have more columns they are truncated (sic!))
	$vms_in_datastore_sorted = $vms_in_datastore | Select *, @{N="NumDisks";E={@($_.Guest.Disks.Length)}} | Sort-Object -Descending NumDisks

	foreach ($vm in $vms_in_datastore_sorted){
		#enumerate vms, create a PS Object with list of disk details for each vm	
		$single_guestOSdisk_info = New-Object PSObject
		$single_guestOSdisk_info | Add-Member -Name VmName -Value $vm.name -MemberType NoteProperty
		$index = 0
		$guest_disks = $vm.guest.disks | Sort-Object -Property path
		foreach ($disk in $guest_disks){
			$single_guestOSdisk_info | Add-Member -Name "Disk$($index) path" -MemberType NoteProperty -Value $disk.Path
			$single_guestOSdisk_info | Add-Member -Name "Disk$($index) Capacity(MB)" -MemberType NoteProperty -Value ([math]::Round($disk.Capacity/ 1MB))
			$single_guestOSdisk_info | Add-Member -Name "Disk$($index) FreeSpace(MB)" -MemberType NoteProperty -Value ([math]::Round($disk.FreeSpace / 1MB))
			$single_guestOSdisk_info | Add-Member -Name "Disk$($index) FreeSpace(%)" -MemberType NoteProperty -Value ([math]::Round(((100* ($disk.FreeSpace))/ ($disk.Capacity)),0))
		#add object with disk information to general collection
		$all_guestOSdisks_info += $single_guestOSdisk_info

	#export to CSV
	$all_guestOSdisks_info | Export-Csv -Path $csvfile -NoTypeInformation

	Write-Host "Report successfully created in $($csvfile)" -ForegroundColor Green

	#disconnect vCenter
	Disconnect-VIServer -Confirm:$false
Write-Host "Error connecting vCenter server $vCenterServer, exiting" -ForegroundColor Red

As with all my scripts –  not really rocket science in here, methodology I use was inspired by Alan Renouf’s post from a few years ago already.

The script requires two parameters, namely vCenter Server name and datastore name (I presume you would like to have such report per datastore) and they are mandatory, so if you forget them while invoking the script you will be asked to provide them before execution starts.

For each vm from datastore we are checking a PowerShell Object is created containing vm name and fields with information about disks which are (in following order): “disk path” (so drive letter in Windows or mount point in Linux), total disk capacity in megabytes, free space in MB and finally we calculate percentage of free space. Every object describing disk configuration of single vm is stored to array and at the end of the script this array is saved to .csv report under file name which (just for convenience) contains name of the datastore. The report is formatted in a way that there is only one line for each vm and columns contain information about each disk.

See example:

"VmName","Disk0 path","Disk0 Capacity(MB)","Disk0 FreeSpace(MB)","Disk0 FreeSpace(%)","Disk1 path","Disk1 Capacity(MB)","Disk1 FreeSpace(MB)","Disk1 FreeSpace(%)","Disk2 path","Disk2 Capacity(MB)","Disk2 FreeSpace(MB)","Disk2 FreeSpace(%)","Disk3 path","Disk3 Capacity(MB)","Disk3 FreeSpace(MB)","Disk3 FreeSpace(%)","Disk4 path","Disk4 Capacity(MB)","Disk4 FreeSpace(MB)","Disk4 FreeSpace(%)","Disk5 path","Disk5 Capacity(MB)","Disk5 FreeSpace(MB)","Disk5 FreeSpace(%)","Disk6 path","Disk6 Capacity(MB)","Disk6 FreeSpace(MB)","Disk6 FreeSpace(%)","Disk7 path","Disk7 Capacity(MB)","Disk7 FreeSpace(MB)","Disk7 FreeSpace(%)","Disk8 path","Disk8 Capacity(MB)","Disk8 FreeSpace(MB)","Disk8 FreeSpace(%)","Disk9 path","Disk9 Capacity(MB)","Disk9 FreeSpace(MB)","Disk9 FreeSpace(%)","Disk10 path","Disk10 Capacity(MB)","Disk10 FreeSpace(MB)","Disk10 FreeSpace(%)","Disk11 path","Disk11 Capacity(MB)","Disk11 FreeSpace(MB)","Disk11 FreeSpace(%)","Disk12 path","Disk12 Capacity(MB)","Disk12 FreeSpace(MB)","Disk12 FreeSpace(%)","Disk13 path","Disk13 Capacity(MB)","Disk13 FreeSpace(MB)","Disk13 FreeSpace(%)","Disk14 path","Disk14 Capacity(MB)","Disk14 FreeSpace(MB)","Disk14 FreeSpace(%)","Disk15 path","Disk15 Capacity(MB)","Disk15 FreeSpace(MB)","Disk15 FreeSpace(%)","Disk16 path","Disk16 Capacity(MB)","Disk16 FreeSpace(MB)","Disk16 FreeSpace(%)"


The tricky part is that every vm can have different number of disks attached (so number of “disk information” properties can be different per every object we create) whereas Export-CSV cmdlet formats the output based on the first object that is passed to it and resulting .csv file has only as many columns as there were properties defined in the first object.

Translating above to English – if we sorted our vm list alphabetically and the first vm had only single disk – output .csv would have only the number of columns to contain information about this single disk (5 columns in our case) and following vms would inherit this number of columns (so if 2nd vm had 3 disks – only information about 1st disk would be in .csv file, the rest would be just truncated).

To circumvent this issue we sort the collection of vms in descending order so that vm with the largest number of disk is listed first (this is done before script even checks the disks).
The original report looks a bit odd because of that, but you can easily process it further with MS Excel or any other editing tool.

Of course the only way to retrieve information about Guest OS is via VMware Tools, that’s why the script checks if tools are running for each vm (machines without running VMware Tools will not be present in the report!).

This is one of my older scripts and it worked pretty fine for me so far, in fact the only issues I had were with virtualized Solaris x86 servers with Vmware Tools running but in status of being “unsupported” (for whatever reason, I’m not really a Solaris expert, probably some very old VMware Tools were used with these vms).

I hope you find this script useful, feel free to give your opinion on it!

0 0 votes
Article Rating

Sebastian Baryło

Successfully jumping to conclusions since 2001.

Notify of
Newest Most Voted
Inline Feedbacks
View all comments

3. Report Guest-OS Disk Usage

[…] script to report Guest disk usage of virtual machines This PowerCLI script could be quite useful if you want to know much over-provisioned your virtual machines disks […]

[…] to 5, because I wanted to avoid difficulties of exporting variable length strings to .csv that I had to deal with some time ago. Most of the time I see only two NTP servers configured – which is perfectly fine, the […]

Matt Topolinski

How can I weed out reporting on drives other than c: ?



Nice Script but could you please check powershell script on VMware Code: https://code.vmware.com/samples?id=5120

Would love your thoughts, please comment.x

FOR FREE. Download Nutanix port diagrams

Join our mailing list to receive an email with instructions on how to download 19 port diagrams in MS Visio format.

NOTE: if you do not get an email within 1h, check your SPAM filters

You have Successfully Subscribed!

Don't miss any posts. Subscribe To Our Newsletter!!

Join our mailing list to receive the latest news and updates from www.vmwaremine.com.

You have Successfully Subscribed!

Pin It on Pinterest