CBT Tracker PowerShell Script - Now With More Zombie
Friday, August 26 2011 15:18 Written by VMGuru
It appears that when I did my site re-design a while back, I left out a few key blog posts. I was kindly reminded today, that my CBT Tracker post no longer exists, so I've decided to bring it back from the dead, as I was under the impression many people found high value in understanding data growth patterns of individual VMs in their environment.
I took it as a personal challenge this week to leverage PowerShell, PowerCLI and the vSphere API to track the amount of data that changes in a VM over a regular interval window. It turns out VMware does make it quite simple to query what blocks in a VMDK file have changed and what the length of data is as long as you know how to structure the API call.
The following script can be run as a scheduled task in Windows on a regular interval such as every 15 or 60 minutes, or even just once a day (depending on how granular you want your data) against a single VM. This is perfect for profiling the amount of data a particular VM will need to send (uncompressed) over a network connection for backup or replication purposes.
There are a few quick things to note about this script:
- It requires vSphere and CBT to be enabled for the selected virtual machine. This also means the VM Hardware version must be set to 7. There is an optional flag of "-enableCBT $true" that can be set as a script parameter to enable CBT for the specified VM. This executes an additional function in the script to turn CBT on. If CBT is already enabled, the function simply exits cleanly, no harm, no foul.
- I don't recommend running this script against a VM if there is potential overlap with other regular processes such as backup or replication that add snapshots to virtual machines. I don't have advanced snapshot debugging in here and simply don't know how all scenarios of snapshots being added/removed from multiple programs against a single VM will play out.
- I have it limited so a single instance of the script can be run against a single VM only. I started off with this being a simple proof-of-concept script, and haven't built in proper multi-VM intelligence yet. If there is enough demand, I'll definitely consider it.
You should create a standalone directory somewhere on an available hard drive of a Windows system. Create a new PS1 file using the built in script editor in PowerGUI. Copy and paste the following code block and save the file as "CBT_Tracker.ps1" in the newly created directory:
There is one optional parameter, and that is setting "-enableCBT = $true" in the batch file inside the quotes. What this will do is attempt to enable CBT on the specified VM. Once CBT is enabled, the flag is no longer needed. It also will not do any specific harm if CBT is already enabled, and will just exit the function and continue on its way.
| CBT_Tracker.ps1 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
Param ( [string] $vmName, [string] $vimHost, [string] $vimUser, [string] $vimPass, [Boolean] $enableCBT = $false ) #Use the optional $enableCBT paramater at input to enable CBT on #a compatible virtual machine (HW Version 7). In order for CBT flags to take #effect, a Snapshot must be added and removed. function Add-CBTFlag { if ($vmv.Config.ChangeTrackingEnabled){ "CBT is already enabled on $vm" return } $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $vmConfigSpec.changeTrackingEnabled = $true $vmv.ReconfigVM($vmConfigSpec) sleep 3 $vm | New-Snapshot -Name "Enable CBT" sleep 5 $vm | Get-Snapshot -Name "Enable CBT" | Remove-Snapshot -Confirm:$false "Enabled CBT for $vm" } #Add a snapshot specific to the purposes of this script function Add-CBTSnap { $newSnap = $vm | New-Snapshot -Name "CBT Change Tracker" return $newSnap } #Remove the snapshot created for the purpose of this script function Remove-CBTSnap { param ( $vmSnap ) $vmSnap | Remove-Snapshot -Confirm:$false } #Captures the ChangeID of the snapshot, which is required for comparisson #tracking purposes. The current run of the script will always compare #current state against the previously logged ChangeID for differences. function Get-ChangeID { param ( $vmSnap ) $vmSnapv.Config.Hardware.Device | where {($_.GetType()).Name -eq "VirtualDisk"} | ForEach-Object { $vzCBT = New-Object PSObject $vzCBT.PSObject.TypeNames.Clear() $vzCBT.PSObject.TypeNames.Insert(0,"vzCBTTracker") $vzCBT ` | Add-Member -MemberType NoteProperty -Name VMName -Value $vm.Name -PassThru ` | Add-Member -MemberType NoteProperty -Name DeviceID -Value $_.Key -PassThru ` | Add-Member -MemberType NoteProperty -Name ChangeID -Value $_.Backing.Get_ChangeID() [array] $vzCBTColl += $vzCBT } return $vzCBTColl } #Writes the historic ChangeID and VMDK device information to a tracking file #This file is read on each iteration of the script to capture the previos #iterations ChangeID inforation. function Write-TrackerLog { $output = $null $cid | ForEach-Object { $output += $_.VMName + "," + $_.DeviceID + "," + $_.ChangeID + "`n" } $output | Out-File "$vm-CBTTracker.cfg" } #Reads previous state information of the VM from the Tracker.cfg file #Captures the list of changed blocks for the specified VM for each VMDK file #calculates the total size in bytes of changed block data across all VMDK #files associated with the VM. function Get-ChangedBlockSize { $chSize = 0 Get-Content "$vm-CBTTracker.cfg" | ForEach-Object { if ($_ -ne "") { $TrackerRef = $_.split(",") $changes = $vmv.QueryChangedDiskAreas($vmSnapv.MoRef,$TrackerRef[1],0,$TrackerRef[2]) $changes.ChangedArea | ForEach-Object { $chSize += $_.Length } } } $chSize = $chSize/1024/1024 return $chSize } #Writes the actual iterations change data out to a CSV file function Write-TrackerCSV { $longDate = Get-Date $shortDate = $longDate.toShortDateString() + " - " + $longdate.toShortTimeString() Add-Content "$vm-CBTTracker.csv" "$vm,$shortDate,$amtChanged" } #Loads VMware's PowerCLI PowerShell Cmdlets if necessary [void](Get-PSSnapin VMWare.VimAutomation.Core -ErrorVariable getVmwareSnapinErr 2> $null) if ($getVmwareSnapinErr.Count -gt 0) { Add-PSSnapin VMware.VimAutomation.Core } #Establish a connection to the VI Server based on input parameters Connect-VIServer $vimHost -User $vimUser -Password $vimPass #Load some VM variables $vm = Get-VM $vmName $vmv = $vm | Get-View #We can only run against a single VM at this point in time. This makes sure #the object being passed is a single VirtualMachineImpl object, and not a #collection. if (($vm.GetType()).Name -ne "VirtualMachineImpl"){ "Script can only run against a single VM at a time" return } #Checks to make sure VM Hardware version is 7. Terminates if not. if ($vmv.Config.Version -ne "vmx-07" -and $vmv.Config.Version -ne "vmx-08"){ "The Virtual Machine $vm must be VM Hardware Version 7 to support CBT" return } #If the "-enableCBT $true" flag is set as an input parameter, enables CBT #for specified VM if necessary if ($enableCBT){ Add-CBTFlag } #If all other checks fail, this is a final failsafe to ensure CBT is enabled #on the VM before continuing the script. if ($vmv.Config.ChangeTrackingEnabled -eq $false){ "CBT is not enabled on $vm. Script cannot proceed." return } #Load up snapshot variables $vmSnap = Add-CBTSnap $vmSnapv = $vmSnap | Get-View $amtChanged = 0 #Checks to see if the script has previous written out a CBTTracker.cfg file. This #would indicate file deletion, or first script run. If cfg file doesn't exist, #initializes CSV headings. If this is an iterative run, Gets the amount of #data that has changed since previous iteration. Writes to CSV file. if (Test-Path "$vm-CBTTracker.cfg") { $amtChanged = Get-ChangedBlockSize Write-TrackerCSV } else { Add-Content "$vm-CBTTracker.csv" "VMName,Time,ChangedMB" } #Capsture the current ChangeID to use against next iteration, Remove Snapshot #Write cfg data. $cid = Get-ChangeID ($vmSnap) Remove-CBTSnap ($vmSnap) Write-TrackerLog |
With the script file created, use notepad or other simple text editor to create a new CMD file called "CBT_Tracker.cmd". This is what you will execute within Windows Task Scheduler. Paste the following line in the CMD file and edit with the proper parameters for your environment. Make sure you copy exactly, including the quotes.
1 |
powershell -command "& '.\CBT_Tracker.ps1' -VMName VMName -vimHost vCenter.domain.com -vimuser domain\user -vimpass Passw0rd"
|
You can now fire up Windows Task Scheduler and point to the CMD file. After the script runs for the first time, you will see 2 new files per VM that you set this to run against. $VMName-CBT_Tracker.cfg is used for tracking previous snapshot history for reference in the current script iteration. $VMName-CBT_Tracker.csv is the actual data file that contains the VMName, Timestamp, and Amount of data changed.
I've also attached a ZIP file containing the PS1 script for those that don't want to mess around with script editors and copy/paste actions.

