Did you know that Horizon utilizes Microsoft RDS’ draining capability and will actually react by placing the server in a special “drain mode” if it detects the DWORD/value TSServerDrainMode = 1? This drain mode simply prevents new logons to the RDS host, and unlike disabling a host via the admin console, will go back to Available again after getting rebooted.

This is a great feature for those that wish to utilize the “Wait for Users to Logoff” functionality when performing Instant Clone image pushes. A few days after pushing the image, you may have some stragglers on 24×7 environments that haven’t received the new image and rebooted yet. If you have Remote Registry on the session host enabled, you can simply run this via PowerShell to place the host in drain mode:

invoke-command -computername <RDS HOSTNAME> -ScriptBlock { New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name TSServerDrainMode -Value 1 -PropertyType DWORD -Force}

What if we have thousands of RDSH Instant Clones and don’t want to go one-by-one to set these? Well, you can utilize the script below, which requires the PowerCLI module. It will connect to the pod’s API service, list the instant clones that still have a pending image, and place them in drain mode if you confirm. Just save the script below to a .ps1 file and use the -CS parameter to point to a Connection Server. Please be cautious as to not accidentally set every single host into drain mode for a farm by running the script immediately after an image push. It looks like below:

# This script reports on any RDS farms in the pod with a pending image, and optionally sets those hosts in DRAIN mode

param (
    [string]$CS = "DefaultCS.domain.com"
    )

try
{
Connect-HVServer $CS
}
catch
{
Write-Host -ForegroundColor Red "Login seems to have failed! Make sure to use DOMAIN\username format and that you have appropriate PS modules!"
Read-Host "Press enter to continue..."
exit
}

# Populates HV services
$hvservices = $global:DefaultHVServers.ExtensionData

# Send query
[VMware.Hv.QueryServiceService]$queryService = New-Object VMware.Hv.QueryServiceService
[VMware.Hv.QueryDefinition]$defn = New-Object VMware.Hv.QueryDefinition
#$defn.queryEntityType = 'RDSServerSummaryView'
$defn.queryEntityType = 'RDSServerInfo'
[array]$queryResults= ($queryService.queryService_create($hvservices, $defn)).results

# Populate custom PS object
$RDSInfo=@()

foreach ($queryResult in $queryResults)
{
$RDSInfo+=New-Object PSObject -Property @{
"HostName" = $queryResult.Base.Name;
"PendingSnap" = $queryResult.rdsservermaintenancedata.pendingbaseimagesnapshotpath;
"Status" = $queryResult.runtimedata.status;
}
}

# Let's get the ones that have a pending image push...
$PendingImagePushes = $RDSInfo | Where-Object {$_.PendingSnap -ne $null}

If ($PendingImagePushes -eq $null)
{
Write-Host -ForegroundColor Green "There are no pending RDSH image pushes in this pod! Goodbye!"
# Cleanup query
$queryService.QueryService_DeleteAll($HVServices)
# Disconnect HVServer
Disconnect-HVServer * -Confirm:$false
exit
}
else
{
Write-Host 
Write-Host -ForegroundColor Green "The following" $PendingImagePushes.hostname.count "host(s) are pending an image push due to active sessions!"
$PendingImagePushes | select hostname,status
Write-Host -ForegroundColor Green "Would you like to enable DRAIN mode for these hosts (yes/no)?"
$yesOrno = Read-Host -Prompt "yes/no"

if ($yesOrno -eq "yes")
{
Write-Host -ForegroundColor Green "Placing hosts into DRAIN mode..."
invoke-command -computername $PendingImagePushes.Hostname -ScriptBlock { New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name TSServerDrainMode -Value 1 -PropertyType DWORD -Force}

Write-Host -ForegroundColor Green "Goodbye!"
# Cleanup query
$queryService.QueryService_DeleteAll($HVServices)
# Disconnect HVServer
Disconnect-HVServer * -Confirm:$false

}
else 
{
Write-Host -ForegroundColor Green "Goodbye!"
# Cleanup query
$queryService.QueryService_DeleteAll($HVServices)
# Disconnect HVServer
Disconnect-HVServer * -Confirm:$false
}
}