The self-healing XenDesktop VM – Part 2

It’s taken me a bit longer to get around to posting the second part of this, apologies to those of you that have been waiting for it. I got a lot of great feedback and questions about the first part and there was a certain commonality among the questions. In my code, after determining that the VM was not registered, it was calling a method called registerVM(). There was a lot of interest in what exactly that method does to attempt to register the VM so I am going to go in to greater detail for that code in this post.

In a nut shell, the method performs any required actions that you want to perform to get the VM to register. These actions could be very specific to your own environment so I am going to go through a few of the more common ones that should generally apply to most deployments. These are recycling services, clearing the DNS cache and validating the DDC entry in the registry.

When it comes to services, the main one to worry about for XenDesktop registration is the Citrix Desktop Service. Now you may have other services that you want to recycle also and the process will be the same for them as the following example. In order to recycle the service, you have to first stop it. This can be a problem if the service is in a hung state, you could tell it to stop but it will just hang there, never stopping and your stop command will eventually time out. In order to avoid this problem, I find that it is best to just actually kill the process and then start it again.

So let’s look at our first piece of code. In the below example, we are going to kill the process for the Citrix Desktop Service. Now, depending on what version of the VDA you have running, the name of this process will be either workstationagent.exe or brokeragent.exe. The string variable brokerProcessName has been used here for that information. You would need to set this in your code before using it. Important to note here that you don’t need to include the “.exe” when setting that variable.

I’m using the Process class to generate an array of all the processes that contain that name, there should be only one. The result value generates an array though so we have to quickly iterate through it and kill the process.

Process[] brokerProcess = Process.GetProcessesByName(brokerProcessName);
foreach (Process p in brokerProcess)
{
p.Kill();
p.WaitForExit(5000);
p.Dispose();
}
}

Before we restart the Citrix Desktop Service, let’s do the other maintenance tasks so that it has a better chance of starting cleanly and getting the VM registered. The next code snippet is going to clear the DNS cache on the VM. I have never been able to find a way to clear the DNS cache programmatically using the .Net Framework so the way that I am doing it is to create a process instance of cmd.exe and issue the flush command using that.

Using the Process class I first create a new process. I then create a ProcessStartInfo object and configure that with the settings that I want. These are having the process window hidden, the name of the file to run the process, cmd.exe and the arguments to start the process with.  I apply this ProcessStartInfo object to the Process object and start it. I set a timeout of 5 seconds, in reality it should be near instant.

Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = “cmd.exe”;
startInfo.Arguments = “/C ipconfig /flushdns”;
process.StartInfo = startInfo;
process.Start();
process.WaitForExit(5000);

Next, let’s validate that the DDC entry in the registry is correct. Like any good administrator, I’m sure that you will have more than one DDC in your farm. The string variable used here for the DDC’s is listOfDDCs. You will need to populate that in your code with the values for your own farm. We do a quick check to see if the VM is 32 or 64 bit and then write the DDC’s to the registry. The reason for the check if that 64-bit will require an additional step to open the base key in Registry64 view. We then open the VirtualDesktopAgent key and write the listOfDDCs variable to the ListOfDDCs string value.

if (Environment.Is64BitOperatingSystem)
{
string keyPath = “Software\\Citrix\\VirtualDesktopAgent”;
var view64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var key = view64.OpenSubKey(keyPath, true);
key.SetValue(“ListOfDDCs”, listOfDDCs, RegistryValueKind.String);
key.Close();
}
else
{
string keyPath = “Software\\Citrix\\VirtualDesktopAgent”;
RegistryKey key = Registry.LocalMachine.OpenSubKey(keyPath, true);
key.SetValue(“ListOfDDCs”, listOfDDCs, RegistryValueKind.String);
key.Close();
}

We are now ready to start the Citrix Desktop Service again. I create a new instance of the ServiceController class using the brokerProcessName variable that we used when killing the process earlier on. I set a timeout of 20 seconds and then go ahead and start the service.

ServiceController vdaService = new ServiceController(brokerProcessName);
TimeSpan timeout = TimeSpan.FromMilliseconds(20000);
vdaService.Start();
vdaService.WaitForStatus(ServiceControllerStatus.Running, timeout);
vdaService.Dispose();

And we are done. Those key steps will likely resolve the vast majority of unregistered VM’s in XenDesktop. You may have additional custom steps for your environment that would assist with getting the VM to register. For example, in my own I am also performing a check to see what OU the VM is contained within in Active Directory due to some required GPO’s. You will know your environment best but regardless, the steps that we have covered here should be pretty much universal. It is worth noting that the code that is used to kill and restart the Citrix Desktop Service can be used for any other service that you feel would benefit from recycling, all you have to do is change the name in the variable, or use a different one.

Questions or comments, feel free to contact me. Email: sasponto(AT)gmail(DOT)com Twitter: @SasPonto

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">