Multi vlan Network for Horizon View using PowerCLI & API’s

One of the things I wanted to do for a while is to write an API version on how to use multiple dvSwitch portgroups with Horizon View linked clones. With instant clones there’s a gui way to select multiple portgroups but for instant clones the only was to do this was to use the View PowerCLI. This gets installed with the connection server and can only be used from there. What you do is create a file, edit and apply it. Johan has described this process very well on his blog. I decided there had to be a way to do this as well with ‘regular’ PowerCLI & the api’s.

The api explorer shows a property named networklabel for both desktop pools and rds farms. This entry showed me what data I needed to configure. I spent most of my time in gathering all the data for this. As you can see in the script I had to dig rather deep to get all information like hostorclusterid and snapshotid. This information then needs to be put into an object called nics.

The script I made is a working prove of concept and doesn’t contain logic about what portgroups to apply. It just grabs all portgroups that comply with a simple filter. It then grabs the id’s for those and configures them to use for the pool. The script grabs information using the snapshotid but in my testing it’s 100% safe to change snapshots or golden images after that, is just uses that information to know where to configure things.

Something I found during testing is that the maximum amount of labels is respected and spread over all port groups as long as there are labels available. If the system runs out of labels it will continue using only the last configured label! I have tested this on View 6.2 and 7.3.2 with vSphere 6.5 on both methods of configuring the portgroups.

This is the script, it asks for some required information at first. This way you don’t have to put a password in plain text in the script. You can see I have the maxlabeltype and enabled properties pre-configured as LIMITED and $true. If the maxlabeltype is UNLIMITED the composer would stop using any other labels configured after that one and if enabled would be $false that label wouldn’t be used at all..

#-------------------------------------------------
# Linked Clone Configure multiple vlan's
# This script is created to allow a Linked Clone
# Desktop pool to use multiple vlan's
#
# In the past only the 'old' View PowerCLI on the Connection
# broker could be used to accomplish this. Now it's possible 
# from any system running PowerCLI 6.5 or above.
#
# This version replaces all current settings!
# 
# Requires PowerCLI 6.5 or higher
#
# Feel free to use or alter in anyway but please remember the original creator :)
#
# Version 1.0
# 16-01-2018
# Created by: Wouter Kursten
# https://retouw.eu
# Twitter @Magneet_NL
#-------------------------------------------------

$hvservername=Read-host "Which Connection broker do you want to connect to?"
$domain=read-host "Please enter your active directory domain?"
$username=Read-host "Please enter your useraccount"
$password=Read-host -assecurestring "Please enter your password"
$poolname=read-host "What pool to configure?"
$labelfilter=Read-host "What portgroups do you wnat to configure (use * as wildcard i.e. DVVDI*)"
$maxlabels=read-host "How many labels to configure per portgroup?"

#Connect to View Connection broker
Import-module vmware.hv.helper
write-host "Connecting to the connection broker" -ForegroundColor Green
try {
	$hvserver1=connect-hvserver $hvservername -domain $domain -username $username -password $password -WarningAction silentlyContinue -erroraction stop
	$Services1= $hvServer1.ExtensionData
}
catch {
	Write-host "Can't connect to the Connection server please check the credentials." -ForegroundColor Red
	exit
}
$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}
try     {
        $poolid=($queryService.queryservice_create($Services1, $defn)).results
        }
catch   { 
        throw "Can't find $poolname, exiting" 
        }

$pool=$Services1.Desktop.desktop_get($poolid.id)
$networklabelsall=$services1.networklabel.NetworkLabel_ListByHostOrCluster($pool.AutomatedDesktopData.VirtualCenterProvisioningSettings.VirtualCenterProvisioningData.hostorcluster)
$networklabels=$networklabelsall | where-object {$_.data.name -like $labelfilter}
$NetworkInterfaceCard=$services1.NetworkInterfaceCard.NetworkInterfaceCard_ListBySnapshot($pool.AutomatedDesktopData.VirtualCenterProvisioningSettings.VirtualCenterProvisioningData.snapshot)
$NetworkInterfaceCardSettings=new-object vmware.hv.desktopNetworkInterfaceCardSettings
$NetworkInterfaceCardSettings.nic=$NetworkInterfaceCard.id
$networkLabelAssignmentSpecs=@()

