Creating custom PowerCLI scripts for VM reporting
VMware environments rarely stay static. Virtual machines are created, resized, migrated and retired every week, while administrators still need accurate answers about capacity, ownership, operating systems and configuration drift. Custom PowerCLI scripts make that information repeatable instead of relying on manually exported vCenter views.
A useful report should do more than list VM names. It should turn vSphere inventory data into an operational record that supports audits, cost reviews, troubleshooting and lifecycle planning. With a clear data model and a few reliable PowerShell techniques, VM reporting can become a scheduled, version-controlled process.
Define the reporting requirement first
Start by deciding who will use the report and what action it should support. A service desk may need VM name, IP address, power state and operating system, while a platform team may require CPU, memory, datastore, cluster and VMware Tools status. Finance or management may need owner, application, environment and last activity fields.
Avoid collecting every available property simply because PowerCLI exposes it. Excessive output makes CSV files difficult to interpret and can slow down large inventory queries. Establish a small core schema, then add optional fields for specific audiences.
Australian organisations may also need to identify where information is stored and who can access it. Reports containing hostnames, usernames or application ownership data should be handled consistently with the Privacy Act 1988 and internal security policies, particularly when files are sent to third-party platforms or stored outside Australia.
Connect to vSphere safely
A reporting script should separate connection details from reporting logic. Use Connect-VIServer with a controlled account, avoid embedding passwords in source files, and disconnect at the end of each run. For scheduled execution, a service account with read-only permissions is usually preferable to a highly privileged administrator account.
$credential = Get-Credential
Connect-VIServer -Server "vcsa01.example.com" -Credential $credential
$vms = Get-VM
Disconnect-VIServer -Server "vcsa01.example.com" -Confirm:$false
For multiple vCenter servers, store names in a configuration file or parameter and process them in a loop. This is useful for organisations operating separate production and disaster recovery environments, such as a Sydney primary site with workloads replicated to Melbourne or Brisbane.
Use try, catch and finally blocks around the connection and query stages. This ensures failures are logged and sessions are closed cleanly, even when a vCenter is unavailable or a certificate issue interrupts execution.
Build a useful VM inventory query
Get-VM provides the foundation for most reports, but the default output is only a starting point. Related objects such as networks, datastores, guest details and annotations must be queried deliberately. Calculated properties allow the final object to contain business-friendly values rather than raw PowerCLI objects.
$report = Get-VM | ForEach-Object {
$vm = $_
$guest = Get-VMGuest -VM $vm -ErrorAction SilentlyContinue
$network = ($vm | Get-NetworkAdapter |
Select-Object -ExpandProperty NetworkName) -join "; "
[pscustomobject]@{
Name = $vm.Name
PowerState = $vm.PowerState.ToString()
vCPU = $vm.NumCpu
MemoryGB = [math]::Round($vm.MemoryGB, 2)
Datastore = (($vm | Get-Datastore).Name -join "; ")
Network = $network
OperatingSystem = $guest.OSFullName
IPAddress = ($guest.IPAddress -join "; ")
Notes = $vm.Notes
}
}
For larger environments, repeated calls inside a loop can create unnecessary load. Retrieve related objects in batches where possible, limit the query to relevant clusters or folders, and avoid running intensive reports during busy backup or patching windows. A PowerCLI report should be a good citizen within the virtual infrastructure.
Add calculated metrics and validation
Raw inventory fields become more useful when they expose operational risk. Examples include powered-on VMs without VMware Tools, snapshots older than a defined threshold, oversized virtual disks, disconnected network adapters and VMs with no owner annotation.
You can add calculated fields with simple PowerShell expressions:
$report | Select-Object *,
@{Name="HasOwner"; Expression={
-not [string]::IsNullOrWhiteSpace($_.Notes)
}}
For snapshot reporting, use Get-Snapshot and calculate age from Created. For capacity reviews, combine allocated disk size with datastore free space rather than treating provisioned capacity as actual consumption. This distinction matters in thin-provisioned environments and helps prevent misleading forecasts.
Reports should also validate expected values. Flag unknown operating systems, blank application tags and inconsistent environment names such as Prod, Production and PROD. Standardised tags make future automation easier, including Ansible deployment workflows that consume inventory or metadata from the same platform.
Export and schedule the report
CSV is a practical interchange format for PowerShell, Excel and monitoring tools. Use an ISO-style date in the filename so files sort chronologically, and include the vCenter or site name when several environments are processed.
$folder = "C:\Reports\VMware"
$date = Get-Date -Format "yyyy-MM-dd_HHmm"
$path = Join-Path $folder "VM-Inventory_$date.csv"
$report | Export-Csv -Path $path -NoTypeInformation -Encoding UTF8
Australian teams working across AEST and AEDT should define the reporting timezone clearly. A scheduled task that runs at 08:00 local time can produce confusing timestamps when daylight saving changes affect Sydney, Melbourne or Canberra. Record the execution time in UTC or label the timezone in the report metadata.
For scheduled execution, Windows Task Scheduler, Azure Automation or a management server can run the script. Store the code in Git, review changes through pull requests and retain a short execution log. If a report supports an audit or capacity decision, being able to identify exactly which script version produced it is valuable.
Recommendations for dependable reporting
A maintainable PowerCLI reporting solution benefits from a few practical standards. These choices reduce noise, improve security and make the script easier for another administrator to operate.
- Use read-only vCenter permissions for inventory collection.
- Keep credentials, vCenter names and output paths outside the main script.
- Add parameters for clusters, folders, datastores and report destinations.
- Validate missing tags, stale snapshots and disconnected network adapters.
- Export UTF-8 CSV files with consistent column names and timestamps.
- Log connection failures, query errors and the number of records returned.
- Test changes against a non-production vCenter or lab environment first.
A report can also become a source for broader infrastructure automation. Pairing consistent VM metadata with documented build standards, such as this VMware build guide, helps align new deployments with the fields your reporting process expects.
Commit the script to a repository, run it against a representative test scope, and compare the output with vCenter before scheduling it. Then publish the resulting report to the team location used for capacity, compliance and operational reviews, with access controls appropriate to the data it contains.