Using PowerCLI to Inventory VMware VM Attributes and Custom Tags
A reliable virtual machine inventory gives administrators more than a list of names and power states. It can show CPU and memory allocation, storage consumption, host placement, guest operating system details, annotations, and the metadata used to organise workloads in vCenter. PowerCLI is well suited to collecting this information repeatedly and exporting it in a format that can be searched, compared, or consumed by another system.
Custom tags and custom attributes are particularly useful in mixed environments. A tag can identify an owner, application tier, backup policy, or business service, while a custom attribute can hold a ticket number, recovery classification, or migration note. For Australian organisations operating across Sydney, Melbourne, Brisbane, or Perth, a scripted inventory also provides a consistent view of workloads spread across multiple sites and data centres.
Prepare PowerCLI And vCenter Access
Install the VMware.PowerCLI modules on an administration workstation or management server, then allow the module to connect to the relevant vCenter Server. PowerCLI can connect directly to an ESXi host for some operations, but tag and category information is managed through vCenter, so a vCenter connection is the practical choice for this inventory.
Install-Module VMware.PowerCLI -Scope CurrentUser
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Scope Session
Connect-VIServer -Server vcsa01.example.com
Use an account with permission to read virtual machines, annotations, tags, tag categories, hosts, and datastores. Avoid using a full administrator account for scheduled collection. In a production environment, especially one subject to APRA CPS 234 controls, a dedicated read-only identity makes access easier to review and reduces the effect of compromised credentials.
Choose The VM Properties To Collect
Start with properties that support capacity planning and operational decisions. VM name, power state, vCPU count, memory, provisioned storage, used storage, host, cluster, folder, guest operating system, and notes are common fields. Get-VM exposes many of these properties directly, while related objects such as the VM host and datastores may need their names extracted separately.
$vms = Get-VM | Sort-Object Name
$vms | Select-Object Name, PowerState, NumCpu, MemoryGB,
ProvisionedSpaceGB, UsedSpaceGB, VMHost, Folder,
Guest, Notes
The returned Guest value may be an object rather than a clean operating system string, depending on the PowerCLI version and guest tools state. For dependable reporting, use Guest.OSFullName where available and fall back to the configuration value exposed by the vSphere API. This helps identify stale VMware Tools installations and VMs that have never reported guest information.
Read Tags And Categories
Tags are returned through Get-TagAssignment. Each assignment includes the tag and its category, allowing the report to preserve useful pairs such as Environment=Production or Backup=Gold. A VM may have several tags, so joining the values into one field keeps the CSV export compact while retaining the relationship between category and tag.
$tagText = Get-TagAssignment -Entity $vm |
ForEach-Object {
"$($_.Tag.Category.Name)=$($_.Tag.Name)"
} |
Sort-Object |
Join-String -Separator '; '
Join-String is available in newer PowerShell versions. On an older Windows PowerShell installation, use -join instead:
$tagText = (Get-TagAssignment -Entity $vm |
ForEach-Object { "$($_.Tag.Category.Name)=$($_.Tag.Name)" } |
Sort-Object) -join '; '
Tags are preferable when a value needs controlled vocabulary, filtering, or policy integration. Categories can also enforce cardinality, such as allowing only one value for an environment category. This prevents the inconsistent spelling that often appears when administrators manually enter values into notes.
Capture Custom Attributes And Annotations
vSphere custom attributes are retrieved with Get-Annotation. The command returns name-and-value pairs assigned to the VM, such as Application Owner, Cost Centre, or Decommission Date. Since different VMs may have different attributes populated, converting them into a single delimited field avoids losing records in a fixed-column export.
$customText = Get-Annotation -Entity $vm |
Where-Object { $_.Value } |
ForEach-Object { "$($_.Name)=$($_.Value)" } |
Sort-Object
$customText = $customText -join '; '
Annotations are useful for free-form operational context, but they need governance. Define naming standards and acceptable formats before using them for reporting. A date such as 2025-06-30 is easier to process than end of June, and a consistent owner identifier is more useful than a mixture of names, email addresses, and team abbreviations.
Build A Reusable Inventory Script
The following pattern combines ordinary VM properties, tags, and custom attributes into one PowerShell object. It also records the vCenter server and collection time, which helps distinguish a current export from an older copy stored on an administrator’s workstation.
$collected = Get-Date
$report = foreach ($vm in Get-VM | Sort-Object Name) {
$tags = (Get-TagAssignment -Entity $vm |
ForEach-Object { "$($_.Tag.Category.Name)=$($_.Tag.Name)" } |
Sort-Object) -join '; '
$attributes = (Get-Annotation -Entity $vm |
Where-Object { $_.Value } |
ForEach-Object { "$($_.Name)=$($_.Value)" } |
Sort-Object) -join '; '
[pscustomobject]@{
CollectedAt = $collected
vCenter = $DefaultVIServer.Name
Name = $vm.Name
PowerState = $vm.PowerState
CPUs = $vm.NumCpu
MemoryGB = $vm.MemoryGB
ProvisionedGB = [math]::Round($vm.ProvisionedSpaceGB, 2)
UsedGB = [math]::Round($vm.UsedSpaceGB, 2)
Host = $vm.VMHost.Name
Folder = $vm.Folder.Name
GuestOS = $vm.Guest.OSFullName
Tags = $tags
CustomAttributes = $attributes
Notes = $vm.Notes
}
}
Some properties can be empty when a VM is powered off, VMware Tools is missing, or inventory permissions are restricted. Treat blank values as a data-quality signal rather than automatically replacing them. A separate review can identify unmanaged VMs, missing ownership tags, and records that need correction.
Export And Validate The Results
Export the objects to CSV for auditing, reconciliation, or import into an asset management platform. Use UTF-8 encoding so names and notes containing Australian place names, accented characters, or other non-ASCII text remain readable in Excel and downstream tools.
$path = "C:\Reports\vm-inventory-$((Get-Date).ToString('yyyyMMdd-HHmm')).csv"
$report | Export-Csv -Path $path -NoTypeInformation -Encoding UTF8
$report | Format-Table Name, PowerState, CPUs, MemoryGB, Host, Tags
Validate the output before treating it as authoritative. Compare the VM count with vCenter, check for duplicate names, inspect blank tag fields, and confirm that storage figures are understood as provisioned versus consumed capacity. A Sydney site and a Perth site may use different cluster naming conventions, so include cluster, data centre, or vCenter fields when the environment spans regions.
Schedule Inventory For Operational Use
A scheduled task can run the script daily or weekly on a management server. For larger environments, filter by vCenter, data centre, cluster, or folder, and collect from each vCenter in a controlled loop. This is useful when VMware licensing changes or hybrid cloud growth makes manual inventory increasingly expensive across the Australian market.
Keep exported files in a restricted location because VM names, IP-related notes, application ownership, and recovery classifications may constitute sensitive business information. The Privacy Act 1988 and internal data-retention rules should guide storage and sharing, while the Essential Eight can support a regular review of administrative access and asset visibility. Retain enough historical data to identify changes, but avoid creating an uncontrolled archive of operational metadata.