foreach ($networklabel in $networklabels){
    $NetworkLabelAssignmentSpec=new-object VMware.Hv.desktopNetworkLabelAssignmentSpec
    $NetworkLabelAssignmentSpec.enabled=$True
    $NetworkLabelAssignmentSpec.networklabel=$networklabel.id
    $NetworkLabelAssignmentSpec.maxlabeltype="LIMITED"
    $NetworkLabelAssignmentSpec.MaxLabel=$maxlabels
    $networkLabelAssignmentSpecs+=$networkLabelAssignmentSpec
    }
$NetworkInterfaceCardSettings.networkLabelAssignmentSpecs=$networkLabelAssignmentSpecs

$VirtualCenterNetworkingSettings=@()
$VirtualCenterNetworkingSettings=new-object vmware.hv.DesktopVirtualCenterNetworkingSettings
$VirtualCenterNetworkingSettings.nics+=$NetworkInterfaceCardSettings

$desktopService = New-Object VMware.Hv.DesktopService
$desktopInfoHelper = $desktopService.read($services1, $Pool.Id)
$desktopinfohelper.getAutomatedDesktopDataHelper().getVirtualCenterProvisioningSettingsHelper().setVirtualCenterNetworkingSettingsHelper($VirtualCenterNetworkingSettings)
$desktopservice.update($services1, $desktopInfoHelper)

I used a lot of variables and arrays with the names as they are pulled from the data, that explains their long names. Afterwards it doesn’t give any feedback. For this I created a separate script so you can separately check what is configured before or after you change the configuration:

#-------------------------------------------------
# Linked Clone get vlan configuration
# This script is created to check if a linked clone pool 
# has any configured vlan/portgroup configuration
#
# Requires PowerCLI 6.5 or higher 
#
# Feel free to use or alter in anyway but please remember the original creator :)
#
# Version 1.0
# 16-01-2018
# Created by: Wouter Kursten
# https://retouw.eu
# Twitter @Magneet_NL
#-------------------------------------------------

#region variables
$hvservername=Read-host "Which Connection broker do you want to connect to?"
$domain=read-host "Please enter your active directory domain?"
$username=Read-host "Please enter your useraccount"
$password=Read-host -assecurestring "Please enter your password"
$poolname=read-host "What pool to check?"

#endregion

#region Connect to View Connection broker
Import-module vmware.hv.helper
write-host "Connecting to the connection broker" -ForegroundColor Green
try{
    $hvserver1=connect-hvserver $hvservername -domain $domain -username $username -password $password -WarningAction silentlyContinue -erroraction stop
    $Services1= $hvServer1.ExtensionData
}
catch{
    Write-host "Can't connect to the Connection server please check the credentials." -ForegroundColor Red
    exit
}
    
#endregion

#regio gather and display data
$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}
try     {
        $poolid=($queryService.queryservice_create($Services1, $defn)).results
        }
catch   { 
        throw "Can't find $poolname, exiting" 
        }

$pool=$Services1.Desktop.desktop_get($poolid.id)
$labels=($pool.automateddesktopdata.virtualcenterprovisioningsettings.VirtualCenterNetworkingSettings.nics).NetworkLabelAssignmentSpecs
if (!$labels){
    write-output "No configured portgroup(s) or $poolname not found."
}
else{
    $output=@()
    foreach ($label in $labels){
        $output+= New-Object PSObject -Property @{
            "Labelname" = get-hvinternalname $label.networklabel;
            "Enabled" = $label.Enabled;
            "Labeltype" = $label.maxlabeltype;
            "Max_labelcount" = $label.maxlabel;
        }
    }
$output | select-object Labelname,Labeltype,Max_labelcount,enabled
}

And the result:

In the end the script looks and is way more complex than the ‘old’ way to assign multiple vlans. On the other hand it is way more flexible to use in any scripting you are already using for the automation of your Horizon environment.

As always both scripts can be found on Github here and here.