«

»

PoSh automation for Horizon View manual pools

Automation is system administrator’s best friend. Automating repetitive tasks is a key enabler in most IT environments. Whilst many of the desktop pool administrative tasks in Horizon View can be made via PowerShell, not all objects are exposed.

The POSH scripts below were created by VMware’s Jedi Master Engineer Mike Pryor and they allow administrators to manage a Horizon View Manual Pool via PoSh, providing methods to add and remove desktops.

Due to the way this script edits pool entries in the ADAM datbase, it is not safe for multiple changes via Add-ManualPoolVm, Remove-ManualPoolVm or Move-ManualPoolVm to be performed on the same pool at the same time, as the changes to the pae-MemberDN attribute on the pool may overlap and another recent change may be lost.

Please also note that the change will take up to a minute to take effect on the Connection Server, as the next full LDAP poll loop must fire for VM pool membership changes to be recognized.

 

Warning – The instructions, steps and scripts provided and outlined in this article are TOTALLY UNSUPPORTED BY VMWARE. I recommend testing in test & dev environment. If you decide to test or implement the solution you are doing it on your own risk.

 

Usage (Ensure you have loaded the Horizon View PowerCLI cmdlets):

  • Add-ManualPoolVm -pool <existing_poolid> -vm <vmname>
  • Remove-ManualPoolVm -pool <existing_poolid> -vm <vmname>

 

AddRemovePoolVms.ps1

[css lang=”plain” autolinks=”false” classname=”myclass” collapse=”false” firstline=”1″ padlinenumbers=”false” gutter=”true” smarttabs=”true” toolbar=”true” language=”true”]
<# .SYNOPSIS Get a View Pool object for a manual VC-managed pool. .DESCRIPTION Returns a manual Pool object or throws an exception, use for input validation .PARAMETER pool The pool’s ID string to use, alternatively can accept an existing Pool object to validate it’s a manual VC-managed type. #>
function Get-ManualPool
{
param ($pool = $(Read-Host -prompt "Pool ID"))

if ($pool.GetType().Name -eq "String") {
# treat a string as a pool_id, get Pool object
$pool = Get-Pool -pool_id $pool
if ($pool -eq $null) {
Throw "Pool not found"
}
}
if ($pool.GetType().Name -ne "Pool") {
Throw "Pool is of unknown type: " + $pool.GetType()
}
if ($pool.deliveryModel -ne "Manual") {
Throw "Pool must be manual"
}
if ($pool.vcServerName -eq $null) {
Throw "Pool must be VC managed"
}
return $pool
}

<# .SYNOPSIS Get a View DesktopVM object for use in a manual VC-managed pool. .DESCRIPTION Return a DesktopVM instance for the specified VM .PARAMETER vm The VM’s ID string to use, alternatively can accept an existing DesktopVM object to validate it’s of the correct type. .PARAMETER vc_id The GUID representing the vCenter instance to filter by. .PARAMETER in_pool Whether the VM is expected to be in an existing pool or not. #>
function Get-ManualPoolVm
{
param ( $vm = $(Read-Host -prompt "VM name"),
[String] $vc_id = $(Read-Host -prompt "VC guid"),
[Boolean] $in_pool = $false)

# need VC guid only
if ($vc_id.GetType().Name -eq "ViewVC") {
$vc_id = $vc_id.vc_id
}

# make sure we have a valid VM
if ($vm.GetType().Name -eq "String") {
# treat string as VM name, we can filter by VC matching $pool
$vm = Get-DesktopVM -vc_id $vc_id -name $vm
if ($vm -eq $null) {
Throw "VM not found"
}
}
if ($vm.GetType().Name -ne "DesktopVM") {
Throw "VM is of unknown type: " + $vm.GetType()
}
if ($vm.isInPool -ne $in_pool) {
Throw "VM has invalid isInPool value"
}
if ($vm.vc_id -ne $vc_id) {
Throw "VM is not in the correct vCenter instance"
}
return $vm
}

<# .SYNOPSIS Get the associated ADSI object for VM/pool. .DESCRIPTION Return an ADSI object for the specified DN on localhost. .PARAMETER pool Either a Pool object or its ID. .PARAMETER vm Either a DesktopVM object or its ID. .PARAMETER dn The DN string. Alternatively, can pass in a Pool or DesktopVM object. #>
function Get-ViewAdsiObj
{
param ([String]$dn = $null,
$pool = $null,
$vm = $null)

# allow overloaded param as pool or vm
if ($pool -ne $null) {
if ($pool.GetType().Name -eq "Pool") {
$pool = $pool.pool_id
}
$dn = ("cn=" + $pool + ",ou=server groups,dc=vdi,dc=vmware,dc=int")
}
if ($vm -ne $null) {
if ($vm.GetType().Name -eq "DesktopVM") {
$vm = $vm.machine_id
}
$dn = ("cn=" + $vm + ",ou=servers,dc=vdi,dc=vmware,dc=int")
}

if ($dn -eq $null) {
Throw "Need to specify a DN"
}

# return ADSI object
return [ADSI]("LDAP://localhost:389/" + $dn)
}

<# .SYNOPSIS Add a new VM to an existing manual pool .DESCRIPTION Adds the specified DesktopVM object and adds it to the existing manual pool. This is done by first creating a new temporary pool with the VM in, moving the VM to the existing pool, and finally deleting the temporary pool. .PARAMETER pool Either a Pool object or its ID. .PARAMETER vm Either an existing DesktopVM object or its ID. #>
function Add-ManualPoolVm
{
param ($pool = $(Read-Host -prompt "Pool ID"),
$vm = $(Read-Host -prompt "VM name"))

$pool = Get-ManualPool $pool
$vm = Get-ManualPoolVm -vm $vm -vc_id $pool.vc_id -in_pool $false

# do the add
$guid = "TMPPOOLADD-" + [Guid]::NewGuid()
$tmppool = Add-ManualPool -pool_id $guid -vc_id $vm.vc_id -vm_id_list $vm.id
try {
# need an updated entry
$vm = Get-ManualPoolVm -vm $vm.name -vc_id $vm.vc_id -in_pool $true
$vm = Move-ManualPoolVm -vm $vm -pool $pool
} finally {
Remove-Pool -pool_id $guid -DeleteFromDisk $false
}
return $vm
}

