VMware Horizon – Powershell scripting (Problem VMs)



In the next post of this series, we’ll have a look at querying the number of Problem vCenter VM’s from VMware Horizon. The number of problem VM’s in Horizon can be seen in the Flash based administrator console in the upper left corner:

Problem VMs

If you click on the number next to Problem vCenter VMs, you get a list of all the VM’s that are in a non-normal status.

If we want to get this information from the ViewAPI, we can’t just read some property to get the results. We need to use the QueryService. First we create a QueryServiceService object and a QueryDefinition object. In the QueryDefinition we set the EntityType to “MachineSummaryView”. For a list of entity types that can be queried, you can check the VMware API Explorer (choose “Query Service in the left sidebar).
We also create an array with all possible “problem states” we’re interested in. With this array we create a QueryFilter object.
The result is a list of all machines that are in one of the “problem states” in $VMs.

...
    $query_Service = New-Object "VMware.Hv.QueryServiceService"
    $query = New-Object "Vmware.Hv.QueryDefinition"
    $query.QueryEntityType = 'MachineSummaryView'

    $HVState = @('PROVISIONING_ERROR', 
                    'ERROR', 
                    'AGENT_UNREACHABLE', 
                    'AGENT_ERR_STARTUP_IN_PROGRESS',
                    'AGENT_ERR_DISABLED', 
                    'AGENT_ERR_INVALID_IP', 
                    'AGENT_ERR_NEED_REBOOT', 
                    'AGENT_ERR_PROTOCOL_FAILURE', 
                    'AGENT_ERR_DOMAIN_FAILURE', 
                    'AGENT_CONFIG_ERROR', 
                    'UNKNOWN',
                    'ALREADY_USED')

    [VMware.Hv.QueryFilter []] $filters = @()
    foreach ($filterstate in $HVState)
    {
        $filters += New-Object VMware.Hv.QueryFilterEquals -Property @{'memberName' = 'base.basicState'; 'value' = $filterstate}
    }
    $orFilter = new-object VMware.Hv.QueryFilterOr -Property @{'filters' = $filters}
    $query.Filter = $orFilter

    $VMs = $query_Service.QueryService_Query($viewAPI,$query)
...

If we check $VMs.results we’ll get the list of machines that are problematic

Well… not much to see here… We’ll have to dig deeper into the results to get the information we need.

We can get the total number of machines using $VMs.Results.Length
More details about the machines are found in $VMs.Results.Base

For monitoring purposes, we’re only interested in the total number of VMs per problem state. So we loop through our filter array, and count the number of VMs for each filter.

foreach ($item in $filters)
    {
        $errorVMs = $VMs.Results.Base | where BasicState -eq $item.Value
        write-host "$($item.Value): $($errorVMs.Length)"

    }

This gives us a nice overview of the number of VMs per problem state. If we wrap this all up and format it nicely in the PRTG expected XML format, we get the following script:

#
# Retrieve the number of Horizon Problem vCenter VMs
#

# set some parameters with default values
param (
    [string]$HVServer="connectionserver.horizon.cloud",
    [string]$HVUser,
    [string]$HVPass
)

    #import necessary modules
    Import-Module VMware.VimAutomation.Core
    Import-Module VMware.VimAutomation.HorizonView

    # if no user/pass specified via parameters, prompt for user/pass, else use the parameters
    if ($HVUser -eq "" -or $HVPass -eq "") { $con = Connect-HVServer -Server $HVServer  }
    else { $con = Connect-HVServer -Server $HVServer -User $HVUser -Password $HVPass }

    # connect to the Horizon View API
    $viewAPI = $con.ExtensionData

    # Create objects to query the ViewAPI
    $query_Service = New-Object "VMware.Hv.QueryServiceService"
    $query = New-Object "Vmware.Hv.QueryDefinition"
    $query.QueryEntityType = 'MachineSummaryView'

    # create array with possible problem states to filter on
    $HVState = @('PROVISIONING_ERROR', 
                    'ERROR', 
                    'AGENT_UNREACHABLE', 
                    'AGENT_ERR_STARTUP_IN_PROGRESS',
                    'AGENT_ERR_DISABLED', 
                    'AGENT_ERR_INVALID_IP', 
                    'AGENT_ERR_NEED_REBOOT', 
                    'AGENT_ERR_PROTOCOL_FAILURE', 
                    'AGENT_ERR_DOMAIN_FAILURE', 
                    'AGENT_CONFIG_ERROR', 
                    'UNKNOWN',
                    'ALREADY_USED')

    # Create filter object
    [VMware.Hv.QueryFilter []] $filters = @()
    foreach ($filterstate in $HVState)
    {
        $filters += New-Object VMware.Hv.QueryFilterEquals -Property @{'memberName' = 'base.basicState'; 'value' = $filterstate}
    }
    $orFilter = new-object VMware.Hv.QueryFilterOr -Property @{'filters' = $filters}
    $query.Filter = $orFilter
    
    # run query and save results     
    $VMs = $query_Service.QueryService_Query($viewAPI,$query)

    # Start XML output for PRTG
    write-host "<prtg>"

    # Total results
    $total = $VMs.Results.Length
    write-host "  <result>"
    write-host "    <channel>Total problem vCenter VMs</channel>"
    write-host "    <value>$total</value>"
    write-host "    <unit>count</unit>"
    write-host "  </result>"

    # loop through our filters and get total number for each problem state
    foreach ($item in $filters)
    {
        $errorVMs = $VMs.Results.Base | where BasicState -eq $item.Value
        write-host "  <result>"
        write-host "    <channel>$($item.Value)</channel>"
        write-host "    <value>$($errorVMs.Length)</value>"
        write-host "    <unit>count</unit>"
        write-host "  </result>"
    }
                
    # close XML for PRTG output
    write-host "</prtg>"
    
    # disconnect from our connection server
    $con | Disconnect-HVServer -Force -Confirm:$false

PRTG

When we create a new “EXE/Script advanced” sensor pointing to our script above (see the previous post on how to create the sensor), We’ll get the follwing information:

We get a channel for each “problem state” showing the total number of VMs in that state. There’s also a channel showing the total number of all problem vCenter VMs. Now you can set error/warning levels on each channel so you get notified when too many problem VMs show up.
E.g. the state “AGENT_UNREACHABLE” can exist shortly after starting a linked clone desktop but should disappear quickly, so you can set a warning level when the total is more than 10. The state “PROVISIONING_ERROR” should be set to warn at 1, because if that happens there’s a problem with our Horizon.

This concludes our third post about monitoring our VMware Horizon environment with PRTG. Stay tuned for more to come!



Leave a Reply

Your email address will not be published. Required fields are marked *