Recently I came up with the idea to create a script to apply new Golden Images against the various types of desktop pools and farms that we have in Horizon View. This was something that I thought was not available from the vmware.hv.helper module but after some research I did find that it it available from the module by using start-hvpool and start-hvfarm. No those are not the best names for the functions in my opinion. This wouldn’t stop me for creating this post though on how to apply the images using api’s only since the module uses mapentries and I still hate those. I will cover full clones and defining a new image without recomposing in a next post since that requires updating the pools.

Let’s take a look at the api explorer on what is needed to recompose or push an image.

The DesktopPushImageSpec for instant clones has a comparable setup with some nuance differences.

For RDS farms the linked clones spec is equal to the desktop spec but for instant clones there’s a rather big difference but I will cover that later on.

So the common steps for most types of applying the golden image are:

Selecting the Desktop Pool or RDS Farm

getting the id for the vcenter or datacenter where the parent VM lives

getting the id of the Parent VM

getting the id of the snapshot to use

getting the id’s of the machines in the desktop pool (Linked Clones only)

Select date & time for the recompose or imagepush (if required)

combine the above info into a spec to recompose or imagepush

Apply the recompose or ImagePush

Each step uses information from the step above it.

Selecting the Desktop Pool or RDS Farm

This can be done using queries. For desktops we user the desktopsummaryview definition and for farms farmsummaryview.

$poolname="pod02_LC" $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.name'; 'value'=$poolname} $desktoppool=($queryservice.QueryService_Create($services1, $defn)).results

And for a farm

$farmname="rds_IC" $queryservice=New-Object VMware.Hv.QueryServiceService $defn=new-object VMware.Hv.QueryDefinition $defn.QueryEntityType='FarmSummaryView' $defn.Filter= New-Object VMware.Hv.QueryFilterEquals -property @{'MemberName'='data.name'; 'value'=$farmname} $farm=($queryservice.QueryService_Create($services1, $defn)).results

getting the id for the vcenter or datacenter where the parent VM lives

For desktops this is a property of the $desktoppool object we have now

$desktopppoolvcenterid=$desktoppool.desktopsummarydata.VirtualCenter

For automated farms we need a small extra step since it is not property for the summary data we we can get it by doing a farm_get with the id we received from the query

$farmvcenterid=($services1.Farm.Farm_Get($farm.id)).automatedfarmdata.VirtualCenter

getting the id of the Parent VM

Using the vcenterid as done below we are able to list all vm’s in the vCenter that might be a Golden Image using

$services1.BaseImageVm.BaseImageVm_List($desktopppoolvcenterid)

You might be able to see it but this gives a list of all VM’s in the vCenter, sadly there is no query for this yet even though that would be really useful. If you know the exact name you can select on that but if you look at the IncompatibleReasons property there’s info to filter (if you want to create a menu for example)

$baseimagevmlist=$services1.BaseImageVm.BaseImageVm_List($desktopppoolvcenterid) $baseimagevmlist.IncompatibleReasons

InUseByDesktop is a usable one for instantclones. I don’t know why InUseByLinkedCloneDesktop doesn’t give any true values even though I have one pool with linked clones, viewcomposerreplica does work. I have filtered this on some of the more obvious ones and end up with both my golden images for Windows 7 & Server 2016

$baseimagevmlist |where {$_.IncompatibleReasons.InUseByDesktop -eq $false -and $_.IncompatibleReasons.InstantInternal -eq $false -and $_.IncompatibleReasons.ViewComposerReplica -eq $false}

I will do it easy and select on the name for now

$Desktopbaseimagevm=$baseimagevmlist | where {$_.name -eq "GI_H72"} $farmbaseimagevm=$baseimagevmlist | where {$_.name -eq "rds_template"}

getting the id of the snapshot to use

With the baseimagevmid we can utilize the baseimagesnapshot method to get the id for the snapshot.

$desktopsnapshotlist=$services1.BaseImageSnapshot.BaseImageSnapshot_List($Desktopbaseimagevm.id) $farmsnapshotlist=$services1.BaseImageSnapshot.BaseImageSnapshot_List($farmbaseimagevm.id)

In this there is also an IncompatibleReasons property but that doesn’t give a lot of information so we’ll need to filter on name.

$desktopLCsnapshot=$desktopsnapshotlist | where-object {$_.name -eq "gi_linked"} $desktopICsnapshot=$desktopsnapshotlist | where-object {$_.name -eq "snap_gi"} $farmsnapshot=$farmsnapshotlist | where-object {$_.name -eq "gi_rds_2016"}

getting the id’s of the machines in the desktop pool

As you’ll see later in the spec there’s a requirement to list the machine id’s for the pool if you want to do a recompose. These can be grabbed by doing a query

