[HorizonAPI] Configuring the Horizon event database in code

Last week Mark Brookfield asked the question if it is possible to configure the event database in code. My answer was that I thought it should be possible until Stephen Jesse pointed me to the the vmware.hv.helper where there is the set-hveventdatabase cmdlet for this. When looking at the code I noticed something familiar:

.NOTES
Author                      : Wouter Kursten
Author email                : [email protected]
Version                     : 1.0

===Tested Against Environment====
Horizon View Server Version : 7.4
PowerCLI Version            : PowerCLI 10
PowerShell Version          : 5.0

So that’s why I knew it was possible! A good reason to create a quick blogpost though. Mark made a nice script for himself with variables and all those fancy things but I just want to quickly show how you can do it.

$hvedbpw=read-host -AsSecureString
$temppw=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($hvedbpw)
$PlainevdbPassword=[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($temppw)
$dbupassword=New-Object VMware.Hv.SecureString
$enc=[system.Text.Encoding]::UTF8
$dbupassword.Utf8String=$enc.GetBytes($PlainevdbPassword)
$eventservice=new-object vmware.hv.eventdatabaseservice
$eventservicehelper=$eventservice.getEventDatabaseInfoHelper()
$eventsettings=new-object VMware.Hv.EventDatabaseEventSettings
$eventdatabase=new-object VMware.Hv.EventDatabaseSettings
$eventsettings.ShowEventsForTime="TWO_WEEKS"
$eventsettings.ClassifyEventsAsNewForDays=2
$eventdatabase.Server="labsql01.magneet.lab"
$eventdatabase.type="SQLSERVER"
$eventdatabase.port=1433
$eventdatabase.name="pod1_events"
$eventdatabase.username="sa_view"
$eventdatabase.password=$dbupassword
$eventservicehelper.setDatabase($eventdatabase)
$eventservicehelper.setsettings($eventsettings)
$eventservice.update($hvservice,$eventservicehelper)

The first three line make it possible to not use a plaintext password. If you don’t care about that you can remove those and declare something for $plainevdbpassword.

For the $eventsettings.ShowEventsForTime for time there are several options (same as in the gui) these are:

ONE_WEEK,TWO_WEEKS,THREE_WEEKS,ONE_MONTH,TWO_MONTHS,THREE_MONTHS,SIX_MONTHS
Yes, they are all in capitals!

To show how this works I will first clear the current database.

$hvservice.EventDatabase.EventDatabase_Clear()
$hvservice.EventDatabase.EventDatabase_Get()

Yes this is one of those exceptions where a service_get doesn’t need an id.

Now I run the script with a new _get to show the results.

If you are interested in the details:

[HorizonAPI] Working with UAG’s

Something that was added in the last few versions of the Horizon API is the option to handle UAG’s. Since I had to add an uag to my lab for another project I decided to find out what api calls are possible. First I’ll check what services there are.

$hvservice | Select-Object gateway*

I will ignore the GatewayAccessUserOrGroup since that was already in there so we are left with Gateway and GatewayHealth. Let’s see what methods are available under Gateway.

$hvservice.Gateway | gm

I Gateway_Get and Gateway_List will show the same information as always but with _Get you will need a gateway ID and it only shows the information about one gateway. WIth _List you will get the information about all registered gateways.

$hvservice.Gateway.Gateway_List()
$gw=$hvservice.Gateway.Gateway_List() | select-object -First 1
$hvservice.Gateway.Gateway_Get($gw.id)

Let’s see what’s in that GeneralData (Spoiler: not a lot!)

$gwdata=$hvservice.Gateway.Gateway_Get($gw.id)
$gwdata.GeneralData

To remove a gateway we use Gateway_Unregister with the gatewayid

$hvservice.Gateway.Gateway_Unregister($gw.id)

Now i need to register the Gateway again let’s see what we need for that.

$hvservice.Gateway.Gateway_Register

So we need an object of the type VMware.Hv.GatewaySpec. Let’s define that and see what it looks like.

$gwspec=New-Object VMware.Hv.GatewaySpec
$gwspec

So we only need the GatewayName, please use the exact name that was used to configure the UAG otherwise it can be added but it won’t be showing any data.

$gwspec.GatewayName="pod1uag1"

Now to register the UAG

$hvservice.Gateway.Gateway_Register($gwspec)

So with this we did everything we could with the Gateway service. Next is the GatewayHealth service.

$hvservice.GatewayHealth | Get-Member

as usual there’s only a get and a list so let’s see what data is in there.

$hvservice.GatewayHealth.GatewayHealth_List()
($hvservice.GatewayHealth.GatewayHealth_List()).ConnectionData

Sadly nothing more than the admin interface gives us but enough to build an health check like I did for the vCheck already (that can be found here)

For the type there are several options and those can be found in the API Explorer.

VALUE DESCRIPTION
“AP” AP type is for UAG.
“F5” F5 type is for F5 server.
“SG” SG type is for Security Server.
“SG-cohosted” SG-cohosted type is for Cohosted CS as gateway.
“Unknown” Unknown type is for unrecognized gateway type.

I was told by a VMware employee that SG-cohosted is fancy wording for a connection server.

And that’s everything we can do with UAG’s using the Horizon API’s!

[HorizonAPI] Changing the amount of desktops or RDS hosts in a pool/farm

Sometimes there is a need to change the amount of desktops/rds hosts in a pool/farm. Since doing this in the GUI sucks (although that seems to have gotten slightly better with 7.11) I prefer to do it using the API’s. Let’s start with a Desktop pool.

The easiest way to change pool settings is to use the helper function of a service. After connecting to the connection server we first need to query for the ID of the desktoppool that we need to change.

[VMware.Hv.QueryServiceService]$queryService = New-Object VMware.Hv.QueryServiceService
[VMware.Hv.QueryDefinition]$defn = New-Object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'DesktopSummaryView'
$defn.Filter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='desktopSummaryData.name'; 'value' = "Pod01_Pool01"}
[array]$queryResults= ($queryService.queryService_create($HVservice, $defn)).results
$hvpoolid=$queryResults.id

