VMware Horizon – Install Connection Server silently with Powershell

Release date: December 26th 2022

Welcome to my VMware Horizon series. I recently experienced a complete hardware crash in my old lab, and had to do a complete rebuild. Although this was sad, it gave me the opportunity to do it by scripting this time. As part of the exercise, I wanted to do all the installation from the management server using PowerShell and PowerCLI. This involved recreating the servers and joining them to the domain. Once that was done, I could start installing my VMware Horizon Connection Servers.

Prerequisites:

  • PowerShell Administrative access to the Connection-server

Before I started, I made myself a little workflow as show below.

To follow my workflow above, I first created the following credentials to be used in the script:

  • vCenter admin-user:
New-VICredentialStoreItem -User <user> -Password <user> -Host <server> -File C:\<your location.xml>
  • Horizon admin-user:
$credential = Get-Credential
$credential | Export-CliXml -Path '<path>\hz_admin.xml'

Now that I had the credentials created, I was good to go. (PS: I know I’m no programmer and a lot of this script have the potential for improvement, but, it gets the job done, and that’s good enough for me. If You have input to making this script even better, please leave a comment below, it will be very much appreciated!)

instCS.ps1

# --- Initialize PowerCLI Modules --- 

Import-Module VMware.VimAutomation.Core
Import-Module VMware.VimAutomation.Common
Set-PowerCLIConfiguration -Scope User -ParticipateInCeip $false -Confirm:$false
Set-PowerCLIConfiguration -InvalidCertificateAction ignore -Confirm:$false
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -Confirm:$false

# --- Connect to vCenter with Get-VICredentialStoreItem ---

$viserver = "vCenter fqdn"
$viuser = Get-VICredentialStoreItem -File "<path to vCenter Credentials>.xml" -host $viserver
Connect-viserver -Server $viserver -User $viuser.user -Password $viuser.password

# --- Shut Down VM ---

$cs = "cs fqdn"
Try{
   $vm = Get-VM -Name $cs -ErrorAction Stop
   switch($vm.PowerState){
   'poweredon' {
  Shutdown-VMGuest -VM $vm -Confirm:$false
   while($vm.PowerState -eq 'PoweredOn'){
  sleep 5
   $vm = Get-VM -Name $cs
   }
   }
   Default {
   Write-Host "VM '$($cs)' is not powered on!"
   }
   }
   Write-Host "$($cs) has shutdown. It should be ready for configuration."
}
Catch{
   Write-Host "VM '$($cs)' not found!"
}

# --- Take Snapshot ---

$SnapshotName = "Pre-Install"
Get-VM $cs | New-Snapshot -Name $SnapshotName

# --- Power On VM ---

Start-VM -VM $cs
# Wait 5 minutes - SLOW LAB :)
Start-Sleep 300

# --- Configure PSSession ---

$credential = Import-CliXml -Path "<path to horizon admin>\hz_admin_${env:USERNAME}_${env:COMPUTERNAME}.xml"
$session = New-PSSession -ComputerName $cs -Credential $credential -Authentication CredSSP

# --- Define, Copy and Run Installer ---

Invoke-Command -Session $session -ScriptBlock {

# Variables
    $InstallDir = "C:\Install\"
    $ExeName = "VMware-Horizon-Connection-Server*"
    $ExeFile = "\\<Network-Path>\$ExeName"
    $Vendor = "VMware"
    $Product = "Horizon Connection Server"

# Creating temp-folder, copy installer
    New-Item -Path $InstallDir -type directory -Force
    Copy-Item -Path $Exe -Destination $InstallDir -Force

# VMware Connection Server MSI Switches
    $MsiArgs = @(
        "/qn"
        "VDM_SERVER_INSTANCE_TYPE=1" # Connection Server
        "FWCHOICE=1"
        "VDM_INITIAL_ADMIN_SID=S-1-5-32-544"
        "VDM_SERVER_RECOVERY_PWD=<Passw0rd!>"
        "VDM_SERVER_RECOVERY_PWD_REMINDER=KeePass_DB_Pwd"
    )

# Install Connection Server
    Write-Host "Installing $Vendor $Product" -ForegroundColor Green
    $Exe = (Get-ChildItem -Path $InstallDir | Where-Object {$_.name -like $ExeName}).Fullname
    $Install = (Start-Process -Filepath $Exe -Wait -ArgumentList "/s /v""$MsiArgs" -PassThru)
    $Install.ExitCode
    if ($Install.ExitCode -ne '0')
        {
        Write-Host "The installation failed, revert to snapshot, remediate error and try again" -ForegroundColor Red

        [System.Environment]::Exit(0)
        }

# --- Rename Self-Signed vdm-cert, request new and rename friendly name
    Write-Verbose "Configuring Connection Server certificate" -Verbose    
    $Thumbprint = (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.FriendlyName -match "vdm"}).Thumbprint
     (Get-ChildItem -Path Cert:\LocalMachine\My\$Thumbprint).FriendlyName = "self-signed"
     Get-Certificate -Template "<Horizon-Server Template Name>" -DnsName "fqdn" -SubjectName 'CN=fqdn' -CertStoreLocation cert:\LocalMachine\My
     $newThumbprint = (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Issuer -match "<CA Name>"}).Thumbprint;
     (Get-ChildItem -Path Cert:\LocalMachine\My\$newThumbprint).FriendlyName = "vdm"

