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.

New Horizon API calls in PowerCLI 10.1.1

VMware quietly released a new version of PowerCLI last week: 10.1.1. This release is mainly an update for the Horizon View API’s. This to bring it back on level with the current Horizon release at 7.5. The release notes are not very extensive but it has a fix for some people getting time-outs when connecting to a Connection server  plus a bunch of new api calls.

I have dumped the output from the available api calls into two text files and made a comparison:

Since there’s no update yet in the API explorer I will have to make an educated guess on what the functions do:

DesktopTask

When looking at the available method’s for this call it looks like it has everything to do with Desktop task. But it also can’t do a damn thing without an vmware.hv.desktoptaskid. This will most probably bu retrievable using a query. This is something I will further investigate in the future.

DiagOperation

To be honest I have no idea yet what this one does. I have tried created a VMware.Hv.DiagOperationRequest and tried to send it but got an error that no message queue handler was found. This might be something from Horizon 7.5 since I haven’t updated my lab yet.

GatewayAccessUserOrGroup

This one is easy, it creates, deletes, gets and lists remote access users. You can expect a function for this in the near future since it looks easy to build.

JwtToken

According to my sources this is a SSO token between the flex and html5 clients.

LogonTiming

This obviously is created to pull logon timing as the name suggests. I have put a session ID in a variable but sadly the data is not usable from PowerCLI. WHat it seems to be is the api call the Helpdesk client uses to pull the logon time. I didn’t have the timing profiler turned on initially and neither the helpdesk tool or this call gave my any information. Disconnected sessions also don’t give any information and when reconnected it gives the reconnection time not the initial logontime for when the session started. This is the same behaviour as the helpdesk tool.

Apparently the output is in a json format and for now I doubt if it will be usable in a function.

While the session itself has this information.

NetworkProxyConfiguration

No idea yet why there is a networkproxy configuration in here.

Performance

This gets some performance data using a session id as also visible in the helpdesk tool.

RemoteApplication

Gives per session information on the Skype 4 Business pairing mode.

RemoteAssistantTicket

100% sure related to the remote assistance function in the helpdesk tool.

RemoteProcess

Looks like this one gets some information from a query and then kills the process, will have to dig into it some further later on. This for sure is a function in the helpdesk tool.

ViewClient

Again from the helpdesktool, this gives the client version of a session.

Conclusion

For now I only see the DesktopTask and GatewayAccessUserOrGroup ending up in a function in the vmware.hv.helper. The first one will need some digging on how it exactly works but it has the looks of a usable call. The latter on can be in there pretty fast if I find the time to do so. The other ones

 

Update

Already received some extra information about some calls.

New experimental functions for the vmware.hv.helper on github

While working on my presentation for the 2nd vEUCtechcon event in Utrecht (The Netherlands) on may 28th I have added a list of new functions to the vmware.hv.helper module. While I haven’t had the time yet to clean them up to be proper coded scripts I have decided to already publish them on Github. All of them work but might be missing a feature or two and almost all of them are get-hv* or new-hv* type functions. Since the presentation is all about building an environment I have decided to build the remove parts later on. You might have already seen some screenshots on twitter recently:

Added functions that are not in the official module yet:

  • register-hvvirtualcenter
  • set-hveventdatabase
  • set-hvlicense
  • get-hvlicense
  • new-hvinstantcloneadministrator
  • New-HVRole
  • Get-HVRole
  • Get-HVpermission
  • New-HVPermission
  • Get-HVVirtualcenter
  • Get-HVInstantCloneAdministrator
  • Get-HVPod
  • Set-HVPod
  • Get-HVHomeSite
  • New-HVHomeSite

 

Registering an Instantclone administrator using PowerCLI

Another question Sean Massey asked me if it is possible to register an instant clone domain administrator. This is possible using the instantcloneenginedomainadministrator service with the InstantCloneEngineDomainAdministrator_create method. This needs a spec with the following content:

  • spec (vmware.hv.InstantCloneEngineDomainAdministratorSpec)
    • base (vmware.hv.InstantCloneEngineDomainAdministratorBase)
      • username (string)
      • domain (domainid)
      • password(vmware.hv.securestring)

The password can be created using the same scriptlet I used to register a new vCenter server. The domain ID can actually be gotten by listing all domains using

$services1.ADDomain.addomain_list()

