I am a great fan of VMware PowerCLI, and even if I don't have my blog posts on the subject, I have got a plethora of functions that I use pretty often for managing my virtual environment. Recently though, I have been asked to perform a deep audit of all the ESXi servers in our farms, and discovered that I did not have a decent function for the job.
I was stuck in particular on the fact that there is no way to know if my ESX are properly licensed to run Microsoft Windows as guest OS and one of the requirements I had was exactly to check that we had bought and assigned a Windows 2012 R2 Datacenter license to the ESXi hosting Windows VMs.
And I was also asked to provide information on the cost center for the project that was used to buy the physical assets and the licenses.
For sure none of this information is available out of the box and I spent quite a bit of time to decide how to cope with the requirements.
In the end I decided to use the Set-Annotation cmdlet to add additional static information to my ESXi and then to write and advanced function to retrieve a general inventory of the physical server as well as those manually added fields. Set-Annotation is a tiny nice cmdlet that modifies the value of a custom attribute. In my case I have added two custom attributes to my hosts:
And I have a script which does the job of setting the values for those attributes each time I install a new ESXi. Here's a couple examples of how I use this script:
1..9 | % {Set-Annotation -Entity (Get-Vmhost esx$_.myserverfarm.com) -CustomAttribute Windows-License -Value 'Datacenter-2012'}or
Set-Annotation -Entity (Get-Vmhost esx1.myserverfarm.com) -CustomAttribute Project -Value 'Project Name'Once I have set those two attributes everywhere, I can proceed to run my function Get-ESXAudit, which retrieves all the information I need and return it in form of a PowerShell object (I hope my friend and fellow MVP Luc Dekens will be forgiving if this is a too basic function).
In my function, to build the object I rely mainly on three pieces of information:
- the one returned by Get-VmHost which basically contains all the hardware information, as you can see in the following screenshot
- the one returned by Get-View, which returns a view of all the object with a higher level of detail, like the serial number or the EVC mode for a host
- the one returned by the License Manager, like the assigned license key or the number of licenses used
And here's the first part of the creation of the custom object:
During the creation of the object I use the Get-Annotation cmdlet to fetch the custom attributes I have added to my hosts:
In order to follow the execution of this function, I find it useful to add a progress bar through the use of the Write-Progress cmdlet:
The last important thing to note is the two phases of setup and tear down of the connections to the VIservers, which is pretty important if you want to keep your memory footprint low:
Now here's the full code of the Get-ESXAudit function, which you can also find on GitHub:
Function Get-ESXAudit { <# .Synopsis The Get-ESXAudit retrieves complete information about the configuration, licensing and load of one or more VMWARE ESX servers. .EXAMPLE Get-ESXAudit -vCenter vcenter.myserverfarm.com -ESX '*' .EXAMPLE Get-ESXAudit -vCenter vcenter.myserverfarm.com -ESX 'esx1.myserverfarm.com','esx2.myserverfarm.com' .EXAMPLE $auditinfo = Get-ESXAudit -vCenter vcenter.myserverfarm.com -ESX 'esx1.myserverfarm.com','esx2.myserverfarm.com' $auditinfo | select -skip 1 | ft * -auto .EXAMPLE 'vcenter1.myserverfarm.com','vcenter2.myserverfarm.com' | Get-ESXAudit -ESX 'esx1.myserverfarm.com','esx2.myserverfarm.com' .EXAMPLE Get-ESXAudit -vCenter vcenter.myserverfarm.com -ESX '*' | Select-Object -Skip 1 | ConvertTo-Csv -NoTypeInformation | Out-File "audit-vmware.csv" -Force .NOTES happysysadm.com @sysadm2010 #> param( [parameter(mandatory=$true,valuefrompipeline=$true)] [string[]]$vCenter, [string[]]$ESX = '*' ) Write-Verbose "Adding snapin" Add-PSSnapin vmware.vimautomation.core Write-Verbose "Cleaning up connections to vcenters" Disconnect-VIServer -Server $vCenter -Confirm:$false -ErrorAction SilentlyContinue Write-Verbose "Connecting to vcenters" Connect-VIServer -Server $vCenter Write-Verbose "Connecting to license manager" $ServiceInstance = Get-View ServiceInstance $LicenseManager = Get-View $ServiceInstance.Content.LicenseManager $LicenseManagerAssign = Get-View $LicenseManager.LicenseAssignmentManager Write-Verbose "Retrieving the hosts" $VMhosts=Get-VMHost $ESX $VMhostsTotal=@() Foreach($VMhost in $VMHosts) { $i++ Write-Progress -activity "Retrieving $($VMHosts.count) ESX information" ` -status "Doing $i on $($VMHosts.count)" -PercentComplete (($i / $VMHosts.count) * 100) Write-Verbose "Retrieving general hardware information on $VMhost" $VMHostHW = Get-VMHost -Name $VMHost.name Write-Verbose "Retrieving a view on the .NET object" $VMHostView = $VMHostHW | Get-View Write-Verbose "Retrieving the ID" $VMhostID = $VMHostView.Config.Host.Value Write-Verbose "Retrieving the licence information" $VMHostLicInfo = $LicenseManagerAssign.QueryAssignedLicenses($VMhostID) Write-Verbose "Creating object" $vmhostobject = [PSCustomObject]@{ Name = $VMHostView.Name Manufacturer = $VMHostHW.Manufacturer Model = $VMHostHW.Model Product = $VMHostView.Config.Product.Name Version = $VMHostView.Config.Product.Version Sockets = $VMHostView.Hardware.CpuInfo.NumCpuPackages CPUCores = $VMHostView.Hardware.CpuInfo.NumCpuCores LicenseVersion = $VMHostLicInfo.AssignedLicense.Name | Select -Unique LicenseKey = $VMHostLicInfo.AssignedLicense.LicenseKey | Select -Unique TotalLicense = $VMHostLicInfo.AssignedLicense.Total | Select -Unique UsedLicense = $VMHostLicInfo.AssignedLicense.Used | Select -Unique CostUnit = $VMHostLicInfo.AssignedLicense.CostUnit | Select -Unique WindowsLicense = ($VMHostHW | Get-Annotation | where name -eq 'Windows-License').value Project = ($VMHostHW | Get-Annotation | where name -eq 'Project').value VMs = ($VMHostHW | Get-VM).count Memory = [math]::round(($VMHostHW.MemoryTotalMB/1KB),0) Memoryused = [math]::round(($VMHostHW.MemoryUsageMB/1KB),0) Percentusedmem = [int]((100/$VMHostHW.MemoryTotalMB ) * $VMHostHW.MemoryUsageMB) CpuTotalMhz = $VMHostHW.CpuTotalMhz CpuUsageMhz = $VMHostHW.CpuUsageMhz Percentusedcpu = [int]((100/$VMHostHW.CpuTotalMhz)*$VMHostHW.CpuUsageMhz) Parent = $VMHostHW.Parent Serial = ($VMHostView.Hardware.SystemInfo.OtherIdentifyingInfo | where {$_.IdentifierType.Key -eq “ServiceTag”}).IdentifierValue EVCMode = ((($VMHostHW).parent | Get-View).summary).CurrentEVCModeKey MaxEVCMode = ($VMHostView | select -ExpandProperty summary).maxevcmodekey Cluster = $VMHostHW.parent.name CPU = $VMHostHW.ProcessorType } Write-Verbose "Object created" $VMhostsTotal += $vmhostobject } Write-Verbose "Cleaning up connections to vcenters" Disconnect-VIServer -Server $vCenter -Confirm:$False -Force write-verbose "Returning all the objects" return $VMhostsTotal } # End Function
Feel free to contribute to this function or to suggest ways to improve it. If you have any question, do not hesitate to post it in the comments and I'll do my best to answer.
No comments:
Post a Comment