To actually change the pool it’s the best to use the helper function of a service so we first put the desktopservice into an object

$desktopservice=new-object vmware.hv.DesktopService

The next step is to read the current settings into another object.

$desktophelper=$desktopservice.read($HVservice, $HVPoolID)

If you want to see what’s in here we’ll just do this

$desktophelper | get-member

With the get helper method’s it’s possible to get things while you can change them with their set counterpart. Don’t forget to use brackets when you want to go deeper.

$desktophelper.getAutomatedDesktopDataHelper() | get-member

And we can go on and on with this but I happen to already have found where the amount of desktops is listed.

$desktophelper.getAutomatedDesktopDataHelper().getVmNamingSettingsHelper().getPatternNamingSettingsHelper() | get-member

Let’s take a look at the getMaxNumberOfMachines method.

$desktophelper.getAutomatedDesktopDataHelper().getVmNamingSettingsHelper().getPatternNamingSettingsHelper().getMaxNumberOfMachines()

And we can actually use this with setMaxNumberOfMachines

$desktophelper.getAutomatedDesktopDataHelper().getVmNamingSettingsHelper().getPatternNamingSettingsHelper().setMaxNumberOfMachines(10)

But nothing has changed yet (and yes I am lazy so I will show it using the vmware.hv.helper module.

(get-hvpool -PoolName pod01_pool01).automateddesktopdata.VmNamingSettings.PatternNamingSettings

To apply the change to 10 vm’s we need to apply the helper using the update method

$desktopservice.update($hvservice, $desktophelper)

And when we check this with get-hvpool.

And we can do almost the same for RDS farms just a few details that are different in the naming of various objects.

[VMware.Hv.QueryServiceService]$queryService = New-Object VMware.Hv.QueryServiceService
[VMware.Hv.QueryDefinition]$defn = New-Object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'FarmSummaryView'
$defn.Filter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='data.name'; 'value' = "pod1_rds_IC"}
[array]$queryResults= ($queryService.queryService_create($HVservice, $defn)).results
$hvfarmid=($queryResults).id
(Get-HVFarm -FarmName pod1_rds_ic).automatedfarmdata.RdsServerNamingSettings.PatternNamingSettings
[VMware.Hv.FarmService]$farmservice=new-object vmware.hv.FarmService
$farmhelper=$farmservice.read($HVservice, $HVFarmID)
$farmhelper.getAutomatedFarmDataHelper().getRdsServerNamingSettingsHelper().getPatternNamingSettingsHelper().setMaxNumberOfRDSServers(3)
$farmservice.update($HVservice, $farmhelper)

 

Updates to the Horizon API’s in PowerCLI 11.4