For now I have created a scripts that requires you to give some details so it can register the instant clone domain administrator. It can also be found on Github but I will also definitively add it to the vmware.hv.helper module.

$icausername=read-host "What username to use for instantclone administrator?"
$icadomain=read-host "please give the dns name for the domain to user (i.e. domain.com)"
$icapassword=read-host "vCenter User password?" -assecurestring
$temppw = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($icaPassword)
$PlainicaPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($temppw)
$icadminPassword = New-Object VMware.Hv.SecureString
$enc = [system.Text.Encoding]::UTF8
$icadminPassword.Utf8String = $enc.GetBytes($PlainicaPassword)
$spec=new-object vmware.hv.InstantCloneEngineDomainAdministratorSpec
$spec.base=new-object vmware.hv.InstantCloneEngineDomainAdministratorBase
$spec.base.domain=(($services1.ADDomain.addomain_list() | where {$_.DnsName -eq $icadomain} | select-object -first 1).id)
$spec.base.username=$icausername
$spec.base.password=$icadminpassword
$services1.InstantCloneEngineDomainAdministrator.InstantCloneEngineDomainAdministrator_Create($spec)

Honoured to be named VMware EUC Champion 2018

You might have seen the announcement on the VMware EUC blog, Twitter or the new EUC Champions page already but I have been named one of the VMware End-User Computing (EUC) Champions for 2018. It is an honour to be awarded this status that only a select few receive each year. For me it feels like a true recognition for the work I have been doing with the Horizon API’s and my activity in the broader (EUC) vCommunity.

What is the EUC Champions Program?

EUC Champions is an experts-only program designed to provide a forum where the end-user computing community and VMware EUC product groups come together and share new product information and ideas through in-person meetings, networking events, industry conferences and webinars. This interaction helps ensure VMware EUC experts receive the most up-to-date information, and VMware product teams hear from industry veterans.

Thought leadership is easier said than done. It takes hard work and an ear to the ground to stay on top of industry trends. Many of our 2018 VMware EUC Champions have been thought leaders for decades, while others are rapidly becoming the go-to experts in their respective area. Whether new or returning, this year’s champions are among the ranks of end-user computing experts, who have done the work, made the commitment and signed up for more of the same in 2018.

What are the requirements to become an EUC Champion?

Not everyone is cut out to be an EUC Champion. It takes deep VMware EUC product expertise, an ability to write about it, a willingness to voice your opinion and the talent to clearly and concisely communicate ideas. EUC Champions are respected by their peers and, most importantly, are respectful of others.

Specifically, we look for candidates that meet the following criteria:

  • Member of the vExpert Program
  • Recognized EUC expert
  • Well regarded member of the greater EUC community
  • Recommended group member

Who are the 2018 EUC Champions?

On the new page there is a nice overview of all 34 EUC Champions

https://www.vmware.com/euc-champions/current-champions.html

Pulling horizon session information using PowerCLI

I should’ve already posted a blog about this but better late then never. At the end of february I posted about several new functions being added to the vmware.hv.helper and two out of three where about pulling session information. Recently I received some questions about using those since it’s the raw data being returned. For my Dutch vmug presentation I used several gif’s that showed what you can do with that data. I might need to update the cmdlets so all information will be shown at once but that’s for another time since it might slow down the cmdlet a lot and I don’t like that.

Usage

Since get-hvglobalsession and get-hvlocalsession show almost similar data I will only show the latter one.

get-hvglocalsession

As you see this only shows the methods contained inside the session. We can show the content by pipelining it to  select-object -expandproperty but I prefer the bracket method since these might go several layers deep.

(get-hvlocalsession).namesdata

Some of the returned values are logical like the username, machineorrdsservername. The desktop name though is the actual desktop pool the user is connected to. Desktoptype can be Automated, Manual or RDS depending on the type of desktop and Desktopsource can be Virtual_Center (VM’s hosted on vCenter but not managed by Horizon or Full Clone desktops), View_Composer(when using Linked Clones), Instant_Clone_engine (when using Instant Clones), Unmanaged (physical machines, non-vCenter vm’s) or RDS (Terminal Servers). Farmname will be used when it’s an RDS session. The Securitygateway will show the Connection Server the user connected to or the UAG/Security server used.

the same can be done with referencedata and sessiondata

(get-hvlocalsession).referencedata
(get-hvlocalsession).sessiondata

