Securing Citrix VDAs with TLS: Automating the Process with Ivanti AM
After restarting a Citrix server, you may occasionally find that the Virtual Delivery Agent (VDA) is no longer configured correctly for SSL/TLS. This can cause issues when establishing secure ICA connections.
To prevent this from happening, or at least make recovery easier, the required PowerShell scripts can be combined and automated through Ivanti Automation Management (Ivanti AM).
The three steps
1. Synchronising the system time
The first step is to synchronise the server’s system clock:
w32tm /resync /nowait
Having the correct system time is important when validating certificates. If the server clock is incorrect, a certificate may appear to be expired or not yet valid. The /nowait parameter allows the command to run without waiting for the synchronisation process to finish.
2. Configuring TLS on the VDA
Next, the Citrix script Enable-VdaSSL.ps1 is executed. This script configures the VDA to use secure SSL/TLS and DTLS connections.
Among other things, it checks the certificate, sets the required access permissions, updates the Windows Firewall rules and writes the TLS settings to the Windows Registry. The final step enables the SSL listener.
One thing worth paying attention to is the TLS version. The script uses TLS 1.0 by default. Since this version is outdated, TLS 1.2 is generally the better choice, provided that the Citrix components and clients in use support it.
Expand to view the contents of Enable-VdaSSL.ps1
<#
.SYNOPSIS
Enable/Disable the TLS/DTLS listeners on the VDA
.DESCRIPTION
Enable or disable the TLS/DTLS listeners on the VDA.
Optionally, the TLS/DTLS certificate, port, version and cipher suite to use can be specified.
.PARAMETER Disable
Disables the TLS/DTLS listeners.
.PARAMETER Enable
Enables the TLS/DTLS listeners.
.PARAMETER SSLPort
Specifies the port to use. Default is port 443.
.PARAMETER SSLMinVersion
Specifies the minimum TLS/DTLS version to use (allowed values are SSL_3.0, TLS_1.0, TLS_1.1 and TLS_1.2).
Default is TLS_1.0.
.PARAMETER SSLCipherSuite
Specifies the cipher suite to use (allowed values are GOV, COM and ALL). Default is ALL.
.PARAMETER CertificateThumbPrint
Specifies the certificate thumbprint to identify the certificate to use. Default is the certificate that
matches the FQDN of the VDA.
.EXAMPLE
To disable the TLS/DTLS listeners
Enable-VdaSSL -Disable
.EXAMPLE
To enable the TLS/DTLS listeners
Enable-VdaSSL -Enable
.EXAMPLE
To enable the TLS/DTLS listeners on port 4000
Enable-VdaSSL -Enable -SSLPort 4000
.EXAMPLE
To enable the TLS/DTLS listeners using TLS 1.2 with the GOV cipher suite
Enable-VdaSSL -Enable -SSLMinVersion “TLS_1.2” -SSLCipherSuite “GOV”
.EXAMPLE
To enable the TLS/DTLS listeners using the specified computer certificate
Enable-VdaSSL -Enable -CertificateThumbprint “373641446CCA0343D1D5C77EB263492180B3E0FD”
#>
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = ‘High’)]
Param(
[Parameter(Mandatory=$True, Position=1, ValueFromPipeline=$False, ParameterSetName = “DisableMode”)]
[switch] $Disable,
[Parameter(Mandatory=$True, Position=1, ValueFromPipeline=$False, ParameterSetName = “EnableMode”)]
[switch] $Enable,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, ParameterSetName = “EnableMode”)]
[int] $SSLPort = 443,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, ParameterSetName = “EnableMode”)]
[ValidateSet(“SSL_3.0”, “TLS_1.0”, “TLS_1.1”, “TLS_1.2”)]
[String] $SSLMinVersion = “TLS_1.0”,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, ParameterSetName = “EnableMode”)]
[ValidateSet(“GOV”, “COM”, “ALL”)]
[String] $SSLCipherSuite = “ALL”,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, ParameterSetName = “EnableMode”)]
[string]$CertificateThumbPrint
)
Set-StrictMode -Version 2.0
$erroractionpreference = “Stop”
#Check if the user is an administrator
if(!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] “Administrator”))
{
Write-Host “You do not have Administrator rights to run this script.`nPlease re-run this script as an Administrator.”
break
}
#Write Header
Write-Host “Enable TLS/DTLS to the VDA”
Write-Host “Running command Enable-VdaSSL to enable or disable TLS/DTLS to the VDA.”
Write-Host “This includes:”
Write-Host “`ta.Disable TLS/DTLS to VDA or”
Write-Host “`tb.Enable TLS/DTLS to VDA”
Write-Host “`t`t1.Setting ACLs”
Write-Host “`t`t2.Setting registry keys”
Write-Host “`t`t3.Configuring Firewall”
Write-Host “”
Write-Host “”
# Registry path constants
$ICA_LISTENER_PATH = ‘HKLM:\system\CurrentControlSet\Control\Terminal Server\Wds\icawd’
$ICA_CIPHER_SUITE = ‘HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman’
$DHEnabled = ‘Enabled’
$BACK_DHEnabled = ‘Back_Enabled’
$ENABLE_SSL_KEY = ‘SSLEnabled’
$SSL_CERT_HASH_KEY = ‘SSLThumbprint’
$SSL_PORT_KEY = ‘SSLPort’
$SSL_MINVERSION_KEY = ‘SSLMinVersion’
$SSL_CIPHERSUITE_KEY = ‘SSLCipherSuite’
$POLICIES_PATH = ‘HKLM:\SOFTWARE\Policies\Citrix\ICAPolicies’
$ICA_LISTENER_PORT_KEY = ‘IcaListenerPortNumber’
$SESSION_RELIABILITY_PORT_KEY = ‘SessionReliabilityPort’
$WEBSOCKET_PORT_KEY = ‘WebSocketPort’
#Read ICA, CGP and HTML5 ports from the registry
try
{
$IcaPort = (Get-ItemProperty -Path $POLICIES_PATH -Name $ICA_LISTENER_PORT_KEY).IcaListenerPortNumber
}
catch
{
$IcaPort = 1494
}
try
{
$CgpPort = (Get-ItemProperty -Path $POLICIES_PATH -Name $SESSION_RELIABILITY_PORT_KEY).SessionReliabilityPort
}
catch
{
$CgpPort = 2598
}
try
{
$Html5Port = (Get-ItemProperty -Path $POLICIES_PATH -Name $WEBSOCKET_PORT_KEY).WebSocketPort
}
catch
{
$Html5Port = 8008
}
if (!$IcaPort)
{
$IcaPort = 1494
}
if (!$CgpPort)
{
$CgpPort = 2598
}
if (!$Html5Port)
{
$Html5Port = 8008
}
# Determine the name of the ICA Session Manager
if (Get-Service | Where-Object {$_.Name -eq ‘porticaservice’})
{
$username = ‘NT SERVICE\PorticaService’
$serviceName = ‘PortIcaService’
}
else
{
$username = ‘NT SERVICE\TermService’
$serviceName = ‘TermService’
}
switch ($PSCmdlet.ParameterSetName)
{
“DisableMode”
{
#Replace Diffie-Hellman Enabled value to its original value
if (Test-Path $ICA_CIPHER_SUITE)
{
$back_enabled_exists = Get-ItemProperty -Path $ICA_CIPHER_SUITE -Name $BACK_DHEnabled -ErrorAction SilentlyContinue
if ($back_enabled_exists -ne $null)
{
Set-ItemProperty -Path $ICA_CIPHER_SUITE -Name $DHEnabled -Value $back_enabled_exists.Back_Enabled
Remove-ItemProperty -Path $ICA_CIPHER_SUITE -Name $BACK_DHEnabled
}
}
if ($PSCmdlet.ShouldProcess(“This will delete any existing firewall rules for Citrix SSL Service and enable rules for ICA, CGP and Websocket services.”, “Are you sure you want to perform this action?`nThis will delete any existing firewall rules for Citrix SSL Service and enable rules for ICA, CGP and Websocket services.”, “Configure Firewall”))
{
#Enable any existing rules for ICA, CGP and HTML5 ports
netsh advfirewall firewall add rule name=”Citrix ICA Service” dir=in action=allow service=$serviceName profile=any protocol=tcp localport=$IcaPort | Out-Null
netsh advfirewall firewall add rule name=”Citrix CGP Server Service” dir=in action=allow service=$serviceName profile=any protocol=tcp localport=$CgpPort | Out-Null
netsh advfirewall firewall add rule name=”Citrix Websocket Service” dir=in action=allow service=$serviceName profile=any protocol=tcp localport=$Html5Port | Out-Null
#Enable existing rules for UDP-ICA, UDP-CGP
netsh advfirewall firewall add rule name=”Citrix ICA UDP” dir=in action=allow service=$serviceName profile=any protocol=udp localport=$IcaPort | Out-Null
netsh advfirewall firewall add rule name=”Citrix CGP UDP” dir=in action=allow service=$serviceName profile=any protocol=udp localport=$CgpPort | Out-Null
#Delete any existing rules for Citrix SSL Service
netsh advfirewall firewall delete rule name=”Citrix SSL Service” | Out-Null
#Delete any existing rules for Citrix DTLS Service
netsh advfirewall firewall delete rule name=”Citrix DTLS Service” | Out-Null
}
else
{
Write-Host “Firewall configuration skipped.”
}
#Turning off SSL by setting SSLEnabled key to 0
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $ENABLE_SSL_KEY -Value 0 -Type DWord -Confirm:$false
Write-Host “SSL to VDA has been disabled.”
}
“EnableMode”
{
$RegistryKeysSet = $ACLsSet = $FirewallConfigured = $False
$Store = New-Object System.Security.Cryptography.X509Certificates.X509Store(“My”, “LocalMachine”)
$Store.Open(“ReadOnly”)
if ($Store.Certificates.Count -eq 0)
{
Write-Host “No certificates found in the Personal Local Machine Certificate Store. Please install a certificate and try again.”
Write-Host “`nEnabling SSL to VDA failed.”
$Store.Close()
break
}
elseif ($Store.Certificates.Count -eq 1)
{
if ($CertificateThumbPrint)
{
$Certificate = $Store.Certificates[0]
$Thumbprint = $Certificate.GetCertHashString()
if ($Thumbprint -ne $CertificateThumbPrint)
{
Write-Host “No certificate found in the certificate store with thumbprint $CertificateThumbPrint”
Write-Host “`nEnabling SSL to VDA failed.”
$Store.Close()
break
}
}
else
{
$Certificate = $Store.Certificates[0]
}
}
elseif ($CertificateThumbPrint)
{
$Certificate = $Store.Certificates | where {$_.GetCertHashString() -eq $CertificateThumbPrint}
if (!$Certificate)
{
Write-Host “No certificate found in the certificate store with thumbprint $CertificateThumbPrint”
Write-Host “`nEnabling SSL to VDA failed.”
$Store.Close()
break
}
}
else
{
$ComputerName = “CN=”+[System.Net.Dns]::GetHostByName((hostname)).HostName+”,”
$Certificate = $Store.Certificates | where {$_.Subject -match $ComputerName}
if (!$Certificate)
{
Write-Host “No certificate found in the certificate store with Subject $ComputerName, please specify the thumbprint using -CertificateThumbPrint option.”
Write-Host “`nEnabling SSL to VDA failed.”
$Store.Close()
break
}
}
#Validate the certificate
#Validate expiration date
$ValidTo = [DateTime]::Parse($Certificate.GetExpirationDateString())
if($ValidTo -lt [DateTime]::UtcNow)
{
Write-Host “The certificate is expired. Please install a valid certificate and try again.”
Write-Host “`nEnabling SSL to VDA failed.”
$Store.Close()
break
}
#Check certificate trust
if(!$Certificate.Verify())
{
Write-Host “Verification of the certificate failed. Please install a valid certificate and try again.”
Write-Host “`nEnabling SSL to VDA failed.”
$Store.Close()
break
}
#Check private key availability
try
{
[System.Security.Cryptography.AsymmetricAlgorithm] $PrivateKey = $Certificate.PrivateKey
$UniqueContainer = ((($Certificate).PrivateKey).CspKeyContainerInfo).UniqueKeyContainerName
}
catch
{
Write-Host “Unable to access the Private Key of the Certificate or one of its fields.”
Write-Host “`nEnabling SSL to VDA failed.”
$Store.Close()
break
}
if(!$PrivateKey -or !$UniqueContainer)
{
Write-Host “Unable to access the Private Key of the Certificate or one of its fields.”
Write-Host “`nEnabling SSL to VDA failed.”
$Store.Close()
break
}
if ($PSCmdlet.ShouldProcess(“This will grant $serviceName read access to the certificate.”, “Are you sure you want to perform this action?`nThis will grant $serviceName read access to the certificate.”, “Configure ACLs”))
{
$private_key = ((($Certificate).PrivateKey).CspKeyContainerInfo).UniqueKeyContainerName
$dir= $env:ProgramData + ‘\Microsoft\Crypto\RSA\MachineKeys\’
$keypath = $dir+$private_key
icacls $keypath /grant `”$username`”`:RX | Out-Null
Write-Host “ACLs set.”
Write-Host “”
$ACLsSet = $True
}
else
{
Write-Host “ACL configuration skipped.”
}
if($PSCmdlet.ShouldProcess(“This will delete any existing firewall rules for port $SSLPort and disable rules for ICA, CGP and Websocket services.”, “Are you sure you want to perform this action?`nThis will delete any existing firewall rules for port $SSLPort and disable rules for ICA, CGP and Websocket services.”, “Configure Firewall”))
{
#Delete any existing rules for the SSLPort
netsh advfirewall firewall delete rule name=all protocol=tcp localport=$SSLPort | Out-Null
#Delete any existing rules for the DTLSPort
netsh advfirewall firewall delete rule name=all protocol=udp localport=$SSLPort | Out-Null
#Delete any existing rules for Citrix SSL Service
netsh advfirewall firewall delete rule name=”Citrix SSL Service” | Out-Null
#Delete any existing rules for Citrix DTLS Service
netsh advfirewall firewall delete rule name=”Citrix DTLS Service” | Out-Null
#Creating firewall rule for Citrix SSL Service
netsh advfirewall firewall add rule name=”Citrix SSL Service” dir=in action=allow service=$serviceName profile=any protocol=tcp localport=$SSLPort | Out-Null
#Creating firewall rule for Citrix DTLS Service
netsh advfirewall firewall add rule name=”Citrix DTLS Service” dir=in action=allow service=$serviceName profile=any protocol=udp localport=$SSLPort | Out-Null
#Disable any existing rules for ICA, CGP and HTML5 ports
netsh advfirewall firewall set rule name=”Citrix ICA Service” protocol=tcp localport=$IcaPort new enable=no | Out-Null
netsh advfirewall firewall set rule name=”Citrix CGP Server Service” protocol=tcp localport=$CgpPort new enable=no | Out-Null
netsh advfirewall firewall set rule name=”Citrix Websocket Service” protocol=tcp localport=$Html5Port new enable=no | Out-Null
#Disable existing rules for UDP-ICA, UDP-CGP
netsh advfirewall firewall set rule name=”Citrix ICA UDP” protocol=udp localport=$IcaPort new enable=no | Out-Null
netsh advfirewall firewall set rule name=”Citrix CGP UDP” protocol=udp localport=$CgpPort new enable=no | Out-Null
Write-Host “Firewall configured.”
$FirewallConfigured = $True
}
else
{
Write-Host “Firewall configuration skipped.”
}
# Create registry keys to enable SSL to the VDA
Write-Host “Setting registry keys…”
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $SSL_CERT_HASH_KEY -Value $Certificate.GetCertHash() -Type Binary -Confirm:$False
switch($SSLMinVersion)
{
“SSL_3.0”
{
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $SSL_MINVERSION_KEY -Value 1 -Type DWord -Confirm:$False
}
“TLS_1.0”
{
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $SSL_MINVERSION_KEY -Value 2 -Type DWord -Confirm:$False
}
“TLS_1.1”
{
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $SSL_MINVERSION_KEY -Value 3 -Type DWord -Confirm:$False
}
“TLS_1.2”
{
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $SSL_MINVERSION_KEY -Value 4 -Type DWord -Confirm:$False
}
}
switch($SSLCipherSuite)
{
“GOV”
{
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $SSL_CIPHERSUITE_KEY -Value 1 -Type DWord -Confirm:$False
}
“COM”
{
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $SSL_CIPHERSUITE_KEY -Value 2 -Type DWord -Confirm:$False
}
“ALL”
{
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $SSL_CIPHERSUITE_KEY -Value 3 -Type DWord -Confirm:$False
}
}
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $SSL_PORT_KEY -Value $SSLPort -Type DWord -Confirm:$False
#Backup DH Cipher Suite and set Enabled:0 if SSL is enabled
if (!(Test-Path $ICA_CIPHER_SUITE))
{
New-Item -Path $ICA_CIPHER_SUITE -Force | Out-Null
New-ItemProperty -Path $ICA_CIPHER_SUITE -Name $DHEnabled -Value 0 -PropertyType DWORD -Force | Out-Null
New-ItemProperty -Path $ICA_CIPHER_SUITE -Name $BACK_DHEnabled -Value 1 -PropertyType DWORD -Force | Out-Null
}
else
{
$back_enabled_exists = Get-ItemProperty -Path $ICA_CIPHER_SUITE -Name $BACK_DHEnabled -ErrorAction SilentlyContinue
if ($back_enabled_exists -eq $null)
{
$exists = Get-ItemProperty -Path $ICA_CIPHER_SUITE -Name $DHEnabled -ErrorAction SilentlyContinue
if ($exists -ne $null)
{
New-ItemProperty -Path $ICA_CIPHER_SUITE -Name $BACK_DHEnabled -Value $exists.Enabled -PropertyType DWORD -Force | Out-Null
Set-ItemProperty -Path $ICA_CIPHER_SUITE -Name $DHEnabled -Value 0
}
else
{
New-ItemProperty -Path $ICA_CIPHER_SUITE -Name $DHEnabled -Value 0 -PropertyType DWORD -Force | Out-Null
New-ItemProperty -Path $ICA_CIPHER_SUITE -Name $BACK_DHEnabled -Value 1 -PropertyType DWORD -Force | Out-Null
}
}
}
# NOTE: This must be the last thing done when enabling SSL as the Citrix Service
# will use this as a signal to try and start the Citrix SSL Listener!!!!
Set-ItemProperty -Path $ICA_LISTENER_PATH -name $ENABLE_SSL_KEY -Value 1 -Type DWord -Confirm:$False
Write-Host “Registry keys set.”
Write-Host “”
$RegistryKeysSet = $True
$Store.Close()
if ($RegistryKeysSet -and $ACLsSet -and $FirewallConfigured)
{
Write-Host “`nSSL to VDA enabled.`n”
}
else
{
Write-Host “`n”
if (!$RegistryKeysSet)
{
Write-Host “Configure registry manually or re-run the script to complete enabling SSL to VDA.”
}
if (!$ACLsSet)
{
Write-Host “Configure ACLs manually or re-run the script to complete enabling SSL to VDA.”
}
if (!$FirewallConfigured)
{
Write-Host “Configure firewall manually or re-run the script to complete enabling SSL to VDA.”
}
}
}
}
# SIG # Begin signature block
# MIIa0AYJKoZIhvcNAQcCoIIawTCCGr0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVlCkBIWutmvfv102UfUYLGe2
# k6GgghTsMIIFJDCCBAygAwIBAgIQCpJdJFWANibhh6AFcJolkDANBgkqhkiG9w0B
# AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz
# c3VyZWQgSUQgVGltZXN0YW1waW5nIENBMB4XDTE4MDgwMTAwMDAwMFoXDTIzMDkw
# MTAwMDAwMFowYDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFENpdHJpeCBTeXN0ZW1z
# LCBJbmMuMQ0wCwYDVQQLEwRHTElTMSMwIQYDVQQDExpDaXRyaXggVGltZXN0YW1w
# IFJlc3BvbmRlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANjWtJ4e
# cpVfB34YnxfYNvb1Rp2JbBu5/G9Boe8aEBQc2zidW82ousZrXj2QD2qUA1Ee8noo
# t1KGcQdY0WzzbSIU7KHePB5KaESWjtHVJ3BW6W9q+U24m2dPD/oaNxGx6DtD7M0N
# lMBIRZKo7aNIsRIlHkg7wnNQzqi0jTkzBO7S34holaqhfuQgqkgKqGmcoSIXVqNm
# EFaU+5kpYFqpMo6x1sSAgfgNEcIgGjnj8xzdU1rnh6iNYMxOt8guMWk2z+KKNbux
# H6YLAA9VBYW417Zf153/5L4ejuxxUhCp03JkoUIWjSRjz3m24HD9K8NSgJ0AdDpN
# E8ZPmIJCMFi9FYcCAwEAAaOCAcYwggHCMB8GA1UdIwQYMBaAFPS24SAd/imu0uRh
# pbKiJbLIFzVuMB0GA1UdDgQWBBS1Y37AhXUHPaYuvS/SUsWFFisSbTAMBgNVHRMB
# Af8EAjAAMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDBP
# BgNVHSAESDBGMDcGCWCGSAGG/WwHATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3
# dy5kaWdpY2VydC5jb20vQ1BTMAsGCWCGSAGG/WwDFTBxBgNVHR8EajBoMDKgMKAu
# hixodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDAy
# oDCgLoYsaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5j
# cmwwgYUGCCsGAQUFBwEBBHkwdzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln
# aWNlcnQuY29tME8GCCsGAQUFBzAChkNodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRTSEEyQXNzdXJlZElEVGltZXN0YW1waW5nQ0EuY3J0MA0GCSqG
# SIb3DQEBCwUAA4IBAQBrQ4tHgdu37madmYML6Ikfb8bNWoritioGcrlVfsMEGdLN
# LAsPYqrMo9mZmNzKTE7UVzGVdwb+Cfz9IRfD6hmK6hhEuom+XNzC8LGQ3o7U2ede
# YF/xuIcFZAwmQnXOoVl4yDWKrfyalOIO9wpQ6bDV7f0CPa8j3Qj2eNJ2u2qKnRE+
# x5Iz8j5lsjQeefIriGVHd27R93ai0li9WZMT9KKOAk06R0Z0qyG70jXhoUp4Or5c
# lv5mmVJgmxr1hMjVg7v95WGY50p2+cfhqLlViu2cu0LCg31IUb0lbTYNbgY1eca2
# cr8F0ppVnrt55YVfb1M80huj9DeYYjeFSKkcN+6xMIIFMDCCBBigAwIBAgIQBAkY
# G1/Vu2Z1U0O1b5VQCDANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMG
# A1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
# IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIw
# MDAwWhcNMjgxMDIyMTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln
# aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhE
# aWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkq
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrb
# RPV/5aid2zLXcep2nQUut4/6kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7
# KSfH03sjlOSRI5aQd4L5oYQjZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCV
# rhxKhwjfDPXiTWAYvqrEsq5wMWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXp
# dOYr/mzLfnQ5Ng2Q7+S1TqSp6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWO
# D8Gi6CxR93O8vYWxYoNzQYIH5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IB
# zTCCAckwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0l
# BAwwCgYIKwYBBQUHAwMweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRw
# Oi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRz
# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1Ud
# HwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz
# c3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgB
# hv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9D
# UFMwCgYIYIZIAYb9bAMwHQYDVR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8G
# A1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IB
# AQA+7A1aJLPzItEVyCx8JSl2qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew
# 4fbRknUPUbRupY5a4l4kgU4QpO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcO
# kRX7uq+1UcKNJK4kxscnKqEpKBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGx
# DI+7qPjFEmifz0DLQESlE/DmZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7Lr
# ZkPas7CM1ekN3fYBIM6ZMWM9CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiF
# LpKR6mhsRDKyZqHnGKSaZFHvMIIFMTCCBBmgAwIBAgIQCqEl1tYyG35B5AXaNpfC
# FTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl
# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdp
# Q2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTYwMTA3MTIwMDAwWhcNMzEwMTA3
# MTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw
# FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEy
# IEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
# AQ8AMIIBCgKCAQEAvdAy7kvNj3/dqbqCmcU5VChXtiNKxA4HRTNREH3Q+X1NaH7n
# tqD0jbOI5Je/YyGQmL8TvFfTw+F+CNZqFAA49y4eO+7MpvYyWf5fZT/gm+vjRkcG
# GlV+Cyd+wKL1oODeIj8O/36V+/OjuiI+GKwR5PCZA207hXwJ0+5dyJoLVOOoCXFr
# 4M8iEA91z3FyTgqt30A6XLdR4aF5FMZNJCMwXbzsPGBqrC8HzP3w6kfZiFBe/WZu
# VmEnKYmEUeaC50ZQ/ZQqLKfkdT66mA+Ef58xFNat1fJky3seBdCEGXIX8RcG7z3N
# 1k3vBkL9olMqT4UdxB08r8/arBD13ays6Vb/kwIDAQABo4IBzjCCAcowHQYDVR0O
# BBYEFPS24SAd/imu0uRhpbKiJbLIFzVuMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1R
# i6enIZ3zbcgPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMG
# A1UdJQQMMAoGCCsGAQUFBwMIMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGB
# BgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNl
# cnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2Vy
# dC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMFAGA1UdIARJMEcwOAYK
# YIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j
# b20vQ1BTMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAQEAcZUS6VGHVmnN
# 793afKpjerN4zwY3QITvS4S/ys8DAv3Fp8MOIEIsr3fzKx8MIVoqtwU0HWqumfgn
# oma/Capg33akOpMP+LLR2HwZYuhegiUexLoceywh4tZbLBQ1QwRostt1AuByx5jW
# PGTlH0gQGF+JOGFNYkYkh2OMkVIsrymJ5Xgf1gsUpYDXEkdws3XVk4WTfraSZ/tT
# YYmo9WuWwPRYaQ18yAGxuSh1t5ljhSKMYcp5lH5Z/IwP42+1ASa2bKXuh1Eh5Fhg
# m7oMLSttosR+u8QlK0cCCHxJrhO24XxCQijGGFbPQTS2Zl22dHv1VjMiLyI2skui
# SpXY9aaOUjCCBVcwggQ/oAMCAQICEA5SwjVXc07EY1PSyXDjKx8wDQYJKoZIhvcN
# AQELBQAwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG
# A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBB
# c3N1cmVkIElEIENvZGUgU2lnbmluZyBDQTAeFw0yMTA0MjgwMDAwMDBaFw0yMzA1
# MDMyMzU5NTlaMIGUMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHRmxvcmlkYTEYMBYG
# A1UEBxMPRm9ydCBMYXVkZXJkYWxlMR0wGwYDVQQKExRDaXRyaXggU3lzdGVtcywg
# SW5jLjEbMBkGA1UECxMSWGVuQXBwKFBvd2Vyc2hlbGwpMR0wGwYDVQQDExRDaXRy
# aXggU3lzdGVtcywgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
# ALqU69rRrQR5G6LXw3BRk644qamIX1oTGmWacWkYHRI6B8dn5hfK2Doaw7KxzKkj
# 05V902fKg2Sf2IJpKlTX9c1HJ9fFQasTZTsw9xESEybANuZNzgzJcnsc1TQwLoKH
# 9WSv4DUiaJCrheh4YICeafPrhojZRgFsiOUFDMXYFmeRwn9j6/o8SUrf+E3Um9T9
# cIgDtYgJgLvLf5nY1qftiMGJ+hLhlz9LDAUbsESL/uC0fkUXcjbbXyxmWKZ2SpS3
# YLZlxgehSqilmk0OYAQi4sIkLvwKEMYrsk7QQv+IQBmVveZkHxZqR9P/uhRtlREb
# GzDFuVYxy7kqYqKPNI2yRSECAwEAAaOCAcQwggHAMB8GA1UdIwQYMBaAFFrEuXsq
# CqOl6nEDwGD5LfZldQ5YMB0GA1UdDgQWBBS7iHme24LPbr20oCMccD2IWSJyGTAO
# BgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1
# oDOgMYYvaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1n
# MS5jcmwwNaAzoDGGL2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3Vy
# ZWQtY3MtZzEuY3JsMEsGA1UdIAREMEIwNgYJYIZIAYb9bAMBMCkwJwYIKwYBBQUH
# AgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYQGCCsG
# AQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
# ME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADAN
# BgkqhkiG9w0BAQsFAAOCAQEAMphWU/pi+dVNcVAIc489Z16RLtzJgZjfLM1trtDI
# 9wtYK+33CLBM7QhW+EL3bt5cFcqbmzlSQ7gH7uAmOOW/eUX4WyFcvEyVYu2aJg1/
# ML0f4JeCe1KQeGbRFjoYvC/5tUYuAEb/9Z7Nc3INtMjL4uhO67VrKlxHFKJOoDks
# AeeKRwhBBQP7Ga8odNXJxSA79s7NrDBUo5HNKc3R2I1N4jASYAfUNhee9H/8Kp85
# B/8+f2zNBpwJUs3ZdRSU0gH5okbw8OP8J4UPfolsRhPJ1+Kz6R/fVScud6VTLYFz
# iRJzdo1asGUJ9OxEh9u31bJcC0W9t6zSWcNgzu4ZT//q3zGCBU4wggVKAgEBMIGG
# MHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT
# EHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJl
# ZCBJRCBDb2RlIFNpZ25pbmcgQ0ECEA5SwjVXc07EY1PSyXDjKx8wCQYFKw4DAhoF
# AKCBnDAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w
# DAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUDuf7Bgt0VZuidKQQo5ndwQCB
# Ff4wPAYKKwYBBAGCNwIBDDEuMCygEIAOAFMAYwByAGkAcAB0AHOhGIAWaHR0cDov
# L3d3dy5jaXRyaXguY29tIDANBgkqhkiG9w0BAQEFAASCAQBBoEqaJ91S4NpVM3Wj
# xLWjFm2Hqll6KknJo0+nsbxISZq7yuMmOmWAfMz9U/x4D1c+pEebRIndhxHzJYlY
# a+3Ov0tU0l3uGW7fK2ms0RpOAO+cqlM2KmerlM5rx3HoXRtIe594IY/uHOTyoCHR
# 0YuK3gWSjVyWzrl/ugibmI2I8SUM/4kgMSjmOHH13NDHHmd5mnHKUz/454QQRbMu
# dKTbm3XM9YHpjldFWBiJ1bTn49TNswuEZfG8KvZ+oqIBzXo6mNfey91AUvNsp+PK
# 1BrW41bQMJNhamBgQSAaDwAyXApICUODiDAMjGSdztsIQZ0xwHSEb3nofC+q3sxj
# flwnoYIC/TCCAvkGCSqGSIb3DQEJBjGCAuowggLmAgEBMIGGMHIxCzAJBgNVBAYT
# AlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2Vy
# dC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3Rh
# bXBpbmcgQ0ECEAqSXSRVgDYm4YegBXCaJZAwDQYJYIZIAWUDBAIBBQCgggE0MBgG
# CSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIyMDMxMTIy
# MzQ1N1owLwYJKoZIhvcNAQkEMSIEII8yLVM/2VCm1ROuWCoA/CJkTvzsQM0vubSB
# Zf2T4QJKMIHIBgsqhkiG9w0BCRACLzGBuDCBtTCBsjCBrwQgsCrO26Gy12Ws1unF
# BnpWG9FU4YUyDBzPXmMmtqVvLqMwgYowdqR0MHIxCzAJBgNVBAYTAlVTMRUwEwYD
# VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAv
# BgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EC
# EAqSXSRVgDYm4YegBXCaJZAwDQYJKoZIhvcNAQEBBQAEggEAkD0IjwPCTm/TFLHi
# JVpTUGT5OTLWF70xWuoC+tNArXhlJgYSXJIyAPEzCh9n6/JF+GWCzqEx9axJV+hu
# iD73jsMiFbYPH301d60wHpHiI61LWEoQeIOwc+toqEOFpN9cK7HgPDB+yyt8zuK/
# FZwLDV1M2nPdaOxHxpLGOA6AbqWok+ZXpPpQDrhkE9sVLy/BjDdZEHl43cK6Chcb
# NpKJPZzarxUhtbX0BZ6BuHNT+teMWDLC+nju7gmU1XXZ9Z4vypAKUnzJoe5P42x2
# b+aI8dYcOlEIGXZQnit5DLd7fWkgQGo7drUsAlExvA/F2x7upEkA+b5cJWaeH0JH
# H3O8Gg==
# SIG # End signature block
3. Selecting the correct certificate
The third step retrieves the server’s hostname and uses it to find a matching certificate in the local computer certificate store. The certificate’s thumbprint is then passed to Enable-VdaSSL.ps1:
$myfQDN = hostname
C:\Install\VDAssl\Enable-VdaSSL.ps1 -Enable -CertificateThumbPrint (Get-ChildItem -path cert:\LocalMachine\My | where-object { $_.Subject -like "*$myFQDN*"} | Select-Object -ExpandProperty Thumbprint) -Confirm:$False
It is important to make sure that the correct certificate is selected, that it is valid and that the required permissions to access its private key are in place.
Automating the process with Ivanti AM
Rather than having to resolve these issues manually, all three steps can be added to a startup job in Ivanti AM. This ensures that the scripts are executed automatically whenever a Citrix server starts up.
However, simply running the scripts at startup is not enough. It is also a good idea to schedule a follow-up check to verify that the TLS configuration has actually been applied correctly.
If the check detects that the SSL configuration is incomplete or that the required listener is not running, Ivanti AM can run the configuration steps again.
This creates a straightforward recovery mechanism: the initial configuration runs at startup, followed by a check at a later time. If something is still not right, the configuration is applied again automatically.
Ideally, the check should go beyond confirming that the PowerShell script ran successfully. It should also verify that the expected TLS settings are in place and that the SSL listener is functioning as intended.
Conclusion
By combining these PowerShell scripts with Ivanti AM, you can create a practical way to deal with TLS issues that may occur after restarting Citrix servers.
The startup job takes care of the initial configuration, while a scheduled follow-up check verifies that everything is working as expected and triggers another run if necessary.
This reduces the need for manual intervention, makes the environment more reliable and helps prevent users from experiencing problems with their secure Citrix connections after a server restart.
Leave a Reply
Want to join the discussion?Feel free to contribute!