So today PowerCLI 11.4 was released with the following updates:

  • Add support for Horizon View 7.9
  • Added new cmdlets to the Storage module
  • Updated Storage module cmdlets
  • Updated HCX module cmdlets

As usual we need to wait for API explorer to be updated before we get the exact changes to the api’s but I already grabbed s short list by comparing the methods. Later I will create a more elaborate blog post about the changes if I have an overview. What I do see are some new additions that might be added to the vCheck for Horizon.

Also: even though the updates are for Horizon 7.9 there’s a good chance that a lot of this also works for previous versions, the examples below where done with 7.8.

  • Datacenter
  • DesktopHealth
  • Gateway
  • GatewayHealth
  • MessageClient
  • Monitoring
  • PersistentDiskQueryService
  • Privilege
  • SecondaryCredentials
  • SessionStatistics
  • StorageAccelerator
  • UsageStatistics
  • Validator
  • VirtualCenterStatistics

Sadly it’s late so I can only show a couple of examples:

$services.Privilege.Privilege_ListSelectablePrivileges()

 

$services.SessionStatistics.SessionStatistics_GetLocalSessionStatistics()

Finally we can reset the usage counters as well now

And some statistics from vCenter

($services.VirtualCenterStatistics.VirtualCenterStatistics_listSummaryStatistics())
($services.VirtualCenterStatistics.VirtualCenterStatistics_listSummaryStatistics()).DataStoreSummaryStatistics

Generating a clean Host Profile using PowerCLI

First of all: I love Host Profiles! But they’re easy to mess up as well, leave something selected related to hardware and an update in ESXi, vib’s or even a firmware update might break it. For a customer where we are going to do the entire vSphere build from scratch I got the idea to generate an empty Host Profile and extend that one using scripting. At first I though this would be an easy thing but it definitely isn’t, a reply from PowerCLI guru Luc Dekens at the VMware{Code} forums set me on the right path to do so. Luc’s remark that editing Host Profiles might take some reverse engineering for the lack of documentation is a huge understatement. It has cost me many many hours to build the script below.

I strongly recommend having the reference host as clean as possible.

These are the steps the script takes

  1. connect to vCenter
  2. extract a new Host Profile
  3. Gets the new Host Profile
  4. Copies all members of the new Host Profile to an object that can be edited
  5. Sets everything that I could find in my environment to false
  6. Updates the Host Profile with the edited object

Required parameters

  • vCenter
    • Your vCenter host
  • Referencehost
    • the name of the host in vCenter
  • Hostprofilename
    • Name for the Host Profile

There are also a couple of optional parameters:

  • dnshost
    • It’s mandatory to have a DNS set in the defaulttcpipstack. With this parameter you can change this.
  • domainname
    • Like DNS it’s mandatory to have a domainname set in the defaulttcpipstack. With this parameter you can change this
  • Cleanup
    • This one defaults to false but can be set to true. It will remove all NFS Datastores, vmkernel ports, portgroups, device aliases and direct i/o profiles.
    • Use this one with care, if you apply it to a host it will most probably remove all networking details for that host making it unusable.

This is how a manual extracted Host Profile looks

This is how a Host Profile looks after using my script without the cleanup option, everything is deselected but the device aliases for example are kept.

.\create_clean_hostprofile.ps1 -vcenter vCenter -Hostprofilename demo_no_cleanup -referencehost hostname

And this is how it looks with the cleanup used.

.\create_clean_hostprofile.ps1 -vcenter vCenter -Hostprofilename demo_no_cleanup -referencehost hostname -cleanup $true

The script itself can be found on Github as well:

#-------------------------------------------------
# Generates a clean Host Profile
#
# Build using PowerCLI 11
#
# Version 1.0
# 17-08-2019
# Created by: Wouter Kursten
# Website: https://www.retouw.nl
#
#-------------------------------------------------

param(
[Parameter(Mandatory=$true)][String]$Hostprofilename,
[Parameter(Mandatory=$true)][String]$vcenter,
[Parameter(Mandatory=$true)][String]$referencehost,
[Parameter()][String]$dnshost,
[Parameter()][String]$domainname,
[Parameter()][bool]$Cleanup = $false
)