How are we to interpret the ChangedMB information? I've been running this script against one of my DC's. I'm finding that every 15 minutes, there is roughly 30-75 "ChangedMB". If there are three intervals of 30 MB changes, does that mean that I would need to transfer 90 MB of new data uncompressed to my target location?
where does the CSV file get saved? i'm seeing snapshots created and removed, but not seeing the files that are supposed to be created. maybe i'm missing some background information on how this all works. VM ver = 7, vmware powerCLI installed, running as administrator. i am getting a certificate error, could that be it?
Thanks for this VM Guru, exactly what I was looking for:-)
I had some issues with the certificate error which I resolved by running the following command in PowerCLI...
Set-PowerCLIConfiguration -InvalidCertificateAction "Ignore" -Confirm:$false
The other thing that had me lost for a while was the task, I had to put the name of the CMD file in as the program and then the directory in the 'Star in (optional):' box.
With that done I'm in business and happily monitoring a couple of test Windows 7 boxes every 15 mins from the vCentre VM. Both are thin provisioned, not being used for anything, one has Symantec Endpoint installed, no pending updates, nobody logged onto them, no active apps, basically doing nothing at all.
I've noticed that the 'Changed MB' on both VM's ranges from 5 to 98! Any thoughts on why the changed MB would be so high?
Cheers
Greg
Hi VM Guru,
I'll have a look at the VMFS alignment.
When I had a closer look at the CSV file I realised that the big changes all seem to happen hourly, I was running a 15 min cycle! It could be something to do with a Windows 7 tasks buried away in the task scheduler or as you say SEP could be doing something. Strange that it also happens on the VM that doesn't have SEP though.
I was wondering where you would recommend running the tasks from? In DEV I'm running them from the VM that has vCentre installed but is that best practice?
One final noob question......
I have a server that creates a lot of temp files when reports are ran. If I replicated the server daily at 23:00 and had a script in place that deleted the temp files before the replication would all the writes and deletes of those temp files be seen as changes in blocks and need to be replicated?
Many thanks
Greg
| Next > |
|---|



