[HorizonAPI] Creating Entitlements

So last week I created a blog about gathering Horizon entitlements using the api’s. At the end I promised that my next blog post would be about creating entitlements and guess what: that’s this post 🙂

First a short explanation about what UserEntitlements actually are in Horizon. When you pull the entitlement info the base property has the needed information.

So in short an entitlement is a link between the userorgroup object id and a resource object id. The resource object can be: Application, Desktop, Global Application Entitlement, Global Desktop Entitlement and URLRedirection.

Let’s first grab the id’s that we need, I use 2 queries for that bur first I put the names of the group and the desktop in variables:

$groupname = "example_group"
$poolname = "pod01_pool01"

Than I create two objects called $group and $pool using queries.

$queryService = New-Object VMware.Hv.QueryServiceService
$defn = New-Object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'ADUserOrGroupSummaryView'
$defn.Filter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='base.name'; 'value' = "$groupname"}
$group= ($queryService.queryService_create($HVService, $defn)).results
$queryService.QueryService_DeleteAll($HVService)

$queryService = New-Object VMware.Hv.QueryServiceService
$defn = New-Object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'DesktopSummaryView'
$defn.Filter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='desktopSummaryData.displayName'; 'value' = "$Poolname"}
$pool= ($queryService.queryService_create($HVService, $defn)).results
$queryService.QueryService_DeleteAll($HVService)

Next we create the object to link them together.

$userentitlement= new-object VMware.Hv.UserEntitlementBase
$userentitlement.UserOrGroup = $group.id
$userentitlement.Resource = $pool.id

And we create the actual entitlement, since the output we get from this is the id of the entitlement object I store this in a variable to show you the entitlement in the next step.

and to show the entitlement

($hvservice.UserEntitlement.UserEntitlement_Get($newentitlement)).base

If you want to create entitlements for other resource you’ll need to use the either of the following to build your query:

Name Data object property to filter on
Application ApplicationInfo data.displayName
Desktop DesktopSummaryView DesktopSummaryData.displayName
Global Application Entitlement GlobalApplicationEntitlementInfo base.displayName
Global Desktop Entitlement GlobalEntitlementInfo base.displayName

There is no query for the URLRedirection so you’ll need to use URLRedirection.URLRedirection_List() to get the entire list and select the right one from that.

This is a complete example script that you could use to create a desktop entitlement:

Import-Module VMware.VimAutomation.HorizonView
Import-Module VMware.VimAutomation.Core

$cs = 'pod1cbr1.loft.lab'
$groupname = "example_group"
$poolname = "pod01_pool01"

$hvServer = Connect-HVServer -Server $cs 

$HVService= $hvServer1.ExtensionData

$queryService = New-Object VMware.Hv.QueryServiceService
$defn = New-Object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'ADUserOrGroupSummaryView'
$defn.Filter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='base.name'; 'value' = "$groupname"}
$group= ($queryService.queryService_create($HVService, $defn)).results
$queryService.QueryService_DeleteAll($HVService)

$queryService = New-Object VMware.Hv.QueryServiceService
$defn = New-Object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'DesktopSummaryView'
$defn.Filter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='desktopSummaryData.displayName'; 'value' = "$Poolname"}
$pool= ($queryService.queryService_create($HVService, $defn)).results
$queryService.QueryService_DeleteAll($HVService)

$userentitlement= new-object VMware.Hv.UserEntitlementBase
$userentitlement.UserOrGroup = $group.id
$userentitlement.Resource = $pool.id
$hvservice.UserEntitlement.UserEntitlement_Create($userentitlement)

[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)

 

New Horizon API explorer posted (new queries!)

While watching the VMworld US 2019 video of Sean Massey presenting about getting started with the Horizon API’s I decided to check if the API explorer has been updated. To my surprise it was and it is good to see that several queries have been added besides the method’s that I previously found.

