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)

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

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


Get VMware Disk Usage with Powershell

Using VMware seriously requires a lot of (shared) storage. This kind of storage (on a SAN for instance) is quite expensive. So you might want to check if you are wasting a lot of this space. When you look at the storage in VMware, it consists of multiple abstraction layers. A virtual machine has one or more Logical Disks, which are indicated by driveletters. You can use WMI to determine the amount of used and free space (Win32_LogicalDisk). One or more logical disks are contained in a partition. One or more partitions reside on a physical disk. That physical disk is really a virtual disk, a vmdk file to be precise. One or more vmdk files reside in a Datastore, which can be found on a LUN on your SAN.
The following script enumerates most of these layers (from logical disk to datastore) and calculates the used and free space. The final line exports the results to a csv file for use in Excel. And the script also helps you to calculate the average free space by showing the totals without the duplicates (don’t try to average the averages in excel, that’s not accurate because datastores contain duplicates and averages should be weighed).

UPDATE: I have modified the script, so no more matching of disks is done based on disk size. The match is made based on SCSI IDs and WMI relations. Thanks to adavidm on the VI Toolkit Community Continue reading

List ALL available properties in the VI Toolkit

UPDATE: Fixed the script to also recurse through arrays. It only gets the first item in the array. That’s for a good reason. Else you’ll get millions of items!

Wow! This was quite a challenge. But I did it!
Inspired by my scripts Create a Directory Tree with Powershell and Listing AD Group Members Recursively with Powershell, I responded to a queation in the VI Toolkit Community: “Is it possible to recursively get all the properties of a VI Toolkit object, such as returned by Get-VMHost | Get-View?”

Here is my script. It creates a collection of objects with the property names (full names) and their values (Great for Export-Csv).

Usage: $VMView = Get-VM | Get-View
.\ShowMyVMProperties.ps1 ‘$VMView’

Do not forget the single quotes around the $VMView there. You can use any variable name you like as well as any object from the VI Toolkit.


# Function that lists the properties
function Show-Properties
If ((Invoke-Expression $BaseName) -ne $null)
#Write-Host “Expanding $BaseName”
$Children = (Invoke-Expression $BaseName) | Get-Member -MemberType Property
ForEach ($Child in ($Children | Where {$_.Name -ne “Length” -and $_.Name -notmatch “Dynamic[Property|Type]” -and $_.Name -ne “”}))
$NextBase = (“{0}.{1}” -f $BaseName, $Child.Name)
$Invocation = (Invoke-Expression $NextBase)
If ($Invocation)
If ($Invocation.GetType().BaseType.Name -eq “Array”)
#Write-Host (“{0} is an array.” -f $Child.Name)
# Recurse through subdir
$NextBase = $NextBase + ‘[0]’
Show-Properties $NextBase
ElseIf ($Child.Definition -like “VMware*”)
#Write-Host (“{0} is a VMware Object” -f $Child.Name)
# Recurse through subdir
Show-Properties $NextBase
#Write-Host (“{0} is an endpoint.” -f $Child.Name)
$myObj = “” | Select Name, Value
$myObj.Name = $NextBase
$myObj.Value = $Invocation
Clear-Variable Invocation -ErrorAction SilentlyContinue
Clear-Variable NextBase -ErrorAction SilentlyContinue
Write-Warning “Expand Failed for $BaseName”

# Actual start of script
If ((Invoke-Expression $VariableName).GetType().BaseType.Name -eq “Array”)
$VariableName = $VariableName + ‘[0]’
Show-Properties $VariableName

Finding and Stopping VI Sessions with Powershell

If you have been trying out the VMware VI Toolkit for Windows Powershell, you have probably noticed. You have to disconnect (disconnect-viserver) each session you set up to the VI Server (connect-viserver), or it will linger for eternity (or until the next reboot at least). That’s why I always include a disconnect-viserver command at the end of my VI Toolkit scripts. But what happens in real life: when debugging a script, it hardly ever reaches the end of the script. It will stop at an error or be cancelled by me to fix some bug I notice. I regularly check the Sessions tab in my VI Client and terminate all my idle sessions to keep VI clean and fast. So why not automate that too? Here’s how:

function Get-Session
$Global:SI = Get-View ServiceInstance
$Global:SM = Get-View $SI.Content.SessionManager
Return $SM.SessionList

function Stop-Session
ForEach ($Session in $_)
If ($Session.Key -ne $SM.CurrentSession.Key)
$Key = $session.Key
Write-Host “Session $Key terminated.”
$Key = $null
Write-Warning “Cannot terminate current session.”

The function Get-Session lists the currently active sessions. You can then filter them as you do any collection of objects in Powershell and pipe them to Stop-Session to have them terminated. Note that VI Client sessions appear to create two actual sessions and that the API (and therefore my function) will not allow you to terminate the current session.

Get-Session | Where { ((Get-Date) – $_.LastActiveTime).TotalHours -ge 8 } | Stop-Session


Create a Directory Tree with Powershell

I was playing around with PSDrives when I decided to write this script. It recurses through (part of) a PSDrive and shows the items it finds in a simple tree view.
The fun part is that it works on any PSDrive!

  • Show-Tree D:\scripts will show subdirectories and files in a tree;
  • Show-Tree HKCU:\ will show Registry keys and subkeys in a tree;
  • Show-Tree VI:\ will show your VMware Virtual Infrastructure in a tree, if you first create a PSDrive for it.

