KiXtart script to shrink VMDK for smaller VCB backups
When I first started using VMware ESX I was testing VMware Consolidated Backup (VCB) to dump my virtual machines to a staging area before being copied offsite. I noticed that one of the VMs had a VMDK attached that as far as the OS (Windows Server 2003) was concerned with had all of the data deleted on that volume. After initiating a VCB dump (backup) on the VM I noticed that the VMDK that was dumped to my staging area strangely appeared to contain data. The VMDK size was considerably larger than it should have been for a disk that Windows reported as containing zero data.
After some investigation I realised that when VCB performed a dump of the VMDK it was correctly dumping the used space. It then dawned on me that when Windows was deleting files from the disk it was actually only deleting the 'pointer' to the data and not the data itself. When VCB was dumping the VMDK it was correctly dumping all blocks of the disk that contained data. I then started looking for a way to clean blocks that were no longer being used but still contained remnants from deleted files. I found a tool called SDelete that writes zero's where the disk contains free space as seen by the Operating System.
I incorporated SDelete into a basic script that also uses Defrag (the Windows utility for defragmenting disks) to tidy up volumes and potentially reduce the size of backups when using VCB.
The script first enumerates all local drives on the VM. For each drive that Windows deems as being a local disk the script then defragments the volume and uses SDelete to zero any free space that the disk may have. The script is written in KiXtart.
Here is the script:
; ENUMERATE LOCAL DRIVES - DEFRAG & ZERO EMPTY BLOCKS
WriteValue("HKCU\Software\Sysinternals\SDelete", "EulaAccepted", "1", "REG_DWORD")
$Drives = GetObject("winmgmts:").ExecQuery("select Name,DriveType from Win32_LogicalDisk")
For Each $Drive in $Drives
If $Drive.DriveType = 3
SHELL "%comspec% /c " + chr(34) + "defrag.exe " + $Drive.name + " -f" + chr(34)
SHELL "%comspec% /c " + chr(34) + "sdelete.exe -c " + $Drive.name + chr(34)
I use this by placing the folder CleanDisk (download link below) in C:\Program Files. I create a Windows scheduled task to run either KIX32.exe or WKIX32.exe on say a monthly basis.
NOTE: If you have multiple VMs with VMDKs residing on the same physical storage you will probably want to consider staggering the schedules to reduce I/O on the physical disks.
Download the script and necessary files - HERE