Add Snapshot Information to the VI Client using Powershell

Although I spend quite some time in the Powershell Command Line Interface, the main tool for managing the Virtual Infrastructure remains the VI Client. So wouldn’t it be great if we could somehow show the results of our Powershell VI Toolkit scripts inside the VI Client?
Well, we can! Let’s take a closer look at Custom Fields / Custom Attributes.
If you select either a VMHost (ESX Server) or a VM in the VI Client and open the Summary tab, you will see the Annotations section in the bottom left. When you click Edit, I’m sure you have used the Notes section to enter Descriptions. But have you ever used the Attributes section? Here you can manually add and remove custom attributes and their values. Go ahead and create one. Then select a cluster or datacenter and click the Hosts or Virtual Machines tab. You will notice you can display your custom attribute in this table view, just like all the other properties of your VMs / Hosts. Pretty sweet!
But we don’t want to add and update those fields manually, now do we? Of course not, we’ve got Powershell! Let’s see how we can automate this.
We start by connecting to the Custom Fields Manager:

$VCServerName = “MYVCSERVER”
$VC = Connect-VIServer $VCServerName
$SI = Get-View ServiceInstance
$CFM = Get-View $SI.Content.CustomFieldsManager

Take a look at the $CFM.Field property. It contains an array of available fields. Next step: add our own custom field.

# Variables
$CustomFieldName = “Snapshots”
$ManagedObjectType = “VirtualMachine”
# Check if the custom field already exists
$myCustomField = $CFM.Field | Where {$_.Name -eq $CustomFieldName}
If (!$myCustomField)
{
# Create Custom Field
$FieldCopy = $CFM.Field[0]
$CFM.AddCustomFieldDef($CustomFieldName, $ManagedObjectType, $FieldCopy.FieldDefPrivileges, $FieldCopy.FieldInstancePrivileges)
}

Final step: Fill the custom field with some relevant information:

# Fill Custom Fields
$VMs = Get-VM
$VMViews = $VMs | Get-View
ForEach ($VMView in $VMViews)
{
$SnapshotCount = ($VMView.Snapshot.RootSnapshotList | Measure-Object).Count
If ($SnapShotCount)
{
$VMView.setCustomValue($CustomFieldName,$SnapShotCount)
}
}

Now take a look at the VI Client:
snapshots
More examples coming soon!
Hugo

PS: Don’t forget to schedule the script to run at an interval, so the values are kept up-to-date!

  • Share/Bookmark

No related posts.

  • Alan Renouf

    December 16th, 2008

    Very nice, I like it alot.

  • afokkema

    December 16th, 2008

    I have tested this script it works great except it doesn’t reset the custom field if a delete the snapshot. Am I doing something wrong?

  • admin

    December 16th, 2008

    @afokkema
    Nope. The script sets the values and exits. You have to schedule the script to run at an interval (using Windows Task Scheduler for instance) to keep the values up-to-date. I added this as a PS to the post, but I’m guessing you read the RSS feed before I updated the post.
    Hugo

  • admin

    December 16th, 2008

    PS: Check back here tomorrow for five great sample scripts using Custom Fields!

  • Julian Wood

    December 16th, 2008

    Hugo, great idea for a script which I will run as a scheduled task.

    I was getting some inconsistent results that it was not correctly counting the number of snapshots when there were multiple sometimes cascading snapshots.

    Here’s my update which seems to work with these. Not sure how the Count is computed differently.
    $VMs = Get-VM
    ForEach ($VM in $VMs)
    {
    $SnapshotCount = (Get-Snapshot -VM $VM | Measure-Object).Count
    $VMView = $VM | Get-View
    $VMView.setCustomValue($CustomFieldName,$SnapShotCount)
    }

  • admin

    December 16th, 2008

    Julian,
    Thank you for sharing the correction!
    Hugo

  • Julian Wood

    December 16th, 2008

    Something else I spotted was that each time you run the script it creates another task against each VM whether the number of snapshots has changed or not.

    So, amendment 2 is to check the value of the CustomField and only update it if the snapshot count has changed.
    This removes the extra tasks from your database and also speeds up the script as it only changes the fields when it needs to.

    $VMs = Get-VM

    ForEach ($VM in $VMs)
    {
    $ExistingSnapShotCount = $vm.CustomFields.Item($CustomFieldName)
    $SnapshotCount = (Get-Snapshot -VM $VM | Measure-Object).Count
    If ($SnapshotCount -ne $ExistingSnapShotCount)
    {
    $VMView = $VM | Get-View
    $VMView.setCustomValue($CustomFieldName,$SnapShotCount)
    }
    }

  • admin

    December 16th, 2008

    That one was already on my TO ADD-list. I have added it to my sample scripts. I will post them tomorrow, so stay tuned.
    Thank you,
    Hugo

  • Jindi

    December 18th, 2008

    I don’t understand where you are putting the PS code. I created my customer attr but where do I run my PS code from?

  • admin

    December 19th, 2008

    From Powershell of course!
    Install Windows Powershell and the VMware VI Toolkit (http://www.vmware.com/go/powershell) and copy-paste the code into the window of save it as a .ps1 file and start it by typing the full path to the file in the powershell window.

  • Simon

    January 16th, 2009

    The code “$SnapshotCount = ($VMView.Snapshot.RootSnapshotList | Measure-Object).Count” will only count the first level of snapshots. To count all snapshots you will need to recurse through the ChildSnapshotList of each snapshot in the RootSnapshotList.

    For example:

    $VMSnapshotCount = 0
    $VMSnapshots = $VMView.Snapshot.RootSnapshotList
    ForEach ($VMSnapshot in $VMSnapshots) {
    Write-Output (“Found snapshot: ” + $VMSnapshot.Name)
    $VMSnapshotCount++;
    $VMSnapshotCount += findSnapshots($VMSnapshot)
    }

    function findSnapshots([VMware.Vim.VirtualMachineSnapshot]$VMSnapshot) {
    $VMChildSnapshots = $VMSnapshot.ChildSnapshotList
    $VMChildSnapshotCount = 0
    ForEach ($VMChildSnapshot in $VMChildSnapshots) {
    $VMChildSnapshotCount += findSnapshots($VMChildSnapshot)
    }
    return $VMChildSnapshots
    }

    Note: This code is untested, but logically you need to recurse through the ChildSnapshotList for each snapshot in the RootSnapshotList.

    Simon

  • admin

    January 16th, 2009

    That’s true! So why not change the code into this:
    $SnapshotCount = ($VM | Get-Snapshot | Measure-Object).Count
    You have to Change the loop to be ForEach ($VM in $VMs) and put $VMView = $VM | Get-View inside the loop.
    Hugo

  • ron

    March 10th, 2009

    Hi,

    I realize this is an older post, but can you paste what the final code would look like with your suggested “ForEach” change. I’m new to powershell and need a little help if you have a moment.

    Thanks Very Much,

    Ron

  • admin

    March 11th, 2009

    @ron
    Hi Ron,

    The updates script can be downloaded here:
    http://www.peetersonline.nl/wp-content/add-vmsnapshotcount.txt

    I will add it to the Script Repository soon for easy reference.

    Hugo

  • Mike

    March 25th, 2009

    Hugo,

    This is a great script, very usefull in our configuration.
    Any idea how (if possible) to get the “age” of the snapshot displayed?

    Thx,
    Mike.

Leave a Comment

* are Required fields