# I grabbed this function somewhere from an example by Luc Dekens
function Copy-Property ($From, $To, $PropertyName ="*"){
    foreach ($p in Get-Member -In $From -MemberType Property -Name $propertyName){
        trap {
            Add-Member -In $To -MemberType NoteProperty -Name $p.Name -Value $From.$($p.Name) -Force
            continue
        }
    $To.$($P.Name) = $From.$($P.Name)
    }
}

#connect to the vCenter
connect-viserver $vcenter

# This deletes any existing Host Profile with the same name as we're using in this script
get-vmhostprofile -name $Hostprofilename  -ErrorAction SilentlyContinue | Remove-VMHostProfile -Confirm:$false

# This creates a new Host Profile from the referencehost
new-vmhostprofile -name $Hostprofilename -referencehost $referencehost

# Retrieves the newly created Host Profile
$hp = Get-VMHostProfile -Name $Hostprofilename

# Creates the spec where the cleanup is done
$spec = New-Object VMware.Vim.HostProfileCompleteConfigSpec

# Copies all properties of the new Host Profile to the spec
Copy-Property -From $hp.ExtensionData.Config -To $spec

# This removes everything that could be specific to the referencehost
if ($cleanup -eq $true){
    $spec.ApplyProfile.Network.Vswitch=$null
    $spec.ApplyProfile.Network.VMportgroup=$null
    $spec.ApplyProfile.Network.HostPortGroup=$null
    $spec.ApplyProfile.Network.pnic=$null
    $spec.ApplyProfile.Storage.NasStorage=$null
    ($spec.ApplyProfile.Property | where-object {$_.PropertyName -like "*DeviceAlias*"}).profile=$null
    ($spec.ApplyProfile.Property | where-object {$_.PropertyName -like "*PCI*"}).profile.property.profile=$null
}

# From here it's just disabling of items except for:
# -items under storage> PSA Configuration (profiles are removed)
# -Properties of the fixed DNS config (set to the default values from this scripts parameters)
$spec.ApplyProfile.Datetime.Enabled=$False
$spec.ApplyProfile.Authentication.Enabled=$False
$spec.ApplyProfile.Authentication.ActiveDirectory.Enabled=$False

foreach ($o in $spec.applyprofile.Option){
    if ($o.Enabled){
        $o.Enabled=$False
    }
}

foreach ($p in $spec.ApplyProfile.Property.Profile){
    if ($p.Enabled){
        $p.Enabled=$False
    }
    foreach ($pa in $p.Property.Profile){
            if ($pa.Enabled){
                $pa.Enabled=$False
                }
        foreach ($paa in $pa.Property.Profile){
                if ($paa.Enabled){
                    $paa.Enabled=$False
                }
        }
    }
}

foreach ($s in $spec.ApplyProfile.Storage.Nasstorage){
    if ($s.Enabled){
        $s.Enabled=$False
    }
    foreach ($sa in $s){
        if ($sa.Enabled){
            $sa.Enabled=$False
        }
    }
}

foreach ($s in $spec.ApplyProfile.Storage.Property.Profile){
    if ($s.Enabled){
        $s.Enabled=$False
    }

    if ($s.ProfileTypeName -eq "psa_psaProfile_PluggableStorageArchitectureProfile" -AND $cleanup -eq $true){
        foreach ($sa in $s.property){
            if ($sa.propertyname -like "*psa_psaProfile_PsaDevice*"){
                [email protected]()
            }
        }
    }
    foreach ($sa in $s.Property.Profile){
        if ($sa.Enabled){
            $sa.Enabled=$False
            }
        foreach ($saa in $sa.Property.Profile){
            if ($saa.Enabled){
                $saa.Enabled=$False
            }
        }
    }
}

foreach ($f in $spec.ApplyProfile.Firewall.ruleset){
    if ($f.Enabled){
        $f.Enabled=$False
    }
}

