Custom report about Custom Fields in virtual infrastructure

by Grzegorz Kulikowski

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 :
[sourcecode language=”powershell”]
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:
[sourcecode language=”powershell”]
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.
[sourcecode language=”powershell”]
$(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.
[sourcecode language=”powershell”]
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 !

You may also like


Gus September 5, 2013 - 10:25 pm

How would I use this to only search a single cluster for instance our Test Cluster?

psvmware September 6, 2013 - 11:40 am

Hi Gus,
In line #2,
foreach ($cluster in get-cluster) {
change this to
foreach ($cluster in get-cluster -name ‘your Test cluster’) {

acekeeper March 31, 2015 - 11:57 pm

I have multiple hosts with CustomAttribute, do you have anything for hosts but not for VMs?

psvmware April 2, 2015 - 10:52 am

Hey Acekeeper,
I think this should do the trick:
foreach ($cluster in get-cluster -name ‘some Name’) {
foreach ($vmhostview in (get-view -ViewType HostSystem -SearchRoot $ {
$vmhost=New-Object PsObject
Add-Member -InputObject $vmhost -MemberType NoteProperty -Name VMname -Value $vmhostview.Name
Add-Member -InputObject $vmhost -MemberType NoteProperty -Name Cluster -Value $cluster.Name
foreach ($CustomAttribute in $vmhostview.AvailableField){
Add-Member -InputObject $vmhost -MemberType NoteProperty -Name $CustomAttribute.Name -Value ($vmhostview.Summary.CustomValue | ? {$_.Key -eq $CustomAttribute.Key}).value

The way of doing is exactly the same as with VMs, it’s just now you want a viewtype of hostsystem and not virtualmachine, that’s the only change.

grephappiness October 7, 2015 - 10:26 pm

Noob question,

I’m trying to populate existing availablefields with a specific value. Basically a reverse of this script. I’d have a csv with the values inputted. Then I’d want to search for the matching vm and update all those values to whats in the csv. I’m having trouble producing this though.

More specifically for this script. Can I specific a certain key value to exclude from being generated during the report?

psvmware October 8, 2015 - 10:27 am

Hi, i am not sure what you are trying to do. Can you elaborate more and give some code example with questions ?

Dan Hadden July 27, 2016 - 7:36 pm

Do you have an import script that would use the csv output? We are migrating VM1 from VC1 to VC2 and after migration would like to import the customer attribs.

Andre April 20, 2018 - 1:49 pm

Bom dia, estou utilizando o comando abaixo para alterar o customfields das pastas, porém não está replicando para as pastas “filho” alguém sabe como fazer isso pelo powercli?

Get-Folder ‘nome_da_pasta’ | Set-Annotation -CustomAttribute Contato -Value e-mail



Leave a Reply

Chinese (Simplified)EnglishFrenchGermanHindiPolishSpanish