I wanted to write valid PowerShell function to do an XDPing the same way Citrix do with their Health Assistant tool. I was struggling a little to get the PowerShell code working as expected, so in the end I used JetBrains decompiler to decompile the VDAAssistant.Backend.dll, which is a component of the Citrix Health Assistant Tool. This allowed me to reverse engineer and understand how Citrix does it in C# .NET, which is then easy for me to convert to PowerShell. Yeah…okay, so I cheated at little 😉 I also released a C# (csharp) function I wrote back in 2020.
To test if the Broker service is reachable, listening and processing requests on its configured port, you can issue blank HTTP POST requests at the Broker’s Registrar service, which is located at /Citrix/CdsController/IRegistrar. If the first line displayed/returned is “HTTP/1.1 100 Continue“, then the Broker service responded and is deemed to be healthy.
Function XDPing { # To work out the best way to write this function I decompiled the VDAAssistant.Backend.dll from the # Citrix Health Assistant tool using JetBrains decompiler. # To test if the Broker service is reachable, listening and processing requests on its configured port, # you can issue blank HTTP POST requests at the Broker's Registrar service, which is located at # /Citrix/CdsController/IRegistrar. If the first line displayed/returned is "HTTP/1.1 100 Continue", # then the Broker service responded and is deemed to be healthy. param( [Parameter(Mandatory=$True)][String]$ComputerName, [Parameter(Mandatory=$True)][Int32]$Port, [String]$ProxyServer="", [Int32]$ProxyPort ) $URI = "http://$ComputerName/Citrix/CdsController/IRegistrar" $InitialDataToSend = "POST $URI HTTP/1.1`r`nContent-Type: application/soap+xml; charset=utf-8`r`nHost: ${ComputerName}:${Port}`r`nContent-Length: 1`r`nExpect: 100-continue`r`nConnection: Close`r`n`r`n" $FinalDataToSend = "X" $IsServiceListening = $False If ($ProxyServer -eq "" -OR $ProxyServer -eq $NULL) { $ConnectToHost = $ComputerName [int]$ConnectOnPort = $Port } Else { $ConnectToHost = $ProxyServer [int]$ConnectOnPort = $ProxyPort #write-verbose "Connecting via a proxy" -verbose } $Saddrf = [System.Net.Sockets.AddressFamily]::InterNetwork $Stype = [System.Net.Sockets.SocketType]::Stream $Ptype = [System.Net.Sockets.ProtocolType]::TCP $socket = New-Object System.Net.Sockets.Socket $saddrf, $stype, $ptype Try { $socket.Connect($ConnectToHost,$ConnectOnPort) #$socket.Connected $initialbytes = [System.Text.Encoding]::ASCII.GetBytes($InitialDataToSend) #write-verbose "Sending initial data..." -verbose #$InitialDataToSend $NumBytesSent = $socket.Send($initialbytes, $initialbytes.length,[net.sockets.socketflags]::None) #write-verbose "Sent $NumBytesSent bytes" -verbose $numArray = new-object byte[] 21 $socket.ReceiveTimeout = 5000 $NumBytesReceived = $socket.Receive($numArray) #write-verbose "Received $NumBytesReceived bytes" -verbose $output = [System.Text.Encoding]::ASCII.GetString($numArray) $finalBytes = [System.Text.Encoding]::ASCII.GetBytes($FinalDataToSend) #write-verbose "Sending final data..." -verbose #$FinalDataToSend $NumBytesSent = $socket.Send($finalBytes, $finalBytes.length,[net.sockets.socketflags]::None) #write-verbose "Sent $NumBytesSent bytes" -verbose $socket.Close() | out-null #write-verbose "Received data..." -verbose #$output if ($output -eq "HTTP/1.1 100 Continue") { $IsServiceListening = $True } } Catch { # } return $IsServiceListening }
Then you can call the function from within your script. Just give it the FQDN of a Delivery Controller and the port it’s listening on. You will either receive a return value of True or False from the function.
$ComputerName = "cxdt01.jouseconsulting.com" $Port = 80 XDPing -ComputerName $ComputerName -Port $Port
You’ll notice that you can also pass proxy parameters to the function. I added this as I was using Fiddler to test the function and make sure the raw data sent was correctly formatted. Therefore they are not mandatory parameters. I just left them there for test and development.
Enjoy!