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:
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
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
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.
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.
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.
[sta_anchor id=”list” unsan=”List” /]
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).
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.
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.
[sta_anchor id=”list” /]
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.
[sta_anchor id=”create” /]
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)
[sta_anchor id=”get” /]
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.
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
[sta_anchor id=”delete” /]
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.
One of the new cmdlets for the vmware.hv.helper that I am currently working on is initiating the Cloud Pod Architecture (CPA) and more actions related to this. This blog post will show the basics about initiating, and joining a CPA using the API’s. Doing things with site’s within the CPA will be covered in a later blogpost.
If we look at the services available in the Horizon API’s you’ll see that podfederation is one of them, let’s take a look at that and what method’s are available.
$services1.PodFederation | gm
So we can Eject, Get, Initialize, Join, Unintialize, Unjoin and update a podfederation. If we look at the brackets behind the methods than (un)initializing and unjoin don’t need any extra info so let’s get ahead and initialize the podfederation. To show you there’s nothing there yet I made a screenshot of the admin interface.
Not a lot of information but there isn’t a lot more anyway in the podfederation itself.
[sta_anchor id=”join” /]
Join a federation
I have another pod that I want to join to this federation since we’ve already seen that this needs some more input let’s check what it exactly needs.
$Services1.PodFederation.PodFederation_join
So we need a remotepod address, presumable one of the connection servers in that pod will be enough, a username where domain\username will do just like in the admin console and a password of the type vmware.hv.securestring. The last one was new for me but thankfully it was described in one of the examples in the api explorer (https://code.vmware.com/apis/75/view and click on Data Object Types).
And again if you are fast enough this is also visible in the admin console
And now a get will also show that it has been enabled
[sta_anchor id=”unjoin” /]
Unjoining a Podfederation
If you are braking down a pod because of whatever reason the best way to do this is to unjoin the pod from the federation. As we saw before there’s no extra information need so you just need to connect to a connection server in that pod and do an unjoin.
$services1.PodFederation.PodFederation_Unjoin()
this is really fast so over several tries I did not succeed in making a screenshot of the admin console.
[sta_anchor id=”eject” unsan=”Eject” /]
Ejecting a pod
This is the only podfederation function not available through the admin console as far as I could see. Ejecting a pod for is for me a last option if a datacenter burned down, everything is gone and you want to get rid of the pod. I did it in my lab against an alive pod and had to uninitialize the (now unlinked) podfederation from that pod to be able to rejoin it to the correct pod. This method also requires some input so let’s see what that is.
$services1.PodFederation.PodFederation_Eject
So we need the podid of the pod to eject, this information can be get trough the pod service
$services1.pod.Pod_List()
I want to eject the pod from pod2cbr1
$pod=$services1.pod.Pod_List() | where {$_.displayname -like "*pod2cbr1*"}
and with $pod I can check if I have the correct one
No feedback, nothing but if we check the pod list it’s gone.
I will show how to remove the remnants in the uninitialize chapter.
[sta_anchor id=”update” /]
Updating a Pod Federation
This one sounds bigger then it is since there’s only one thing that we can update in a federation. To do this it is better to use the helper service then to use the podfederation_update method since that can get complicated very fast sometimes. To use the helper service we will need to create some variables first
After some trial and error I know we need to getdatahelper method to continue
This only show the updates that are currently in the queue to be applied with a get method it’s possible to see what can be set.
$podservicehelper.getDatahelper() | gm
What we need to look for is a set so the only options here are setdisplayname that needs a string value and setupdates that needs a load of information and that probably might also be a way to do it but I will use the setdisplayname.
$podservicehelper.getDatahelper().setdisplayname("Whatever name you like")
This will give no feedback and nothing will be changed yet, what needs to be done is to apply this update in the helper service to the service.
$podservice.update($services1, $podservicehelper)
and if you now do a get on the podfederation it will show the changed name.
[sta_anchor id=”Unintialize” /]
Uninitializing a Podfederation
To show the pod uninitialization step I will use the pod that I have ejected from the podfederation pod2cbr1. It is clear that it is a bit wonky if we look at the pod list from that connection server.
So it knows about the pod federation but doesn’t see itself in it anymore.
In this blogpost I showed how to assign a certain vdi machine to a user. This has been made easier since in the vmware.hv.helper module. These days we can use this:
This week I got the logical question from Brandon Smith in the comments about removing the assignment. First I need to re-assign the desktop (I have been building a VMUG presentation about PowerCLI & Horizon view so things got messed up)
the result:
Now what need to be done is setting the base.user to $null. I am going to do this by connecting to the machine service and utilize the machinehelper to update the userdata.
We now need to connect to the machinehelper by doing a read on the machineservice. $machineservice.read will give us the info we need to be able to do this.
From this it becomes clear that we will need the services service and the machineid we want to edit. First let’s put the machine id into a variable.
Since I know the user property is under the base we will need to get the base first and then set the user. This done by doing getbasehelper() on the machineinfohelper and then do .setuser(user) on that but let’s see what’s under the getbasehelper first.
$machineinfohelper.getbasehelper() | gm
A lot of information but as said the one we need is setuser. To assign a desktop we will need to set this to a userorgroupid value (and that is what the vmware.hv.helper cmdlet does). To clear it we will need to set it to $null.
$machineinfohelper.getbasehelper().setuser($null)
At this point no changes have been made yet! We will need to apply this update first.
In a previous post i mentioned that finding the entitlements for a user from the Horizon side of things can be a bit of a hassle. If only active directory groups are used its dead easy: just use the Active directory commands for those groups. If the groups are used for multiple pools and if you have assigned desktops things get a bit more complicated. For now I will only concentrate on the local pod without global entitlements.
getting that info
To get started the vmware.hv.helper module has the get-hventitlement command. As almost always a very useful one but it has some flaws. First it requires full domainname\username or username@fulldomainname.
For example
get-hventitlement -user magneet.lab\user1
or
get-hventitlement -user user1@magneet.lab
Both work but
get-hventitlement -user magneet\user1
gives this message: Get-HVEntitlement: No entitlements found with given search parameters.
At least
get-hventitlement -user user1
If you add the -type group to this command you get all group entitlements
gives an error message that the -user argument does not match the “^.+?[@\\].+?$” pattern. With this last one you at least get an error so you know where to look but not displaying any entitlements is an issue for me.
So, back to the results of these commands, I have assigned the user user1 the following rights
Pool04 directly and by using a group
directly on a single desktop in pool04.
Pool01 only by group.
Paint rds app by group
Calculator rds app direct
Wordpad rds app by both group & directly
When using the get-hventitlement without anything else it doesn’t seem to show a lot of usable things
get-hventitlement -user user1@magneet.lab
If you put this between brackets followed by a period and one of the properties a bit more info is shown.
(get-hventitlement -user user1@magneet.lab).base
Some information about the user, not very usable the session data property gives some information about current sessions (none at the moment)
With the localdata property it looks like we hit the motherload jackpot thingy
I read something about get-hvinternalname when checking out the module, sounds usable.
get-help get-hvinternalname -examples
Ah, so this needs an entityid as input, a machine is an entity so let’s try it. This might need a foreach though because the output gave machines and not machine.
foreach ($Entityid in ($entitledids.machines)){get-hvinternalname $Entityid}
Damn, that’s not usable, let’s double-check with the other id types
foreach ($Entityid in ($entitledids.desktops)){get-hvinternalname $entityid}
foreach ($Entityid in ($entitledids.desktopuserentitlements)){get-hvinternalname $entityid}
foreach ($Entityid in ($entitledids.aplicationuserentitlements)){get-hvinternalname $entityid}
foreach ($Entityid in ($entitledids.applications)){get-hvinternalname $entityid}
The ones we need are readable, couple of them not but I don’t those will be missed.
The missing machine name is actually easy to solve by doing an api call:
foreach ($Entityid in ($entitledids.machines)){($services1.machine.machine_Get($Entityid)).base}
Conclusion
Because this is rather easy to use and since I didn’t have a direct use case for that I decided not to create a complete script. With get-hventitlement, get-hvinternalname and maybe an api call here or there it’s very easy to pull the information about which account or groups have what rights. To see if a user belongs to a group can easily be done with any of the multitude of scripts for that here’s a good example of those.
So last week there where a couple of posts on vmtn about people wanting to automatically removing or refreshing faulty Horizon desktops. With faulty I mean desktops in Agent Unreachable or in error state or whatever status are available. Since this was something i had been investigating anyway I decided to make a script for it that had separate menu’s for the status the desktop needs to be and to pick the desktop to be deleted. The latter part can be rebuild to do all those desktops at once in case something breaks pretty badly during a recompose of the pool.
The largest part of the script is for creating the menu’s. Since the amount of returned desktops is variable and names differ it’s not possible to use a static menu. Instead I have used a menu structure created by Roman Gelman and that can be found inside this script on github. The part that gets things done i have listed below. The $spec array doesn’t need to be created but it is required in the API call to remove the desktop, Powershell assumes everything true by default when it’s empty but it just has to be called otherwise you will get a big fat red error. To remove multiple desktops at once machine_deletemachines needs to be used with an array filled with desktop id’s and $spec.
$spec = New-Object VMware.Hv.machinedeletespec
$spec.deleteFromDisk=$TRUE
$desktops=@()
$desktops=get-hvmachine -state $targetstate
$selectdesktop=@()
foreach ($desktop in $desktops){
$selectdesktop+= New-Object PSObject -Property @{"Name" = $desktop.base.name
"ID" = $desktop.id;
}
}
$selectdesktop=write-menu -menu ($desktops.base.name) -header "Select the desktop you want to remove"
$removedesktop=$desktops | where {$_.base.name -eq $selectdesktop}
try {
$services1.machine.machine_delete($removedesktop.id, $spec)
#$services1.machine.machine_reset($removedesktop.id, $spec)
write-host "$selectdesktop will be marked for deletion" -ForegroundColor Green
}
catch {
write-host "Error deleting $selectdesktop" -ForegroundColor Red
}
After the comment below I decided to create the script to delete all desktops in a certain state. It’s a variation of the script above, just a bit shorter. Again it can be found on Github. Please be aware that due to a limitation in get-hvmachine both these scripts will only handle 1000 desktops at a time. It is safe to just repeat the script to do the rest.
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here:
Cookie Policy