Here’s how to create a PSDrive for you Virtual Infrastructure:

$root = Get-Folder -NoRecursion
New-PSDrive -Name VI -PSProvider VIMInventory -Root ‘\’ -Location $root

Creating a full tree takes plenty of time, but you can get a branch of the full tree like so: Show-Tree VI:\MYDATACENTER\host\MYFOLDER\MYCLUSTER, where you replace the caps with your own names. Use vm instead of host to show the Virtual Machines and Templates view instead of the Hosts and Clusters view.


# Function that lists the children of a dir
function Show-TreeItems

# Function that indents to a level i
function Indent
$Global:Indent = $null
For ($x=1; $x -le $i; $x++)
$Global:Indent += ” “

$Children = Get-ChildItem $Location | Sort Name
ForEach ($Child in $Children)
Indent $i
“{0}{1}” -f $Indent,$Child
If ($Child.PSIsContainer)
# Recurse through subdir
Show-TreeItems $Child.PSPath


# Actual start of script
$i = 0
Show-TreeItems $BaseDir

Modifying vSwitch Offload Policy with Powershell

Of all the vSwitch properties, the Offload Policy settings are the most obscure. You can’t even view them through the GUI. You can see them in the /etc/vmware/esx.conf file, or using the Powershell VI Toolkit, if you know how to use this command:

((Get-VMHostNetwork ESXSERVER | Get-View).NetworkConfig.vSwitch | Where {$_.Name -eq “vSwitch1”}).Spec.Policy.OffloadPolicy

I told you it’s obscure…

Changing the settings is even more difficult, as the method that allows you to do so, requires almost every possible property to be set, even if you don’t want to change it. So, I thought I’d make it a bit more simple. How about the following command:

Set-MyOffloadPolicy -VMHost ESXSERVER -vSwitch “vSwitch1” -TcpSegmentation Off

All you need is to connect to your VIServer and make sure this function is loaded:

Set-MyOffloadPolicy (rename to .ps1 or copy into your profile)

Hope you like it!

Setting Video Hardware Acceleration Level

It’s about time I follow up on the post Getting Video Hardware Acceleration Level.

I have created a simple, fire-and-forget script that sets the Hardware Video Acceleration Level for all your (Windows Server 2003 and Powered On) VM’s to Full. This way you can always enjoy smooth mouse movements when working in the console!

Set-VMVideoAccLevel (Rename to .ps1)


Setting of advanced options with the VI Toolkit

It’s a bit tricky to find, but the API reference showed me where to look. And now I’m posting it here, so you don’t have to search any further.

First, connect to the Option Manager:
$SI = Get-View $ServiceInstance
$OM = Get-View $SI.Content.Setting

Query current values of advanced options:

To change or add an advanced option:

Create a new object to hold the new settings.
$newOption = New-Object VMware.Vim.OptionValue

Set the Key and Value you would like to add or change.
$newOption.Key = ‘ADV_OPTION_NAME’
$newOption.Value = 300

Use the UpdateOptions method to execute the change.

Tadaa! 🙂

Track Datastore Free Space

I’ve got a great new script for you today!

We all love VMware for consolidating our servers. And we all know that virtualization requires lot’s of SAN space. But how do you keep track of the amount of space left on all your datastores? It’s pretty easy to create a report using the Powershell VI Toolkit. But who is going to read all those reports and compare them to yesterday’s values? You will most likely end up with a mailbox full of reports and still be surprized when yet another datastore fills up.

PeetersOnline to the rescue! How about storing the report every day and comparing today’s values to yesterday’s values? Then you can email yourself only the differences. The overview shows the datastores that changed since yesterday, the change rate and the current value. This way, you can easily assess if the datastore is about to fill up.

Because it is quite a large script (in Powershell terms) and it contains long lines that are not easily readable on my site, I have attached the script for you to download. It contains lot’s of comments, so you should be able to follow exactly what it does and how it works. If not, post a comment.


Track-Datastores (Rename to .ps1)

VMware Stats Oneliner

Today’s oneliner is a nifty little function that reports the average CPU and Memory usage for one or more of your VMs, calculated over the last x hours:

function Get-VMStat
param( $VM,[Int32]$Hours = 1 )
 $VM | Sort Name |
 Select Name, @{N=”CPU”;E={[Math]::Round((($_ |
 Get-Stat -Stat cpu.usage.average -Start (Get-Date).AddHours(-$Hours) -IntervalMins 5 -MaxSamples ($Hours*12) |
 Measure-Object Value -Average).Average),2)}}, @{N=”MEM”;E={[Math]::Round((($_ |
 Get-Stat -Stat mem.usage.average -Start (Get-Date).AddHours(-$Hours) -IntervalMins 5 -MaxSamples ($Hours*12) |
 Measure-Object Value -Average).Average),2)}}

A great way to use it is like this:

Get-VMStat (Get-VM) -Hours 4 | Where {$_.CPU -gt 50 -or $_.MEM -gt 75}

I’m sure you can figure out what that does. Be the first to give the correct answer in the comments to win everlasting glory! (or at least until the next oneliner…)