foreach ($n in $spec.ApplyProfile.Network.vswitch){
    if ($n.Enabled){
        $n.Enabled=$False
    }
    foreach ($na in $n){
        if ($na.Enabled){
            $na.Enabled=$False
        }
        foreach ($naa in $na.link){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
        foreach ($naa in $na.NumPorts){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
        foreach ($naa in $na.NetworkPolicy){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
    }
}

foreach ($n in $spec.ApplyProfile.Network.pnic){
    if ($n.Enabled){
        $n.Enabled=$False
    }
    foreach ($na in $n){
        if ($na.Enabled){
            $na.Enabled=$False
        }
    }
}

foreach ($n in $spec.ApplyProfile.Network.VmPortGroup){
    if ($n.Enabled){
        $n.Enabled=$False
    }
    foreach ($na in $n){
        if ($na.Enabled){
            $na.Enabled=$False
        }
        foreach ($naa in $na.Vlan){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
        foreach ($naa in $na.Vswitch){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
        foreach ($naa in $na.NetworkPolicy){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
    }
}

foreach ($n in $spec.ApplyProfile.Network.HostPortGroup){
    if ($n.Enabled){
        $n.Enabled=$False
    }
    foreach ($na in $n){
        if ($na.Enabled){
            $na.Enabled=$False
        }
        foreach ($naa in $na.IpConfig){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
        foreach ($naa in $na.Vlan){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
        foreach ($naa in $na.Vswitch){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
        foreach ($naa in $na.NetworkPolicy){
            if ($naa.enabled -eq $True){
                $naa.Enabled=$False
            }
        }
    }
}

foreach ($n in $spec.ApplyProfile.Network.Property.Profile){
    if ($n.Enabled){
        $n.Enabled=$False
    }
    foreach ($na in $n.Property.Profile){
        if ($na.Enabled){
            $na.Enabled=$False
            }
        foreach ($np in $na.policy.policyoption){
            if ($np.id -eq "FixedDnsConfig"){
                foreach ($npp in $np.parameter){
                    if ($dnshost){
                        if ($npp.key -eq "address") {
                            [string[]][email protected]($dnshost)
                            $npp.value=$dnsarray
                        }
                    }
                    if ($domainname){
                        if ($npp.key -eq "domainName"){
                            $npp.value=$domainname
                        }
                    }
                }
            }
        }
        foreach ($naa in $na.Property.Profile){
            if ($naa.Enabled){
                $naa.Enabled=$False
            }
            foreach ($naaa in $naa.Property.Profile){
                if ($naaa.Enabled){
                    $naaa.Enabled=$False
                }
            }
        }
    }
}


(Get-VMHostProfile $Hostprofilename).ExtensionData.Updatehostprofile($spec)
disconnect-viserver $vcenter -confirm:$False

And yes that’s a lot of foreach’s.

 

 

[API’s] Getting session counts (incl performance comparison)

One of my customers asked the question if it is possible to get a quick sessioncount for a script that they can run very often for a correct logging of license usage. While this could easily be done by grabbing all the sessions I thought this could be a slow process. I remembered though that the first release of the vmware.hv.helper module had a function called get-podsessions that only returned a sessioncount. I decided to see what was used for this. By going back in time at github I found that the GlobalSessionQueryService was still used but with the GlobalSessionQueryService_GetCountWithSpec method. It needs the service and a spec of the type VMware.Hv.GlobalSessionQueryServiceCountSpec.

the spec itself can hold one of the many options to get a count for

As you can see there is a globalentitlement property that needs to be set using the id so let’s grab that one first.

$queryService = New-Object VMware.Hv.QueryServiceService
$defn = New-Object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'GlobalEntitlementSummaryView'
$globalentitlements = ($queryService.QueryService_Create($Services1, $defn)).results

I will use the first globalentitlement to grab the sessioncount

$globalentitlement=$globalentitlements | select -first 1
$globalsessionqueryservice_helper = New-Object VMware.Hv.GlobalSessionQueryServiceService  
$count_spec = New-Object VMware.Hv.GlobalSessionQueryServiceCountSpec  
$count_spec.globalentitlement=$globalentitlement.id
$sessioncountperglobalentitlements=$globalsessionqueryservice_helper.GlobalSessionQueryService_GetCountWithSpec($services1,$count_spec)

As you can see we actually get a count per pod so to get all the counts from all pods from all globalentitlements I have created a script with a couple foreach’s.

$hvserver1=connect-hvserver SERVERNAME
$services1=$hvserver1.extensiondata
$queryService = New-Object VMware.Hv.QueryServiceService
$defn = New-Object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'GlobalEntitlementSummaryView'
$globalentitlements = ($queryService.QueryService_Create($Services1, $defn)).results
$queryservice.QueryService_DeleteAll($services1)
[email protected]()


foreach ($globalentitlement in $globalentitlements){
  $globalsessionqueryservice_helper = New-Object VMware.Hv.GlobalSessionQueryServiceService  
  $count_spec = New-Object VMware.Hv.GlobalSessionQueryServiceCountSpec  
  $count_spec.globalentitlement=$globalentitlement.id
  $sessioncountperglobalentitlements=$globalsessionqueryservice_helper.GlobalSessionQueryService_GetCountWithSpec($services1,$count_spec)
  foreach ($sessioncountperglobalentitlement in $sessioncountperglobalentitlements){
    $pod=$services1.pod.pod_get($sessioncountperglobalentitlement.id)
    $sessioncount+= New-Object PSObject -Property @{
      "Global_Entitlement_Name" = $globalentitlement.base.displayname;
      "Pod_Name"=$pod.displayname
      "Pod_Sessioncount" = ($sessioncountperglobalentitlement | select-object -expandproperty count);
      "Site_Name"= ($services1.site.site_get($pod.site)).base.Displayname;
    }
  }
}
 return $sessioncount | select-object Global_Entitlement_Name,Pod_Name,Site_Name,Pod_Sessioncount

The W10_MGMT global entitlement only has a pool in pod1 so even though the pod doesn’t have a pool inside the global entitlement it will still return a sessioncount.

Performance

I also decided to time it but in my small environment it took 3 seconds and 3 of those where for connecting to the connection server. If I removed the connecting part it was 0.7 seconds.

Measure-Command {D:\scripts\dev\session_count.ps1}

Back at the customer I decided to compare this against dumping all global sessions, this will give some better data since it has a couple more sessions in it (around 3500 at the moment of testing)

The script I used for getting all global sessions is the code that I used for the get-hvglobalsession in the vmware.hv.helper module

$query_service_helper = New-Object VMware.Hv.GlobalSessionQueryServiceService
$query=new-object vmware.hv.GlobalSessionQueryServiceQuerySpec

$SessionList = @()
foreach ($pod in $services1.Pod.Pod_List()) {
  $query.pod=$pod.id
  $queryResults = $query_service_helper.GlobalSessionQueryService_QueryWithSpec($services1, $query)
  $GetNext = $false
  do {
    if ($GetNext) { $queryResults = $query_service_helper.GlobalSessionQueryService_GetNext($services1, $queryResults.id) }
    $SessionList += $queryResults.results
    $GetNext = $true
  } while ($queryResults.remainingCount -gt 0)
    $query_service_helper.GlobalSessionQueryService_Delete($services1, $queryresults.id)

}
return $sessionlist

Screenshots from the timing:

so the getcountwithspec method is about 2.5 seconds faster but the data in the globalsession is way more extensive and usable for all kinds of management overviews.

The VMware Labs flings monthly for December 2018

Happy New Year everyone! Hope you all had a great (and safe!) end of the year. I just need to close the year up with one thing: an overview of flings that have been released or updated in December. No less than four new flings have arrived: VMware Workspace ONE Provisioning ToolDispatch-SoloAndroid Device Pre-Verification Suite and PowerCLI for VMware Cloud on AWS. Two flings have received an update: PowerCLI Extensions and the HCIBench.

New

VMware Workspace ONE Provisioning Tool

The VMware Workspace ONE Provisioning Tool gives you an gui to provision and test WS One Applications.

The VMware Workspace ONE Provisioning Tool helps you test and validate your applications (exported as a .ppkg file) and the special-purpose unattend.xml configuration file as part of the Dell Provisioning for Workspace ONE offer. This tool simplifies the testing and validation of this process in your own environment before these files are sent and applied in the Dell factory.

Highlights

  • Simple UI to easily enable the IT admin to validate their ppkg and unattend.xml files in their own environment, mimicking what Dell is doing in the factory.
  • Supports PPKGs and unattend.xmls generated with Workspace ONE UEM Console 1811 or newer.
  • Highly flexible. Allows IT admins to specify the configurations for tool in a text based config file in order to change things like tool timeout and report location, to name a few.
  • Generates a detailed final summary report with client details and app installation results. This file is saved in C:\ProgramData\Airwatch\UnifiedAgent\Logs\PPKGFinalSummary.log after the “Full Process” button is clicked.
  • Halts the process if any steps fails for the given operation, giving the ability to IT admins to view & debug the state of the machine and the apps.

Supported Operations

  • Apply Apps Only – Given a ppkg, this tool deploys the applications on a test windows machine
  • Apply Full process – Given a ppkg and xml file, this tool deploys the applications on a test windows machine followed by Workspace ONE enrollment and Sysprep.

Dispatch-Solo

The Dispatch-Solo fling actually is a prepackaged VM to get you started with dispatch as easily as possible.

Dispatch-Solo is lean version of Dispatch which has been packaged as VM appliance. The goals of Dispatch-Solo are simple:

  • Lower the barrier to entry – get started with Dispatch in a matter of minutes
  • Support nearly the full Dispatch feature set – API compatibility
  • Explore use-cases – get user feedback and iterate

Because Dispatch and serverless is still in its infancy, understanding use cases is the highest priority. It therefore makes sense to continue to focus on getting Dispatch in as many hands as possible and making it as easy as possible to get started exploring its usage. By packaging Dispatch-Solo as a VM appliance, getting started is quick and predictable.

For full documentation and examples see the Dispatch project page.

Android Device Pre-Verification Suite

This Android Device Pre-Verification Suite Fling reduces the time to perform a preliminary test on any Android device from any OEM. Pre-verification result decides whether the device is eligible for a full device verification program or not. This eliminates the TAT (turnaround time) for basic test failures during the initial phase of verification from VMware. Customers/Partners can run this tool at their premise and check whether the device passes the device verification program entry criteria.

PowerCLI for VMware Cloud on AWS

If you are using VMware Cloud on AWS the PowerCLI for VMware Cloud on AWS fling will give you an preview on what to expect from PowerCLI to automate VMC.

This Fling provides a community preview of the upcoming PowerCLI commands for managing VMware Cloud on AWS. It comes in the form of a single PowerCLI module and integrates with existing PowerCLI modules.

All commands have been automatically generated. They are still in development, contain known issues, and will change in the future.

Updated

PowerCLI Extensions

The PowerCLI extensions fling gives you a preview on what to expect in the official PowerCLI releases.

Changelog

Version 3.0.0.11173018

  • Updated PowerCLI.Extensions Module to be compatible with VMware PowerCLI 11.0.0

HCIBench

This one should be known by now, the HCIBench is made for benchmarking your hyperconverged infrastucture. Ideal for things like vSAN but please be aware that it could also possibly be tuned for that.

Changelog

Version 1.6.8.7

  • Enhanced easy-run, put original 4k,70% read as the first test case, then 4k, 100% read and 256k, 100% write
  • Enhanced tvm deployment validation
  • Added Checksum into easy-run consideration
  • Updated guest VM template with increased ring_pages and disk scheduler
  • Added DNS configuration guidance into welcome message

Version 1.6.8.5

  • Added 2 more test cases into easy-run, 4k 100% random read and 256k 100% sequential write
  • Batch deployment will be involved if deploying more than 8 VMs to speed up deployment process
  • Allow user to choose IP prefix when using static IP
  • Optimized UI to allow user to review the results by single click
  • Fixed regression issue when placing Datacenter/Cluster in the folder

 

[Update 15-10] VMware PowerCLI 11.0.0 release with new Horizon (7.6!) API calls

UPDATE 12-10: The new API explorer page also has been published, it just needs to be added to the main page. Check this link: https://code.vmware.com/apis/445

Update 15-10: I have received an overview from VMware about the other changes:

New API Endpoints:
ConnectionServer_GetTags
GlobalSettings_GetEnvironmentSettings
QueryService_DeleteByIds
Datastore_GetDatastoreRequirements
Datastore_ListDatastoresByDesktopOrFarm
RemoteApplication_EndApplication

There also have been some changes to some objects (MachineBase,AccessGroup etc) to include more properties

Original Article:

Today the latest version of PowerCLI was released with version 11.0.0. When you look at the release notes it’s obvious that some extra things have been added for the Horizon VIew API’s.

PowerCLI has been moving at quite the rapid pace over the last 2 years. In 2018, we’ve been releasing roughly every other month to make sure we get the latest features, performance improvements, and updates available as quickly as possible. Well, it’s been two months and we’re not going to break this trend. Today, we are releasing PowerCLI 11.0.0!

PowerCLI 11.0.0 comes with the following updates:

  • Added a new Security module
  • Added new cmdlets for Host Profiles
  • Added a new cmdlet to interact with NSX-T in VMware Cloud on AWS
  • Support for vSphere 6.7 Update 1
  • Support for NSX-T 2.3
  • Support for Horizon View 7.6
  • Support for vCloud Director 9.5
  • Multiplatform support for the Cloud module
  • Updated the Get-ErrorReport cmdlet
  • Removed the PCloud module
  • Removed the HA module

Even though Jake Robinson already gave me a heads up that this version was coming it’s always the question what has been added for Horizon View. According to the API explorer page no new querydefinitions have been added. Like last time I decided to compare the services against the old list and there are two new additions:

  • CategoryFolder
  • ResourceSettings

I have tried both against a Horizon 7.5 setup and they failed so these are only exposed from Horizon View 7.6 and up.

The first one called Categoryfolder is linked to the possibility to put rdsh applications into folders.

It currently has only one function:

I have also investigated if there was a way to change things using the helper function but sadly it has no .update api call so that’s a no-go. I currently have no rdsh on my lab so I can do the list but it doesn’t show anything.

The other new service is the .ResourceSettings just like categoryfolder it also only has one function:

For this one I can actually show what it’s used for:

It shows the general settings for forced logoffs.

Sadly this service also doesn’t show a way to change things.

Sadly I have no found no way yet to see what queryservice entity’s have been added so hopefully we will have a new API explorer soon (maybe with release notes this time, pretty please VMware?) that shows us all the new goods.

New View API query services in PowerCLI 10.1.1: pulling event information without the sql password.

A while back I already posted about new services that where available for the View API’s in PowerCLI 10.1.1. Recently the api explorer for this version was published and can be found here. Two things that I didn’t find back then was the addition of two services for the query service. The first is GlobalApplicationEntitlementInfo this one can be compared to the previously already available GlobalEntitlementSummaryView and will return information about global entitlements.

The second added services is extremely useful: you can now query the event database. This means you don’t need the actual sql password anymore to query the events. According to the api explorer at least Horizon 7.3 is required and only events from the Event and Event_Data database tables. A simple query will show all events.

$queryservice=new-object VMware.Hv.QueryServiceservice
$defn=new-object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'EventSummaryView'
$results=($queryservice.QueryService_Query($services1,$defn)).results
$results

As you can see the data is divided in data and namesdata properties, these contain the same data as what is returned with get-hvevent. I added some selections to show only one event.

$results | where {$_.data.eventtype -like "*BROKER_USERLOGGEDIN*"}  | select -last 1 | select -expandproperty data

and

$results | where {$_.data.eventtype -like "*BROKER_USERLOGGEDIN*"}  | select -last 1 | select -expandproperty namesdata

Offcourse it;s better to use filtering from the query directly. The full lust for that is available from the api explorer but I will give a couple of examples. (be aware that membername and the value are case sensitive)

$queryservice=new-object VMware.Hv.QueryServiceservice
$defn=new-object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'EventSummaryView'
$equalsFilter = New-Object VMware.Hv.QueryFilterEquals
$equalsFilter.membername='data.eventType'
$equalsFilter.value="BROKER_USERLOGGEDIN"
$defn.filter=$equalsFilter
($queryservice.QueryService_Query($services1,$defn)).results.data | select -last 1

Or by severity

$queryservice=new-object VMware.Hv.QueryServiceservice
$defn=new-object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'EventSummaryView'
$equalsFilter = New-Object VMware.Hv.QueryFilterEquals
$equalsFilter.membername='data.severity'
$equalsFilter.value="WARNING"
$defn.filter=$equalsFilter
($queryservice.QueryService_Query($services1,$defn)).results.data | select -last 1

As said it can be filtered on other properties as well but that might require some more logic to get the userid or desktopid for example. This is a very useful addition in my opinion to the Horizon View api’s.

My presentation at the vEUCtechcon 2018

Yesterday it was clear for me that more people are interested in what Dutch secret agents have to do with airwatch/workspace one uem then with PowerCLi for Horizon View. Nonetheless there where some people listening to my presentation and watching the ginormous slide deck filled with gif’s that I created. My personal experience was that it went ok but nothing more than that. Sadly using the vga cable didn’t help against the connection bugs all presenters where having during the entire day. Also I would have preferred to have a monitor in front of me so I could actually hear myself talking in that big room. Personal points for next time: I had a good storyline in my head in advance, that didn’t come out at all. Also I need to channel my personal energy onto stage, I have the feeling that wasn’t really visible. Aka I need to do some more energetic storytelling.

For the people interesting in the presentation it can be found HERE. There’s a video recorded that I will add to this post when it gets published. Luckily there where also a couple of tweets about my sessions so we do already have some pictures.