{"id":1931,"date":"2019-05-16T22:14:24","date_gmt":"2019-05-16T14:14:24","guid":{"rendered":"http:\/\/www.jhouseconsulting.com\/?p=1931"},"modified":"2025-08-02T10:50:27","modified_gmt":"2025-08-02T02:50:27","slug":"xdping-powershell-function","status":"publish","type":"post","link":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/2019\/05\/16\/xdping-powershell-function-1931","title":{"rendered":"XDPing PowerShell Function"},"content":{"rendered":"\n<p>I wanted to write valid PowerShell function to do an XDPing the same way Citrix do with their\u00a0<a href=\"https:\/\/support.citrix.com\/article\/CTX207624\" target=\"_blank\" rel=\"noopener\">Health Assistant tool<\/a>. I was struggling a little to get the PowerShell code working as expected, so in the end I used\u00a0the <a href=\"https:\/\/www.jetbrains.com\/decompiler\/\" target=\"_blank\" rel=\"noopener\" title=\"\">JetBrains dotPeek .NET decompiler<\/a> 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&#8230;okay, so I cheated at little \ud83d\ude09\u00a0I also released a <a href=\"https:\/\/www.jhouseconsulting.com\/2023\/06\/13\/xdping-c-function-2443\" target=\"_blank\" rel=\"noopener\">C# (csharp) function<\/a> I wrote back in 2020.<\/p>\n\n\n\n<p>I used this PowerShell function in two scripts:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.jhouseconsulting.com\/2019\/03\/04\/controlling-the-starting-of-the-citrix-desktop-service-brokeragent-1894\" target=\"_blank\" rel=\"noopener\">Controlling the Starting of the Citrix Desktop Service (BrokerAgent)<\/a><\/li>\n<li><a href=\"https:\/\/www.jhouseconsulting.com\/2025\/06\/21\/the-citrix-virtual-apps-and-desktops-desktops-as-a-service-health-check-script-on-steroids-3181\" target=\"_blank\" rel=\"noopener\">The Citrix Virtual Apps and Desktops &amp; Desktops as a Service Health Check Script on Steroids<\/a><\/li>\n<\/ul>\n\n\n\n<p>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&#8217;s Registrar service, which is located at <strong>\/Citrix\/CdsController\/IRegistrar<\/strong>. If the first line displayed\/returned is &#8220;<strong>HTTP\/1.1 100 Continue<\/strong>&#8220;, then the Broker service responded and is deemed to be healthy.<\/p>\n\n\n\n<!--more-->\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\nFunction XDPing {\n  # This function performs an XDPing to make sure the Delivery Controller or Cloud Connector is in a healthy state.\n  # It tests whether the Broker service is reachable, listening and processing requests on its configured port.\n  # We do this by issuing a blank HTTP POST requests to the Broker's Registrar service. Including \"Expect: 100-continue\"\n  # in the body will ensure we receive a respose of \"HTTP\/1.1 100 Continue\", which is what we use to verify that it's in\n  # a healthy state.\n  # You will notice that you can also pass proxy parameters to the function. This is for test and development ONLY. I\n  # added this as I was using Fiddler to test the functionality and make sure the raw data sent was correctly formatted.\n  # I decided to leave these parameters in the function so that others can learn and understand how this works.\n  # To work out the best way to write this function I decompiled the VDAAssistant.Backend.dll from the Citrix Health\n  # Assistant tool using JetBrains decompiler.\n  # Written by Jeremy Saunders\n  param(\n    &#x5B;Parameter(Mandatory=$True)]&#x5B;String]$ComputerName, \n    &#x5B;Parameter(Mandatory=$True)]&#x5B;Int32]$Port,\n    &#x5B;String]$ProxyServer=\"\", \n    &#x5B;Int32]$ProxyPort,\n    &#x5B;Switch]$ConsoleOutput\n  )\n  $service = \"http:\/\/${ComputerName}:${Port}\/Citrix\/CdsController\/IRegistrar\"\n  $s = \"POST $service 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\"\n  $log = New-Object System.Text.StringBuilder\n  $log.AppendLine(\"Attempting an XDPing against $ComputerName on TCP port number $port\") | Out-Null\n  $listening = $false\n  If (&#x5B;string]::IsNullOrEmpty($ProxyServer)) {\n    $ConnectToHost = $ComputerName\n    &#x5B;int]$ConnectOnPort = $Port\n  } Else {\n    $ConnectToHost = $ProxyServer\n    &#x5B;int]$ConnectOnPort = $ProxyPort\n    $log.AppendLine(\"- Connecting via a proxy: ${ProxyServer}:${ProxyPort}\") | Out-Null\n  }\n  try {\n    $socket = New-Object System.Net.Sockets.Socket (&#x5B;System.Net.Sockets.AddressFamily]::InterNetwork, &#x5B;System.Net.Sockets.SocketType]::Stream, &#x5B;System.Net.Sockets.ProtocolType]::Tcp)\n    try {\n      $socket.Connect($ConnectToHost,$ConnectOnPort)\n      if ($socket.Connected) {\n        $log.AppendLine(\"- Socket connected\") | Out-Null\n        $bytes = &#x5B;System.Text.Encoding]::ASCII.GetBytes($s)\n        $socket.Send($bytes) | Out-Null\n        $log.AppendLine(\"- Sent the data\") | Out-Null\n        $numArray = New-Object byte&#x5B;] 21\n        $socket.ReceiveTimeout = 5000\n        $socket.Receive($numArray) | Out-Null\n        $log.AppendLine(\"- Received the following 21 byte array: \" + &#x5B;BitConverter]::ToString($numArray)) | Out-Null\n        $strASCII = &#x5B;System.Text.Encoding]::ASCII.GetString($numArray)\n        $strUTF8 = &#x5B;System.Text.Encoding]::UTF8.GetString($numArray)\n        $log.AppendLine(\"- Converting to ASCII: `\"$strASCII`\"\") | Out-Null\n        $log.AppendLine(\"- Converting to UTF8: `\"$strUTF8`\"\") | Out-Null\n        $socket.Send(&#x5B;byte&#x5B;]](32)) | Out-Null\n        $log.AppendLine(\"- Sent a single byte with the value 32 (which represents the ASCII space character) to the connected socket.\") | Out-Null\n        $log.AppendLine(\"- This is done to gracefully signal the end of the communication.\") | Out-Null\n        $log.AppendLine(\"- This ensures it does not block\/consume unnecessary requests needed by VDAs.\") | Out-Null\n        if ($strASCII.Trim().StartsWith(\"HTTP\/1.1 100 Continue\", &#x5B;System.StringComparison]::CurrentCultureIgnoreCase)) {\n          $listening = $true\n          $log.AppendLine(\"- The service is listening and healthy\") | Out-Null\n        } else {\n          $log.AppendLine(\"- The service is not listening\") | Out-Null\n        }\n        try {\n          $socket.Close()\n          $log.AppendLine(\"- Socket closed\") | Out-Null\n        } catch {\n          $log.AppendLine(\"- Failed to close socket\") | Out-Null\n          $log.AppendLine(\"- ERROR: $_\") | Out-Null\n        }\n        $socket.Dispose()\n      } else {\n        $log.AppendLine(\"- Socket failed to connect\") | Out-Null\n      }\n    } catch {\n      $log.AppendLine(\"- Failed to connect to service\") | Out-Null\n      $log.AppendLine(\"- ERROR: $_\") | Out-Null\n    }\n  } catch {\n    $log.AppendLine(\"- Failed to create socket\") | Out-Null\n    $log.AppendLine(\"- ERROR: $_\") | Out-Null\n  }\n  If ($ConsoleOutput) {\n    Write-Host $log.ToString().TrimEnd()\n  }\n  return $listening\n}\n<\/pre><\/div>\n\n\n<p>Then you can call the function from within your script. Just give it the FQDN of a Delivery Controller or Cloud Connector and the port it&#8217;s listening on, which is 80 by default. You will either receive a return value of True or False from the function.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\n$ComputerName = \"cxdt01.jhouseconsulting.com\"\n$Port = 80\n\nXDPing -ComputerName $ComputerName -Port $Port\n<\/pre><\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/www.jhouseconsulting.com\/xdpingoutput\"><img fetchpriority=\"high\" decoding=\"async\" width=\"487\" height=\"107\" src=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-content\/uploads\/2019\/05\/XDPingOutput.png\" alt=\"XDPing Output\" class=\"wp-image-1943\" srcset=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-content\/uploads\/2019\/05\/XDPingOutput.png 487w, https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-content\/uploads\/2019\/05\/XDPingOutput-300x66.png 300w\" sizes=\"(max-width: 487px) 100vw, 487px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>Enjoy!<\/p>\n\n\n","protected":false},"excerpt":{"rendered":"<p>I wanted to write valid PowerShell function to do an XDPing the same way Citrix do with their\u00a0Health Assistant tool. I was struggling a little to get the PowerShell code working as expected, so in the end I used\u00a0the JetBrains dotPeek .NET decompiler to decompile the VDAAssistant.Backend.dll, which is a component of the Citrix Health &#8230; <a title=\"XDPing PowerShell Function\" class=\"read-more\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/2019\/05\/16\/xdping-powershell-function-1931\" aria-label=\"Read more about XDPing PowerShell Function\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[14,626,659,5,91,38,242],"tags":[544,657,416,862,861,545,882,340,656,543],"class_list":["post-1931","post","type-post","status-publish","format-standard","hentry","category-citrix","category-cvad","category-powershell","category-scripting","category-vdi","category-xenapp","category-xendesktop","tag-citrixcdscontrolleriregistrar","tag-broker-registrar-service","tag-citrix","tag-cloud-connector","tag-delivery-controller","tag-http1-1-100-continue","tag-iregistrar","tag-powershell","tag-registrar-service","tag-xdping"],"aioseo_notices":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/1931","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/comments?post=1931"}],"version-history":[{"count":5,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/1931\/revisions"}],"predecessor-version":[{"id":3445,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/1931\/revisions\/3445"}],"wp:attachment":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/media?parent=1931"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/categories?post=1931"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/tags?post=1931"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}