Not a lot of directly usefull information but a bunch of id’s that you might be able to use with the api’s if needed.

A lot of information about the session itself.

The actual code

The get-hvglobalsession actually is a query repeated for all pods. First it connects to the query service and then creates a query to run against each pod and add that to a sessionlist.

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

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

}
return $sessionlist
} 

The get-hvlocalsession is almost the same, it just doesn’t need to foreach since it doesn’t have multiple pods to query.

 $query_service_helper = New-Object VMware.Hv.QueryServiceService
  $query = New-Object VMware.Hv.QueryDefinition

  $query.queryEntityType = 'SessionLocalSummaryView'
  $SessionList = @()
  $GetNext = $false
  $queryResults = $query_service_helper.QueryService_Create($services, $query)
  do {
    if ($GetNext) { $queryResults = $query_service_helper.QueryService_GetNext($services, $queryResults.id) }
    $SessionList += $queryResults.results
    $GetNext = $true
  } 
  while ($queryResults.remainingCount -gt 0)
    $query_service_helper.QueryService_Delete($services, $queryResults.id)
  

  return $sessionlist
  [System.gc]::collect()
} 

In both there is a do while because otherwise it will run into some restrictions about maximum amount of data to return.

Adding vCenter server to Horizon View using the api’s

Yesterday Sean Massey (https://thevirtualhorizon.com/) asked me if it was possible to add a vCenter server + some other things to Horizon View using the api’s. With a quick look at the api explorer I confirmed this should be possible. The other things he asked I will put in a separate blogpost.

It looks like a simple matter of building the spec and I should be good. In the end it turned out to be a bit more work then expected. Some items are not required according to the api explorer but should at least be called in the spec (set them to something empty) while others can safely be left away. The automatic generated ssl certs in my lab also turned out to be a pita. First I copied them from a current spec and later I downloaded the certificate on the Connection server itself and read that cert. Andrew Morgan (http://andrewmorgan.ie/)from VMware helped me out with this by showing their internal script that they use. It turned out that except for the SSL certs I was on the right path. As usual I will add this functionality to the vmware.hv.helper but since that might take a while I decided to create a useful script

$hvServer = $global:DefaultHVServers[0]
$services=  $hvServer.ExtensionData

# Create required objects

$spec=new-object VMware.Hv.VirtualCenterSpec
$spec.serverspec=new-object vmware.hv.serverspec
$spec.viewComposerData=new-object VMware.Hv.virtualcenterViewComposerData

$spec.Certificateoverride=new-object vmware.hv.CertificateThumbprint
$spec.limits=new-object VMware.Hv.VirtualCenterConcurrentOperationLimits
$spec.storageAcceleratorData=new-object VMware.Hv.virtualcenterStorageAcceleratorData

# vCenter Server specs

$spec.ServerSpec.servername="pod2vcr1.magneet.lab"        # Required, fqdn for the vCenter server
$spec.ServerSpec.port=443                                 # Required
$spec.ServerSpec.usessl=$true                             # Required
$spec.ServerSpec.username="[email protected]"   # Required [email protected]
$vcpassword=read-host "vCenter User password?" -assecurestring
$temppw = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($vcPassword)
$PlainvcPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($temppw)
$vcencPassword = New-Object VMware.Hv.SecureString
$enc = [system.Text.Encoding]::UTF8
$vcencPassword.Utf8String = $enc.GetBytes($PlainvcPassword)
$spec.ServerSpec.password=$vcencPassword
$spec.ServerSpec.servertype="VIRTUAL_CENTER"

# Description & Displayname, neither is required to be set

#$spec.description="description"              # Not Required
#$spec.displayname="virtualcenterdisplayname" # Not Required

$spec.CertificateOverride=($services.Certificate.Certificate_Validate($spec.serverspec)).thumbprint


# Limits
# Only change when you want to change the default values. It is required to set these in the spec

$spec.limits.vcProvisioningLimit=20
$spec.Limits.VcPowerOperationsLimit=50
$spec.limits.ViewComposerProvisioningLimit=12
$spec.Limits.ViewComposerMaintenanceLimit=20
$spec.Limits.InstantCloneEngineProvisioningLimit=20

# Storage Accelerator data

$spec.StorageAcceleratorData.enabled=$false
#$spec.StorageAcceleratorData.DefaultCacheSizeMB=1024   # Not Required

# Cmposer
# most can be left empty but they need to be set otherwise you'll get a xml error

$spec.ViewComposerData.viewcomposertype="DISABLED"  # DISABLED for none, LOCAL_TO_VC for installed with the vcenter and STANDALONE for s standalone composer


if ($spec.ViewComposerData.viewcomposertype -ne "DISABLED"){
  $spec.ViewComposerData.ServerSpec=new-object vmware.hv.serverspec
$spec.ViewComposerData.CertificateOverride=new-object VMware.Hv.CertificateThumbprint
  $cmppassword=read-host "Composer user password?" -assecurestring
  $temppw = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($cmpPassword)
  $PlaincmpPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($temppw)
  $cmpencPassword = New-Object VMware.Hv.SecureString
  $enc = [system.Text.Encoding]::UTF8
  $cmpencPassword.Utf8String = $enc.GetBytes($PlainvcPassword)
  $spec.ViewComposerData.ServerSpec.password=$cmpencPassword
  $spec.ViewComposerData.ServerSpec.servername="pod2cmp1.magneet.lab"
  $spec.ViewComposerData.ServerSpec.port=18443
  $spec.ViewComposerData.ServerSpec.usessl=$true
  $spec.ViewComposerData.ServerSpec.username="[email protected]"
  $spec.ViewComposerData.ServerSpec.servertype="VIEW_COMPOSER"
  
  $spec.ViewComposerData.CertificateOverride=($services.Certificate.Certificate_Validate($spec.ViewComposerData.ServerSpec)).thumbprint    
  
}


# Disk reclamation, this is required to be set to either $false or $true
$spec.SeSparseReclamationEnabled=$false 

# This will create the connection
$services.VirtualCenter.VirtualCenter_Create($spec)

Looking at the output it will only ask for the vCenter user’s password and if a Composer server is set for that user’s password.

 

Added functions in vmware.hv.helper

Last Saturday I created a pull request to add some new functionality to the VMware.hv.helper. Together with an older PR that was still open it received an okay on Sunday. This is a list of the functionality I have added:

  • Get-HVHealth
    • Shows the health information for the following services:
      • ADDomain
      • CertificateSSOConnector
      • ConnectionServer,EventDatabase
      • SAMLAuthenticator
      • SecurityServer
      • ViewComposer
      • VirtualCenter
      • Pod
  • new-hvpodfederation
    • Initiates the Cloud Pod Architecture.
  • remove-hvpodfederation
    • Uninitiates the Cloud Pod Architecture.
  • get-hvpodfederation
    • Shows information about the Cloud Pod Architecture.
  • register-hvpod
    • Registers a new pod in the Cloud Pod Architecture.
  • unregister-hvpod
    • Removes a pod from the Cloud Pod Architecture. This can either be gracefully or forced.
  • set-hvpodfederation
    • Sets the name of the Cloud Pod Architecture.
  • get-hvsite
    • Retrieves information about all sites in the Cloud Pod Architecture.
  • new-hvsite
    • Creates a new site in the Cloud Pod Architecture.
  • set-hvsite
    • Sets site properties within the Cloud Pod Architecture.
  • remove-hvsite
    • Removes a site from the Cloud Pod Architecture.

The next functionality on my list is to put the pod service methods from this previous post into functions.

Managing Pods in a Horizon View Cloud Pod Environment using PowerCLI & Api’s

After Pod Federations and Sites it is time to manage the actual pods. Let’s take a look at what we can do.

$services1.pod | gm

Looks like a short post to me since there’s onl Get, List and Update

Pod_Get

Just like with site’s the get can be used in conjunction with a podid that might be gotten from somewhere else

$services1.pod.pod_get((($services1.site.site_list()).pods | select -first 1))

This selects the first podid listed when pulling all the pods from all sites and gets the information about that pod. We’ll see the same information when doing a list but just with all pod’s listed.

Pod_List

$services1.pod.pod_list()

Those endpoints are the connection servers in the pod. Let’s take a short detour and get the listing for one of those (the podendpoint service only has list and get so you will not see them separately anyway).

$services1.PodEndpoint.PodEndpoint_Get((($services1.pod.pod_list() | select -first 1).endpoints | select -first 1))

It might look lazy to use the select -first one and yes it is a bit but doing  a foreach to explain things also doesn’t really work in my opinion.

Pod_Update

Standard by now, first we need to connect to the podservice.

$podservice=new-object vmware.hv.podservice
$podhelper=$podservice.read($services1, ($services1.pod.pod_list() | select -first 1).id)

Under $podhelper we can already see how to set things.

$podhelper | gm

Let’s update  the easy things.

$podhelper.setdescription("This is a new description")
$podhelper.setDisplayName("This is a new name")
$podservice.update($services1, $podhelper)
$services1.pod.pod_list()

As a result we have updated the name and description of the pod. The other thing we can do is assign the pod to another site. Thankfully I already have two of those created.

$services1.site.site_list()
$siteid=$services1.site.site_list() | select -first 1

$podhelper.setsite($siteid.id)
$podservice.update($services1, $podhelper)
($services1.pod.pod_list()).site
$services1.site.site_list()

Both the lists aren’t required but I added them to show that the pods are spread over both pods now.

 

Creating and managing Sites in a Horizon View Cloud Pod Environment using PowerCLI & Api’s

Intro

Like I said in my previous post about Pod Federations this is a separate post that will show how to handle Sites within a Pod Federation. There are only a couple of API calls that do not include assigning a pod to a site. This is done trough the podservice which I will post about in a next blog post.

Let’s take a look at the site service to see what it actually has in api call’s

$services1.site | gm

So we have Site_create, Site_delete, site_get, site_list and site_update. To Make it myself easy I will use the order of List, create, get, update and delete.

Site_list

With site_list a list of all available site’s will be created, currently I have only one so let’s show that one.

$services1.site.site_list()

Note a lot of information is shown so let’s take a look at the contents of base and pods.

($services1.site.site_list()).base

($services1.site.site_list()).pods

so again not a lot of information since it only contains a name, description and the pod id’s of the member pods.

Site_Create

Since we already saw in the methods under the siteservice that the create needs a bit more information then just a name let’s take a look again at what is required.

$services1.site.site_create

An object is needed of the type vmware.hv.sitebase, we will need to take a look in the API explorer to see what this object should contain. Under Site_create we can click on sitebase.

The sitebase object has 2 properties of which only DisplayName is required. I have tried various ways to keep the description empty but haven’t succeeded so far and with it it the create also doesn’t work so how optional is it?

Let’s create the sitebase object

$sitebase=new-object vmware.hv.sitebase
$sitebase.displayname="blogpostdemosite"
$sitebase.description="This is a blog demo site"
$sitebase

The $sitebase is not required but shows what the object contains. Now we have enough to create the new site.

$services1.site.site_create($sitebase)

Site_Get

In the overview we have seen that a site_get needs a bit more information.

$services1.site.site_get

We already know how to get this site id by using site_list, normally you would only use the site_get with an id received from another service like the pod service. For the example I will use the demo site I create in the site_create part of this post.

First I will need to get the siteid

$demosite=$services1.site.site_list() | where-object {$_.base.displayname -like "*blogpostdemosite*"}

And now we need to apply that to the site_get

$services1.site.site_get($demosite.id)

Site_Update

As said before for an update method it is better to use the helper service for that service.

$siteservice=new-object vmware.hv.siteservice

now what method’s do we see?

$siteservice | gm

To see the difference between the sitebasehelper and siteinfohelper I will create both objects.

$siteinfohelper=$siteservice.read($services1, $demosite.id)
$sitebasehelper=$siteservice.read($services1, $demosite.id)

Now let’s compare them.

$sitebasehelper | gm
$siteinfohelper | gm

 

This is again one of those wtf moments, they both do exactly the same! I will use the sitebasehelper for now will update both the Displayname and description. For this I will need to use the getbasehelper 1 step deeper

$sitebasehelper.getbasehelper() | gm

$sitebasehelper.getbasehelper().setDisplayname("thissitecanberemoved")
$sitebasehelper.getbasehelper().setDescription("yes it can really be removed")

and apply the update, since neither will generate a response I won’t put any screenshots in.

$siteservice.update($services1, $sitebasehelper)

Now let’s see the result for a site_get for this site now

Site_Delete

We can take a look at it but to delete a site we only need the siteid so let’s remove that site we gave an update.

$services1.site.Site_Delete($demosite.id)

again no visual feedback but if we do a sitelist there’s only one left.