Tuesday, January 24, 2017

Auditing your VMware environment with PowerCLI

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'}
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:
  1. the one returned by Get-VmHost which basically contains all the hardware information, as you can see in the following screenshot

  2. 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
  3. the one returned by the License Manager, like the assigned license key or the number of licenses used
Once I have put the contents of these three information providers into three variables, I can use those to build up my custom object. Here's the variable assignment part:
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


The Get-ESXAudit retrieves complete information about the configuration, licensing and load of one or more VMWARE ESX servers.
Get-ESXAudit -vCenter vcenter.myserverfarm.com -ESX '*'
Get-ESXAudit -vCenter vcenter.myserverfarm.com -ESX 'esx1.myserverfarm.com','esx2.myserverfarm.com'
$auditinfo = Get-ESXAudit -vCenter vcenter.myserverfarm.com -ESX 'esx1.myserverfarm.com','esx2.myserverfarm.com'
$auditinfo | select -skip 1 | ft * -auto
'vcenter1.myserverfarm.com','vcenter2.myserverfarm.com' | Get-ESXAudit -ESX 'esx1.myserverfarm.com','esx2.myserverfarm.com'
Get-ESXAudit -vCenter vcenter.myserverfarm.com -ESX '*' | Select-Object -Skip 1  | ConvertTo-Csv -NoTypeInformation | Out-File "audit-vmware.csv" -Force


    [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


    Foreach($VMhost in $VMHosts)


        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

Related Posts Plugin for WordPress, Blogger...