Inventorying vSphere VMs with custom attributes

I'm somewhat new to working with VMware's vSphere and have been teaching it to myself through Powershell.  Powershell has the advantage of being able to explore objects without having to worry about accidentally clicking on something that could take the environment down.  To stay as safe as possible, I started out with exploring the Get commands, the most obvious being Get-VM.  My first script was as basic as they get.

Get-VM 'myvm' | Format-List *

This gave me a basic list of properties that I could view.  Now I needed a way to store that information in a report.

Get-VM 'myvm' | Select Name,NumCPU,MemoryMB,UsedSpaceGB,Notes | Export-CSV C:\myVMs.csv

My new CSV was a good start, but there was other information that I wanted to capture.  I started digging into the objects nested deep in the VM and started creating my own properties.  The one-liner started to stretch a bit far, so I cleaned it up by breaking the lines at the pipes.

Get-VM 'myvm' | 
Add-Member -Name "GuestOS" -Value {$this.ExtensionData.Guest.GuestFullName} -MemberType ScriptProperty -Passthru -Force | 
Add-Member -Name "VMToolsVer" -Value {$this.extensiondata.config.tools.toolsversion} -MemberType ScriptProperty -Passthru -Force | 
Select Name,NumCPU,MemoryMB,UsedSpaceGB,GuestOS,IPv4Address,Notes |
Export-Csv C:\myVMs.csv

Now we're getting somewhere.  Almost any information that was built into the vSphere console and viewable was in my grasp.  While I was searching the internet for more things I could add, I came across a post from @LucD22 about custom attributes.  There were a few posts about creating and setting custom attributes, but no easy way to retrieve them that I could find.  So I set out to write my own.  This was my first attempt at gathering the information.

Get-VM 'myvm' | Select Name,@{l="Contact";e={$_.customfields | ?{$_.key -eq 'Contact'} | select -ExpandProperty value}}

The more I learn about Powershell, the more I become a stickler for standardization and I didn't like the look of that hash table when I added it into my previous script; it cluttered my Select-Object statement and made it harder to read which attributes I was pulling.  Once I cleaned up the script, I turned it into a function and it was ready for production.  Below is the final version of the script with help included.

Function Get-VMReport {
<#
.SYNOPSIS
Retrieves virtual machines from VMware vCenter
.DESCRIPTION
Retrieves virtual machines from VMware vCenter and returns summary information
.EXAMPLE
.\Get-VMReport.ps1
This returns all virtual machines from all default vCenters
.EXAMPLE
.\Get-VMReport.ps1 -vCenter vCenter01 -Credential $Credential
This returns all virtual machines from vCenter01 using the credentials stored in $Credentials
.LINK
http://blog.richprescott.com
#>

[CmdletBinding()]
    Param(
    [String[]]$vCenter = 'MyvCenter',
    
    [Parameter(Mandatory=$true,ParameterSetName="RunAs")]
    [Alias("PSCredential")]
    [System.Management.Automation.PSCredential]$Credential
    )

Connect-VIServer -Server $vCenter -Credential $Credential | Out-Null
Get-VM | 
    Add-Member -Name "vCenter" -Value {$vCenter} -MemberType ScriptProperty -Passthru -Force | 
    Add-Member -Name "IPv4Address" -Value {$this.ExtensionData.Guest.IPAddress} -MemberType ScriptProperty -Passthru -Force | 
    Add-Member -Name "GuestOS" -Value {$this.ExtensionData.Guest.GuestFullName} -MemberType ScriptProperty -Passthru -Force | 
    Add-Member -Name "Datastore" -Value {Get-Datastore -VM $this} -MemberType ScriptProperty -Passthru -Force | 
    Add-Member -Name "VMToolsVer" -Value {$this.extensiondata.config.tools.toolsversion} -MemberType ScriptProperty -Passthru -Force | 
    Add-Member -Name "Contact" -Value {$this.customfields | ?{$_.key -eq 'Contact'} | select -ExpandProperty value} -MemberType ScriptProperty -Passthru -Force | 
    Select vCenter,Name,Contact,PowerState,VMToolsVer,GuestOS,numCPU,MemoryMB,Datastore,UsedSpaceGB,ProvisionedSpaceGB,IPv4Address,Notes
Disconnect-VIServer -Server $vCenter -confirm:$False | Out-Null
}
Get-VMReport | Export-Csv C:\Reports\vCenter.csv -NoTypeInformation