# Copy locked.properties to .\sslgateway\conf folder    
    $LockedPropertiesFile = "\\<Network Path>\locked.properties"
    $SslGatewayDir = "C:\Program Files\VMware\VMware View\Server\sslgateway\conf"
    Copy-Item -Path $LockedPropertiesFile -Destination $SslGatewayDir -Force  
}
Remove-PSSession $session

Get-VM $cs | Restart-VMGuest

# Wait 3 minutes - SLOW LAB :)
Start-Sleep 180

# --- Check Service-status, remove Temp folder and install media ---
Write-Verbose "Remove temp folder and snapshot" -Verbose
$session = New-PSSession -ComputerName $cs -Credential $credential -Authentication CredSSP

Invoke-Command -Session $session -ScriptBlock {

# Waiting for VMware Horizon View Connection Server Service to start"
    $SvcName = 'wsbroker'
    $SvcDisplayName = "VMware Horizon View Connection Server Service"
    $Svc = Get-Service -Name $SvcName
    Write-Host "Waiting for VMware Horizon View Connection Server Service to start" -ForegroundColor Green
    if ($Svc.Status -eq 'Running')
        {
        Write-Host "$SvcDisplayName is Running" -ForegroundColor Green
        }

    if ($Svc.Status -ne 'Running')
        {
        Write-Host "Waiting for $SvcDisplayName to start" -ForegroundColor Green
        $Svc.WaitForStatus("Running")
        Write-Host "$SvcDisplayName is now running" -ForegroundColor Green
        }

    $installDir = "C:\Install\"
    Remove-Item –path $installDir –Recurse -Force
}
Remove-PSSession $session

# Remove Snapshot
Read-Host "Press Any Key to remove Snapshot"
Get-VM $cs | Get-snapshot -Name $SnapshotName | Remove-Snapshot  -Confirm:$false

# Disconnect from vCenter
write-host "Disconnecting from vCenter" -ForegroundColor Green
Disconnect-VIServer -Server $viserver -Confirm:$false

While the script above installs a standard Horizon Connection Server, I can use the same script with minor adjustments, to install a Replica Server or an Enrollment Server, for instance changing the “$MsiArgs” variable:

Replica Server:

    $MsiArgs = @(
        "/qn"
        "VDM_SERVER_INSTANCE_TYPE=2"
        "FWCHOICE=1"
        "ADAM_PRIMARY_NAME=<FQDN Primary Connection Server>"
        "VDM_INITIAL_ADMIN_SID=S-1-5-32-544"
    )

Enrollment Server:

    $MsiArgs = @(
        "/qn"
        "VDM_SERVER_INSTANCE_TYPE=5"
        "FWCHOICE=1"
        "VDM_INITIAL_ADMIN_SID=S-1-5-32-544"
    )

With the Connection Server installed with correct certificate, I can now proceed with configuring the first connection server using API, covered here:

VMware Official Documentation:

VMware Horizon planning, deployment etc.

Disclaimer: Every tips/tricks/posting I have published here, is tried and tested in different it-solutions. It is not guaranteed to work everywhere, but is meant as a tip for other users out there. Remember, Google is your friend and don’t be afraid to steal with pride! Feel free to comment below as needed.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: