Sorting bits into bytes...

VMware Horizon Client Version in vROps

One of the questions I often get from the Horizon Admins is that they like to know which Horizon Client version the end users are using. I tried to solve this question multiple times in the past, without any success. So I thought why not ask help from my fellow EUC guys. Within a couple of minutes Jesper and Michiel jumped to my help. They provided me with a Powershell script which outputs the client version used by the end users. Now lets combine that with my skills to write a Powershell script that shows the Horizon client version in vROps. And that’s exactly what this script does. It gets the client versions from the Horizon connection server. Next the users are looked up in vROps and a new custom metric is added to them.

 

<#

Author: Kabir Ali - info@kablog.nl
Scriptname: VMware Horizon Client Version (VHCV)
Version: 1.0 (Tested)
Date: Feb 11 2021
Why: Security is important.
Remark: Test setup
        vROps Version: 8.2.0 (16949153)
        VMware Horizon 7.12

Example: .\VHCV.ps1 -ConnectionServer "HorizonConnectionServer.local.domain" -ConnectionUser "VDI-Admin" -ConnectionPass "VMware1!" -vROpsServer "vROps.local.domain" -vROpsUser "vROps-Admin" -vROpsPass "VMware1!"

#>

Param (
    
    [Parameter(Mandatory = $true)][string]$ConnectionServer,
    [Parameter(Mandatory = $true)][string]$ConnectionUser,
    [Parameter(Mandatory = $true)][string]$ConnectionPass,
    [Parameter(Mandatory = $true)][string]$vROpsServer,
    [Parameter(Mandatory = $true)][string]$vROpsUser,
    [Parameter(Mandatory = $true)][string]$vROpsPass
)

# Functions are required
function ConvertTo-UnixTimestamp {
    $epoch = Get-Date -Year 1970 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0	
 	$input | % {		
        $milliSeconds = [math]::truncate($_.ToUniversalTime().Subtract($epoch).TotalMilliSeconds)
        Write-Output $milliSeconds
    }	
}
function Get-TimeStamp {
    return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date)
}

### Define Defaults ###
# See Parameters

### vCenter Connection ###

# Lets connect to the Horizon Connection Server
try {
  Connect-HVServer -Server $ConnectionServer -User $ConnectionUser -Password $ConnectionPass
}
Catch {
  Write-Output "Failed to connect to the Horizon Connection Server: $ConnectionServer ... Exiting..."
  Exit
}


### vROps API Connection ###

#Building vROps API string & invoking REST API
$vROpsURL = "https://" + $vROpsServer + "/suite-api/api/"
$vROpsAuthURL = "https://" + $vROpsServer + "/suite-api/api/auth/token/acquire"
$Type = "application/json"
# Creating JSON for Auth Body
$AuthJSON =
"{
  ""username"": ""$vROpsUser"",
  ""password"": ""$vROpsPass""
}"
# Authenticating with API
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Try {
    $vROpsSessionResponse = Invoke-RestMethod -Method POST -Uri $vROpsAuthURL -Body $AuthJSON -ContentType $Type
}
Catch {
    $_.Exception.ToString()
    $error[0] | Format-List -Force
    Write-Output "Failed connecting to vROps: $vROpsServer ... Exiting..."
    Exit
}
# Extracting the session ID from the response
$vROpsSessionHeader = @{"Authorization"="vRealizeOpsToken "+$vROpsSessionResponse.'auth-token'.token
"Accept"="application/json"}


### Generic Code ###

# Query Horizon to get logged on users with the used client version
$query = New-Object "Vmware.Hv.QueryDefinition"
$query.queryEntityType = 'SessionLocalSummaryView'
$qSrv = New-Object "Vmware.Hv.QueryServiceService"
# Users with client version
$UserClientVersions = $qSRv.QueryService_Query($global:DefaultHVServers[0].ExtensionData,$query) |
Select -ExpandProperty Results |
Select -ExpandProperty NamesData |
Select-Object -Property UserName,ClientVersion

# Generate output
write-host "Found a total of" $UserClientVersions.count "users" -ForegroundColor Green
# For every user found look up the user in vROps
foreach ($UserClientVersion in $UserClientVersions) {
    # vROps cant deal with two dots in the version. So lets break 5.4.4 up into 5. (major release) and 44 (minor release number) while removing the last dot.
    $major = $UserClientVersion.ClientVersion.Substring(0,2)
    $minor =  $UserClientVersion.ClientVersion.split('.')[1..2] -join '' 
    $SimpleVersion = "$major$minor" 
    # Do some cleanup to match usernames in vROps
    $JustUserName = $UserClientVersion.UserName
    # Remove domain part
    $CleanUserName = $JustUserName -replace ".local"
    # Generate output
    write-host $UserClientVersion.UserName "is running version:" $UserClientVersion.ClientVersion -ForegroundColor Green
            # Build vROps URL based on username
            $ResourcesURL = $vROpsURL+"resources?resourceKind=User&name=" +$CleanUserName
            # Get data from vROps
            $vROpsUserName = (Invoke-RestMethod -Method GET -Uri $ResourcesURL -Headers $vROpsSessionHeader -ContentType $Type).resourceList
            # Get timestamp to update vROps with
            $EpochTimeNow = (Get-Date | ConvertTo-UnixTimestamp)
            # Create the JSON reply to update vROps
            $JSONData='{
                "stat-content" : [ {
                "statKey" : "Custom Metrics|Horizon Client Version",
                "timestamps" : ['+$EpochTimeNow+'],
                "data" : ['+$SimpleVersion+'],
                "others" : [ ],
                "otherAttributes" : { }
                } ]
            }'
            # Try to add/update the custom metric
            Try {
                $TagJSONResponse = Invoke-RestMethod -Method POST -Body $JSONData -Uri ($vROpsURL+'resources/'+$vROpsUserName.identifier+'/stats') -TimeoutSec 100 -Headers $vROpsSessionHeader -ContentType $Type
                $TagDetailedInfo = $TagJSONResponse.value
                write-host "Update successful on" $UserClientVersion.UserName -ForegroundColor Green
                write-host "--- --- --- ---" -ForegroundColor Yellow
            }
            Catch {
                $_.Exception.ToString()
                $error[0] | Format-List -Force
                write-host "Update unsuccessful on" $UserClientVersion.UserName -ForegroundColor Red
            }
            # Fix timeout issues
            sleep 1
}

# Close session and done
write-host "All done" -ForegroundColor Green
Invoke-RestMethod -Method POST -Uri https://$vROpsServer/suite-api/api/auth/token/release -Headers $vROpsSessionHeader -ContentType $Type
Disconnect-HVServer -Server * -Confirm:$false

 

I’ve also created a cool dashboard with the newly added metrics.

First create a Metric Configurations file under:

Administration – Configuration – Metric Configurations – TxtWidgetContent – Add

Name the file HClient and add this:

<p><img style="display: block; margin-left: auto; margin-right: auto;" src="https://nolabnoparty.com/wp-content/uploads/2020/08/horizon-7-configuration-01.jpg" alt="Horizon Client 8" width="602" height="202" /></p>
<p style="text-align: center;">Download the latest VMware Horizon Client. Open this link in a new tab:</p>
<p style="text-align: center;"><a title="Download Horizon Client" href="https://my.vmware.com/en/web/vmware/downloads/info/slug/desktop_end_user_computing/vmware_horizon_clients/horizon_8">Horizon Client</a></p>

 

Next import this view:

https://www.kablog.nl/wp-content/uploads/2021/02/Horizon-Client-Version-View.zip

 

The final step is to import this dashboard:

https://www.kablog.nl/wp-content/uploads/2021/02/Dashboard-2021-02-12-03-19-08-PM.zip

Edit the “Number of sessions” widget and be sure to select your own connection servers!

 

Now you should end up with a dashboard like this:

Leave a Reply