Function for getting report on annotation in VirtualCenter server clusters or particular cluster

I described one way of getting this report in earlier post. If you want to use it as a function… there you go 😉
You can always use get-help greg-get-annotations , if you are in powershell session and want to check the syntax etc..
Report will also include the normal notes section. I’ve tested it in some environments, for example it took 38 sec to complete it in VI where there was ~1500vms, including creation of the csv.

function greg-get-annotations {
Greg-get-annotations function stores information about annotation fields for vms in given
cluster or in all clusters in VC. It stores the result in an arraylist $vms, you can either create
a csv report from this object or display it on screen
greg-get-annotations |export-csv -NoTypeInformation c:\file1.csv will export it to csv file etc...
greg-get-annotations |format-table VMname,Cluster,CreatedOn,Notes will just display on screen a table with
annotations that include : vm name, its cluster and field "CreatedOn" and Notes

.PARAMETER clustername
Specifies the clustername against wchi report will be built

greg-get-annotations -clustername 'cluster01'|Export-Csv c:\annotation-report.csv
Will procude report on vms that resides in 'cluster01' and store it in csv file

greg-get-annotations -clustername 'cluster01'|ft *
Will procude report on vms that resides in 'cluster01' output it to screen

greg-get-annotations |Export-Csv c:\annotation-report.csv
Will procude report on vms that resides in all clusters and output it to screen

Without specified -clustername switch, it will do report regarding all clusters in VC

AUTHOR: Grzegorz Kulikowski
LASTEDIT: 05/30/2011

param ([string]$clustername)
if(!($clustername)){$clusters=Get-Cluster}else{$clusters=Get-Cluster $clustername}
$VMs=New-Object Collections.ArrayList
foreach ($cluster in $clusters)  {
foreach ($vmview in (get-view -ViewType VirtualMachine -SearchRoot $ {
$vm=New-Object PsObject
Add-Member -InputObject $vm -MemberType NoteProperty -Name VMname -Value $vmview.Name
Add-Member -InputObject $vm -MemberType NoteProperty -Name Notes -Value $vmview.Config.Annotation
Add-Member -InputObject $vm -MemberType NoteProperty -Name Cluster -Value $cluster.Name
foreach ($CustomAttribute in $vmview.AvailableField){
Add-Member -InputObject $vm -MemberType NoteProperty -Name $CustomAttribute.Name -Value ($vmview.Summary.CustomValue | ? {$_.Key -eq $CustomAttribute.Key}).value
return $VMs

Add-Member -InputObject $vm -MemberType NoteProperty -Name Notes -Value $vmview.Config.Annotation

Custom report about Custom Fields in virtual infrastructure

This time i wanted to create a report on information which is put in the custom fields for my vms. You can do it very easy using the :

get-vm VM1 | get-annotation

What is more , you can specify which particular custom field you want to retrieve, for example if you cant a custom field called ContactPerson you could write:

get-vm VM1 | get-annotation -CustomAttribute "ContactPerson"

Now it is ok to use it like this, but using that : get-vm | % { get-annotation } would take you quite a while when ran in VI > 100 vms, and even more in > 1000 vms.
I have written short one liner to get all the data and put it into a csv file so i could minupulate data using filters and conditional formatting.

$(foreach ($cluster in get-cluster)  { get-view -ViewType VirtualMachine -SearchRoot $ | % { $vVM=$_; $_.Summary.CustomValue | select @{N="VM Name";E={$vVM.Name}},@{N="Cluster";E={$}},Value,Key,@{N="Key Name";E={$vKey=$_.Key;($vVM.AvailableField|?{$_.Key -eq $vKey}).Name}} }}) | export-csv c:\customfields.csv

You will receive a file in c:\customfields.csv , which will include information as on the screenshot below:

Report is generated in about 8-10 sec on a 1000vms + infrastructure, so it is faster than with the get-annotation. Feel, free to modify it, add other custom columns so it will meet your expectations.
I had to go to two places in order to complete this report, 1 is the Summary.CustomValue section from the get-view virtualmachine object, and second is the AvailableFiled section. Summary.CustomValue will tell you what values are set on which Keys(Key number), and using AvailableField you match a pair KeyNo=KeyName. I am doing a cluster loop, to get the have the information in which cluster vm resides. If needed you can change this to datacenters, or just use without cluster/datacenter container.
The above example was pulling only existing annotations data, so you will not see any vm there which did not have the custom fields filled out. I made a new script to pull data on each vm, each annotation even if the vm does not have any annotation data. What’s more, instead of having each row on “annotation entry” for vm, i have create now an output where you have 1 vm per row, and in columns you have all annotations. I hope this one will be more useful for everybody.

foreach ($cluster in get-cluster)  {
    foreach ($vmview in (get-view -ViewType VirtualMachine -SearchRoot $ {
        $vm=New-Object PsObject
        Add-Member -InputObject $vm -MemberType NoteProperty -Name VMname -Value $vmview.Name
        Add-Member -InputObject $vm -MemberType NoteProperty -Name Cluster -Value $cluster.Name
        foreach ($CustomAttribute in $vmview.AvailableField){
            Add-Member -InputObject $vm -MemberType NoteProperty -Name $CustomAttribute.Name -Value ($vmview.Summary.CustomValue | ? {$_.Key -eq $CustomAttribute.Key}).value
$VMs|Export-Csv c:\annotation-report.csv

I decided to build my own object, and then fill it with all properties. It is building property columns dynamically, so when you have 5 you get 5 columns, if 10 then 10 etc…
And what is more important 😉 it is easier to read this one !

Custom report, checking notes/description for vm, Active Directory description, ManagedBy, Operating System and exporting to csv

This time i wanted to build a report to check which vms are missing the notes/description section. If you have large virtual infrastructure it is very handy to have information about vm, what is its role. In case i don’t have notes/description field in VM, i would go to AD and check if the object has description. I would also like to know who to contact in case it does not have the description i will put data from ManagedBy field in AD. I would also like to know what operating system the vm has, and if it is powered on or off. At the end, i want to have a csv file with this information, so i can quickly edit it in Excel, or other spreadsheet sotware, apply some filters, conditional formatting and so on. It could be done also via powershell using the excel object for instance, and generating data directly to excel spreadsheet but it would take more time to write this at this point for me than applying filters and conditional formatting(1 minute).

$(foreach ($cluster in get-cluster) { get-view -viewtype VirtualMachine -SearchRoot $ | select @{N="VM name";E={$_.Name} },@{N=
"PowerState";E={$_.Summary.Runtime.PowerState}} ,@{N="Guest OS";E={$_.Config.GuestFullName} } , @{N="Cluster";E={$} },@{N="VM .Notes";E={$_.Summary.
Config.Annotation} }, @{N="AD Description";E={(Get-QADComputer $_.Name).Description} },@{N="AD ManagedBy";E={((Get-QADComputer $ | Get-QADUser)
.DisplayName} } }) | export-csv -NoTypeInformation c:\report.csv

I am pulling data cluster after cluster:
foreach ($cluster in get-cluster)
Pulling data for virtual machines in that particular cluster:
get-view -viewtype VirtualMachine -SearchRoot $
Building custom colums :
select @{N=”VM name”;E={$_.Name} -> this should be self explanatory, at this moment i am in a loop where i am receiving vms for cluster, so $_ is the view for VM, $_.Name is the name field in the vm view
I want to have in report the powerstate information :
I want to have information about the operating system:
@{N="Guest OS";E={$_.Config.GuestFullName} }
Information about in which cluster vm resides :
@{N="Cluster";E={$} }
Finally i want to see if the notes have been filled out or not:
@{N="VM .Notes";E={$_.Summary.Config.Annotation} }

In case the notes section is not filled out, i want to see what’s in AD description field:
@{N="AD Description";E={(Get-QADComputer $_.Name).Description} }
If that description would be empty i would like to know who to contact in order to get this information so:
@{N="AD ManagedBy";E={((Get-QADComputer $ | Get-QADUser).DisplayName} }
At the end i close whole output $() in sub-expression to pipe it to export-csv

I was using here Quest cmdlets to query AD. You can download it for free at
Make sure that if you are using them in a script you will add them first by using this:
Add-PSSnapin Quest.ActiveRoles.ADManagement