The new queries that I found are:

  • DesktopAssignmentView
    • Description:
      • Desktop id + Desktop assignment data which will include desktop pool information, operation system, global entitlement.
  • DesktopHealthInfo
    • Description:
      • Desktop health Information. This data will be populated only for the desktops which support application remoting.
  • GlobalEntitlementSummaryView
    • Description:
      • Summary information about Global Entitlements.
  • MachineSummaryView
    • Description:
      • This View includes summary data of all entities related to this Machine

So the DesktopAssignmentView seems to give a lot of similar data to what the DesktopSummaryData query already gives. They both give global entitlement data plus user assignment data. The big difference is that it gives way more detailed information about the desktop pool itself like vGPU settings. The names should have been DesktopInfo in my opinion.

Desktophealthinfo is created for the new Windows 10 App remoting and the monitoring for that. The globalentitlementsummaryview and machinesummaryview are linked to GlobalEntitlementInfo and MachineDetailsView from which they give a subset of data.

I hope to have a new blog post soon with more detailed information of what the new method’s and queries will bring but I wanted to update you with the fact that the api explorer has been updated as soon as possible.

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

[API]How to successfully logoff users in Horizon

One of the things that annoy me about the Horizon admin interface is the fact that if you give a session the logoff command that this only works if the user is active aka when the desktop is not locked. With the api’s though (and Andrew implemented this in the helpdesk fling) it is possible to force a logoff. Let’s look at the available method’s first.

So we have a logoff and logoffForced. But there are also the logoffsessions and LofoffSessionsForced, I guess those let you logoff multiple sessions. this is what the extensiondata says about them.

So for the singular method’s we need a single id and for the sessions we need an array of ids. At first I will use get-hvglobalsession (yes, this works against sessions in other pod’s in a cloud pod architecture as well!) to get the id’s to show how it works. I have 5 sessions running from my desktop

$services1.Session.Session_Logoff((get-hvglobalsession | select -first 1).id)

Damn locked, let’s force this bastard from his desktop.

$services1.Session.Session_LogoffForced((get-hvglobalsession | select -first 1).id)

Aaaand it’s gone

And to show that it works I had to make sure the first session wasn’t locked.

And now the big bang fuck all of you!

$services1.Session.Session_LogoffSessionsForced((Get-HVGlobalSession).id)

As you can see one of my users was a but slow in logging off (nested esxi with only a couple vcpu’s for that one) I have also created a script that asks for the user whom you want to logoff and which session you want to logoff in case they have multiple. It’s not the cleanest code that I have written but it works 🙂

$hvserver1=connect-hvserver servername -user user -domain domain -password passwords
$Services1= $hvServer1.ExtensionData

$username= Read-Host "Which user do you want to logoff? (no wildcards needed, part of the name is enough)"

$queryService = New-Object VMware.Hv.QueryServiceService
$userdefn = New-Object VMware.Hv.QueryDefinition
$userdefn.queryEntityType = 'ADUserOrGroupSummaryView'
$userfilter1= New-Object VMware.Hv.QueryFilterContains
$userfilter1.membername='base.name'
$userfilter1.value=$username
$userfilter2= New-Object VMware.Hv.QueryFilterEquals
$userfilter2.membername='base.group'
$userfilter2.value=$False
$userfilter=new-object vmware.hv.QueryFilterAnd
[email protected]($userfilter1, $userfilter2)
$userdefn.filter=$userfilter
$users=($queryService.QueryService_Create($Services1, $userdefn)).results

$menu = @{}
for ($i=1;$i -le $users.count; $i++){ 
    Write-Host "$i. $($users[$i-1].base.name)" 
    $menu.Add($i,($users[$i-1].id))
}
[int]$ans = read-host "Please select the correct user"
$user=$menu.Item($ans)

$GlobalSessionQueryService = new-object VMware.Hv.GlobalSessionQueryServiceService
$sessionfilterspec=new-object vmware.hv.GlobalSessionQueryServiceQuerySpec
$sessionfilterspec.user=$user
$sessions=($GlobalSessionQueryService.GlobalSessionQueryService_QueryWithSpec($services1, $sessionfilterspec)).results