$queryService = New-Object VMware.Hv.QueryServiceService $defn = New-Object VMware.Hv.QueryDefinition $defn.queryEntityType = 'MachineSummaryView' $defn.filter=New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='base.desktop'; 'value'=$desktoppool.id} $QueryResults=$queryService.Queryservice_create($Services1, $defn) $desktopmachinelist=$queryresults.results

For Linked Clone RDS farms you ned to use the QueryEntityType of RDSServerSummaryView but since I don’t have those in my lab I can only show the theory

$queryService = New-Object VMware.Hv.QueryServiceService $defn = New-Object VMware.Hv.QueryDefinition $defn.queryEntityType = 'RDSServerSummaryView' $defn.filter=New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='base.desktop'; 'value'=$farm.id} $QueryResults=$queryService.Queryservice_create($Services1, $defn) $farmmachinelist=$queryresults.results

Settings date and time for the action

It’s not required to set a date and but is very usable if you want to schedule an action. Please be aware that this is based on us format for day and time so mm-dd-yyyy otherwise I would have scheduled it for august.

$datetime=[DateTime]"02-08-2019 10:00:00AM"

The [DateTime] converts the string that follows it to a variable of the type day and time

combine the above info into a spec to recompose or imagepush.

To build the spec we first need to declare a new object with new-object vmware.hv.DesktopRecomposeSpec please be aware that for this name you need to look at the data object in the API explorer and not the class.

$desktoprecomposespec=new-object vmware.hv.DesktopRecomposeSpec $desktoprecomposespec.ParentVm=$desktopbaseimagevm.id $desktoprecomposespec.Snapshot=$desktopLCsnapshot.id $desktoprecomposespec.StartTime=$datetime $desktoprecomposespec.LogoffSetting="WAIT_FOR_LOGOFF" $desktoprecomposespec.StopOnFirstError=$true $desktoprecomposespec.Machines=$desktopmachinelist.id

For the instant clone image push there’s an extra layer required for the settings

$desktopimagepushspec=new-object VMware.Hv.DesktopPushImageSpec $desktopimagepushspec.settings=new-object vmware.hv.DesktopPushImageSettings $desktopimagepushspec.ParentVm=$desktopbaseimagevm.id $desktopimagepushspec.snapshot=$desktopICsnapshot.id $desktopimagepushspec.settings.StartTime=$datetime $desktopimagepushspec.settings.LogoffSetting="WAIT_FOR_LOGOFF" $desktopimagepushspec.settings.StopOnFirstError=$true

The recompose for a linked clone rds farm is similar to the desktop linked clone.

$farmrecomposespec=new-object vmware.hv.farmRecomposeSpec $farmrecomposespec.ParentVm=$farmbaseimagevm.id $farmrecomposespec.Snapshot=$farmLCsnapshot.id $farmrecomposespec.StartTime=$datetime $farmrecomposespec.LogoffSetting="WAIT_FOR_LOGOFF" $farmrecomposespec.StopOnFirstError=$true $farmrecomposespec.Machines=$farmmachinelist.id

For RDS instant clone farms the pushing of a new image is part of the maintenance schedule that can be done immediate or recurring. I will do the recurring option for now since rds hosts needs to be refreshed every once in a while anyway. There’s some options inside the settings that are explained in the api explorer.

$farmmaintenancespec=new-object vmware.hv.FarmMaintenanceSpec $farmmaintenancespec.recurringMaintenanceSettings=new-object vmware.hv.FarmRecurringMaintenanceSettings $farmmaintenancespec.imageMaintenanceSettings=new-object vmware.hv.FarmImageMaintenanceSettings $farmmaintenancespec.maintenanceMode="RECURRING" $farmmaintenancespec.scheduledTime=$datetime $farmmaintenancespec.logoffsetting="WAIT_FOR_LOGOFF" $farmmaintenancespec.stopOnFirstError=$true $farmmaintenancespec.recurringMaintenanceSettings.startTime="23:00" $farmmaintenancespec.recurringMaintenanceSettings.maintenancePeriod="WEEKLY" $farmmaintenancespec.recurringMaintenanceSettings.startInt=1 $farmmaintenancespec.ImageMaintenanceSettings.parentVm=$farmbaseimagevm.id $farmmaintenancespec.ImageMaintenanceSettings.snapshot=$farmsnapshot.id

Apply the recompose or ImagePush

This is the easiest part of the spec’s have been build properly.

Please note that the variables for the pools I use are a bit different to show the linked and instant clone pools

$services1.Desktop.Desktop_Recompose($linkedclonepool.id, $desktoprecomposespec) $services1.Desktop.Desktop_SchedulePushImage($instantclonepool.id, $desktopimagepushspec) $services1.farm.Farm_ScheduleMaintenance($farm.id, $farmmaintenancespec)

No visible feedback but it’s visible from the admin console (sadly not all tasks can be gotten from the api’s yet 🙁 )

That’s it for now but expect future posts about full clones, setting a default image for linked clones without recompose and maybe a complete script that does it all for you.