<# .SYNOPSIS Move a VM from one manual pool to another .DESCRIPTION Removes the specified DesktopVM from its existing manual pool and adds it to the specified one. .PARAMETER pool Either a Pool object or its ID. .PARAMETER vm Either an existing DesktopVM object or its ID. #>
function Move-ManualPoolVm
{
param ($pool = $(Read-Host -prompt "Pool ID"),
$vm = $(Read-Host -prompt "VM name"))

$pool = Get-ManualPool $pool
$vm = Get-ManualPoolVm -vm $vm -vc_id $pool.vc_id -in_pool $true
$oldPool = Get-ManualPool $vm.pool_id

$vmAdam = Get-ViewAdsiObj -vm $vm
$oldPoolAdam = Get-ViewAdsiObj -pool $oldPool
$newPoolAdam = Get-ViewAdsiObj -pool $pool

$vmDn = [String]($vmAdam.distinguishedName)
# remove VM from the old pool
$oldPoolAdam."pae-MemberDn".Remove($vmDn)
$oldPoolAdam.SetInfo()

# add VM to the new pool
$newPoolAdam."pae-MemberDn".Add($vmDn)
$newPoolAdam.SetInfo()

$vm.pool_id = $pool.pool_id
return $vm
}

<# .SYNOPSIS Removes a DesktopVM from a manual pool .DESCRIPTION Removes the DesktopVM from the specified pool, by removing its entry from ADAM and then clearing its View configuration information from the machine.id field. The pool parameter is used as a safety check. .PARAMETER pool Either a Pool object or its ID. .PARAMETER vm Either an existing DesktopVM object or its ID. .PARAMETER clearMid Clean the machine.id field for the VM, this is needed if you are not planning to delete it, but does require the vSphere PowerCLI cmdlets to be loaded. #>
function Remove-ManualPoolVm
{
param ($pool = $(Read-Host -prompt "Pool ID"),
$vm = $(Read-Host -prompt "VM name"),
[Boolean]$clearMid = $true)

$pool = Get-ManualPool $pool
$vm = Get-ManualPoolVm -vm $vm -vc_id $pool.vc_id -in_pool $true

if ($pool.pool_id -ne $vm.pool_id) {
Throw "VM is not in the correct pool"
}

# remove from ADAM
$serverOu = Get-ViewAdsiObj -dn "ou=servers,dc=vdi,dc=vmware,dc=int"
$serverOu.Delete("pae-VM", "cn=" + $vm.machine_id)
$serverOu.SetInfo()

# set machine.id field
if ($clearMid -eq $true) {
Clear-ViewMachineIdConfig -vm $vm.name
}
}
[/css]

 

MachineId.ps1

[css lang=”plain” autolinks=”false” classname=”myclass” collapse=”false” firstline=”1″ padlinenumbers=”false” gutter=”true” smarttabs=”true” toolbar=”true” language=”true”]</pre>
#### Set/get machine.id field for specified VM.

function Set-ExtraConfig() {
param( $vm = $(throw "Need VM"),
[String] $key = $(Read-Host -prompt "Key name"),
[String] $value = $(Read-Host -prompt "New value"))

# accept a string name if not an actual VM object
if ($vm.GetType().name -eq "String") {
$vm = get-vm $vm
}
$view = $vm | Get-View
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$extra = New-Object VMware.Vim.optionvalue
$extra.Key = $key
$extra.Value = $value
$vmConfigSpec.extraconfig += $extra
$view.ReconfigVM($vmConfigSpec)
}

function Get-ExtraConfig() {
param( $vm = $(throw "Need VM"),
[String] $key = $(Read-Host -prompt "Key name"))

# accept a string name if not an actual VM object
if ($vm.GetType().name -eq "String") {
$vm = get-vm $vm
}
$view = $vm | Get-View
$extraConfig = $view.config.extraconfig | where { $_.key -eq $key }
if ($extraConfig) {
return $extraConfig.value
} else {
return $null
}
}

function Set-MachineId() {
param( $vm = $(throw "Need VM"),
[String] $machineId = "")

return Set-ExtraConfig $vm "machine.id" $machineId
}

function Get-MachineId() {
param( $vm = $(throw "Need VM"))
return Get-ExtraConfig $vm "machine.id"
}

function Clear-ViewMachineIdConfig() {
param ($vm = $(throw "Need VM"))

$mid = Get-MachineId $vm
# keep itemDn (used for 5.1 secure pairing)
$r = "^vdi.broker.itemDn="
newmid = $mid.split(";") | where {[regex]::matches($_, $r)}
Set-MachineId $vm [String]$newmid
}
<pre>[/css]

 

This article was first published by Andre Leibovici (@andreleibovici) at myvirtualcloud.net.

1 comment

1 ping

  1. Ashish

    i am getting error while executing below command direct in View CLI (Horizon7 running)

    Add-ManualPoolVm -pool MyPool -vm win7

    having no output / input, while executing AddRemovePoolVms on ViewCLI

    please assist.

    Thanks

  1. Horizon View: Adding a virtual workstation to manual pool. | Piszki Lab | EN

    […] used was written by Andre Leibovici and as you can see, it works perfectly. In the attached file there are several different procedures […]

Leave a Reply