$menu = @{}
for ($i=1;$i -le $sessions.count; $i++){ 
    Write-Host "$i. $($sessions[$i-1].namesdata.basenames.MachineOrRDSServerName)" 
    $menu.Add($i,($sessions[$i-1].id))
}
[int]$ans = read-host "Please select the correct VDI Desktop"
$session=$menu.Item($ans)

$Services1.Session.Session_Logoffforced($session)
$queryService.QueryService_DeleteAll($services1)

This script forces the logoff for the sessions since I haven’t been able yet to find where the desktop status (locked or not) is visible.

Updates to the VMware Horizon Helpdesk fling

Today a new version has been released of the VMware Horizon Helpdesk fling by Andrew Morgan. One big change is that the Helpdesk license isn’t required anymore so at least a part of the functionality is available to owners of advanced or standard Horizon licenses.

the entire changelog:

Version 1.4.0.1

  • No longer requires a helpdesk license! Yay!
  • Added the ability to interact with vCenter machines
  • Added the ability to open vCenter VM consoles
  • Added the ability to perform bulk machine actions
  • Added the ability to perform refresh / recompose tasks directly from helpdesk.
  • Fixed performance issues with multiple windows open (see single instance).
  • Fixed a crash when logon durations could not be accessed.
  • Added polling to allow logon durations to be received if notavailable when the session page is requested.
  • Fixed a crash in the ending of processes.
  • Fixed a metric ton of bugs with delegated administration.
  • Fixed a memory leak in the tray icon menu, of all places.
  • Removed the logon page graphic as it was to much of a pain to change it’s colour when changing themes
  • Fixed some layout issues when changing themes.
  • Removed empty sites from the viewon the change pod tray menu.
  • Added preliminary support for Horizon 7.9.

 

Let’s look into some of the new options (will do the options without the helpdesk license last)

Added the ability to interact with vCenter machines 

From the pool view you’ll see an extra button for vCenter actions

And that will give these options

These all speak for themselves in functionality.

Added the ability to open vCenter VM consoles 

Open VM console will give an popup that asks for vCenter credentials.

Hit logon and a vrmc client should start if it’s installed

Added the ability to perform bulk machine actions 

The vCenter actions above can be done against multiple vm’s but also the various actions from View itself

Added the ability to perform refresh / recompose tasks directly from helpdesk. 

No longer requires a helpdesk license! Yay! 

when you use the std license the biggest difference is that you can’t view any specifics inside sessions since that’s all limited to the helpdesk license.

[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.

[API]Resetting Desktops

This is the first post in a series of shorts that I will be posting about various methods that you can use with the VMware Horizon API’s. This time it will be about resetting desktops. When looking at the API Explorer you’ll see that there are two ways do do this from the machine service.

So the first is for a single VDI desktop and the latter for multiple.

First we need to get a list of vm’s I will be using the machines in pod1pool02 as victims for this post.

$queryservice=new-object VMware.Hv.QueryServiceService
$defn=New-Object VMware.Hv.QueryDefinition
$defn.QueryEntityType="MachineNamesView"
$filter=new-object VMware.Hv.QueryFilterContains
$filter.MemberName='base.name'
$filter.Value="Pod1Pool2"
$defn.filter=$filter
$results=($queryservice.QueryService_Query($services1, $defn)).results

with this result:

From this we’ll make a variable with all of them and one with a single one

$singlevm=$results | select-object -first 1
$multiplevms=$results

Before I will reset the single VM I will show the state of all the vm’s.

($queryservice.QueryService_Query($services1, $defn)).results.base.basicstate

And now let’s reset the vm.

$services1.machine.machine_reset($singlevm.id)

Since this is an instant clone you’ll see provisioned and not reset. Now let’s reset the rest as well.

$services1.Machine.Machine_ResetMachines($multiplevms.id)

And this method will work for all managed vdi desktops full, linked or instant clones.