Home Datacenter Reclaim dirty free space in Windows VMs by comparing Windows to vSphere reported free space

Reclaim dirty free space in Windows VMs by comparing Windows to vSphere reported free space

by Philip Sellers

Windows is dirty.  It has always been dirty.  It is an OS that doesn’t do a good job of cleaning up after itself.  And so, you may have a lot of unused, dirty space consumed in your environment that can be cleaned up.  When files are deleted, the OS leaves behind the actual data on its disk.  It does not take the time to zero out the space and that’s where the opportunity comes in.  PowerShell to the rescue.

vSphere has the ability to thin provision, but it doesn’t have the native ability to reclaim free space in a guest operating system.  To be able to reclaim your dirty free space, the first thing you’ll need is storage that can detect zeros and perform an unmap at the array level.

When vSphere introduced vSphere API’s for Array Integration (VAAI), it touted the unmap capability, but the backend arrays were not all able to keep up with the unmap commands happening in real time.  Instead, VMware turned off unmap for several versions of vSphere.  In vSphere 6.5, you have a simple on/off switch for the feature in vCenter.

But turning on the unmap feature does not solve the whole problem.  Inside of the guest OS, you also need to zero out the prior used space.  If you do not do this, the OS and hypervisor both see the space is used still.

PowerShell to the Rescue

So, the script below helps with this process.  It uses a PowerShell routine called Write-ZeroToFreeSpace from Chris Duck that you will need to download separately.

Then the routine below gets a list of all the VMs in vCenter and compares them to the free space reported by the Windows guest OS looking for large differences to help target which VMs to write zeros to in their free space.

Let me be the first to say that this is far from prefect – so please correct and expand on the code as you see fit.


# Detect and thin out Windows disks
# Requires script to run as a privileged Windows account - like Domain Administrator
# Requires the Write-ZeroToFreeSpace script at http://blog.whatsupduck.net/2012/03/powershell-alternative-to-sdelete.html
# Wrap the Write-ZeroToFreeSpace script as a function - eg. Function Write-ZeroToFreeSpace { --content from website-- } 
# vCenter credentials can be separate if the same account does not have access to vCenter - you will be prompted for credentials for vCenter in that case

# --- VARIABLES ---
# Set the size in GB for threshold to be performed, 100GB default below
$ReclaimThreshold = 100
# Set the vCenter Server Name or IP address
$vCenterServer = "vcenter.local.domain"
# Connect to vCenter - will perform SSO, if available, or prompt for credentials, if not
connect-viserver $vCenterServer

# Target only VMs on arrays with thin provisioning capabilities - otherwise the process is a waste
# Examples of different ways to target VMs, as an example - all VMs in a vCenter - if your back end storage is all ZeroDetect or Thin capable
$targetVMs = Get-VM
# Get individual datastores that match pattern - can be VVOL datastores
# $targetVMs = Get-Datastore * | Get-VM
# Get a datastore cluster or clusters matching a pattern
# $targetVMs = Get-DatastoreCluster 3PAR*
# Get all VMs in a Cluster
# $targetVMs = Get-VM -Location (Get-Cluster ClusterName)

# Create a new object that lists the FreeSpace characteristics - limit to just Windows guests
$freespace = $targetVMs | Where {$_.Guest -like "*Win*"} | Select Name, UsedSpaceGB, ProvisionedSpaceGB, @{N="FreeSpaceVMwareGB";E={$_.ProvisionedSpaceGB - $_.UsedSpaceGB}}, @{N="FreeSpaceWindows";E={(Get-WmiObject Win32_LogicalDisk -ComputerName $_.Name | Where {$_.DriveType -eq 3} | Measure -Property FreeSpace -Sum).Sum}}

# Use the $freespace object and summarize 
$reclaimable = $freespace | Select Name, @{N="TotalSpaceVMW";E={ [math]::Round($_.ProvisionedSpaceGB)}}, @{N="UsedSpaceVMW";E={ [math]::Round($_.UsedSpaceGB)}}, @{N="FreeSpaceVMW";E={ [math]::Round($_.FreeSpaceVMwareGB)}}, @{N="FreeSpaceWIN";E={ [math]::Round($_.FreeSpaceWindows / 1GB)}} | Where {$_.FreeSpaceVMW -ne 0 -AND $_.FreeSpaceWIN -ne 0} 

# Add a final column called Reclaimable with the difference between Windows reported and VMware reported free space
$reclaimable = $reclaimable | Select *, @{N="Reclaimable";E={$_.FreeSpaceWIN - $_.FreeSpaceVMW}}

# Perform the cleanup
$reclaimable | sort -Property Reclaimable -DESC | Where {$_.Reclaimable -gt $ReclaimThreshold} | ForEach {
	$computer = $_.name
	$drives = Get-WmiObject Win32_LogicalDisk -ComputerName $_.Name | Where {$_.DriveType -eq 3}
	$drives | Select DeviceID | FT
	$drives | ForEach {
		Write-Host "Zeroing disk space on drive "$_.DeviceID
		Invoke-Command -Computer $computer -ScriptBlock ${function:\Write-ZeroToFreeSpace} -ArgumentList $_.DeviceID,.01

Utilized the Write-ZeroToFreeSpace script from Chris Duck. http://blog.whatsupduck.net/2012/03/powershell-alternative-to-sdelete.html

You may also like