Installing, Configuring, Securing and Using MDT Webservices – Part 3

In Part 1 we walked through the installation and configuration of Deployment Webservices.

In Part 2 we walked through securing the Webservice.

In this part I will demonstrate how to use the Webservice via a PowerShell script to securely move a computer object during the operating system deployment (OSD) task sequence using Microsoft Deployment Toolkit (MDT).

To achieve the end result we need to:

  • Create some deployment share rules in MDT (CustomSettings.ini)
  • Add two “Run PowerShell Script” tasks to the Task Sequence
  • Download and place the PowerShell Script into the deployment share Scripts folder

Read more

Best Practice for the Windows Client Side Caching (CSC) kernel driver in VDI workloads

It’s been a best practice for a long time to disable Offline Files in both RDSH and VDI workloads. However, this has only ever been based around the Offline Files (CscService) service and some registry tweaks.

What people don’t realize is that you must properly disable Offline Files in all VDI workloads by also disabling the Windows Client Side Caching (CSC) kernel driver as outlined by Ned Pyle here.

Even with the Offline Files (CscService) service disabled, the Windows Client Side Caching (CSC) kernel driver is still loaded at Windows startup, creating unnecessary noise and potentially impeding performance when users access a network share.

The following example is a screen shot of Process Monitor monitoring a zpaq64.exe process extracting a file to a network drive. Note how it’s continually attempting to access the CSC (Client-Side Caching) area before the network share, even though Offline Files is disabled. This creates a large number of NAME NOT FOUND errors, and adds a potential delay to the execution time.

Read more

Best Practice for the Windows Time (W32TIME) Service for RDSH and VDI workloads

When using image deployment mechanisms for RDSH and VDI workloads, such as Citrix PVS, Citrix MCS and VMware View Composer, it’s extremely important to reconfigure the Windows Time (w32time) Service to ensure that the LastBootUpTime is accurate. If it’s not accurate, it effects monitoring, the correlation of log data, event triggers, etc.

The default Manual trigger of the Windows Time service is based on domain membership, which seems to cause issues as the image boots and changes name to the correct target name. Without having a deep enough understanding on the inner workings of these technologies, I can only assume that the default trigger of the Windows Time service is not compatible with the way the imaging mechanisms work on boot up to change the computer name and join to an Active Directory computer object. There may be a point during startup where Windows detects that it’s not domain joined and therefore stops the Windows Time service, which seems to throw the time out.

Read more

XDPing PowerShell Function

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 the JetBrains dotPeek .NET 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.

I used this PowerShell function in two scripts:

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.

Read more

Controlling the Starting of the Citrix Desktop Service (BrokerAgent)

UPDATED 17th November 2025

  • Improved the check for the Personality.ini and MCSPersonality.ini files based on the history of VDA changes.
  • Replaced the Get-LastBootTime function with the Get-UpTime function. This starts to phase out the reliance on the Get-WmiObject cmdlet, with preference to use the Get-CimInstance cmdlet.
  • Added a group policy update (gpupdate) to be invoked before it reads the VDAHelper registry values. I’ve
    found this hit and miss with MCS images. So a gpupdate helps to ensures that the registry values are in
    place.
  • Added a check to see if it is a Citrix MCS Master Image. The script will check the following value:
    Key: HKEY_LOCAL_MACHINE\SOFTWARE\Citrix\Configuration
    Type: DWORD
    Value: MasterImage
    Data: 1
    This is important so that it starts the Broker service immediately so that it does not cause any issues
    with the image preparation process.

UPDATED 21st July 2025

  • Added extra error checking and further improved the coding
  • When we set the Winlogon DefaultDomainName value we also need to set AutoAdminLogon value to 0 and clear the DefaultUserName value.
  • If the Winlogon AutoAdminLogon value is 0 (disabled), and the TriggerOnTaskEndEvent is set to 1 (enabled), we change the TriggerOnTaskEndEvent to 0 (disabled). This reduces unnecessary further delay waiting for an event that will never run.

UPDATED 14th July 2025

  • Replaced the Get-DeliveryControllers function with the Get-ListOfDDCs function. The name of the function may have been misleading given that it’s for both Delivery Controller or Cloud Connector addresses. It now allows for the C:\Personality.ini and C:\MCSPersonality.ini for MCS deployments.
  • Added the UsePersonalityini value to the VDAHelper registry values, which is used to call the updated Get-ListOfDDCs function.
  • Updated the XDPing function
  • Changed the flow of some of the code

UPDATED 31st January 2023

  • Added the DefaultDomainName value to the registry, which tells this script to set the Winlogon DefaultDomainName value in the registry once the autologon process has started. This allows us to use a local account for the Autologon process instead of a Domain service account, which won’t work if the Winlogon DefaultDomainName value has already been set to your preferred domain. This reduces the security footprint when using service accounts by allowing us to easily rotate passwords using a local account for the autologon process for each image build. Refer to my article Priming a Non-persistent Windows Image using an Autologon Process with an Auto Logoff Timer to understand how this works.
  • You can now use the policies registry key for the registry settings:
    • Policies Key: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Citrix\VDAHelper
    • Preferences Key: HKEY_LOCAL_MACHINE\SOFTWARE\Citrix\VDAHelper
    • Values set under the Policies key have a higher priority.

UPDATED 30th April 2022

  • Improved the code so that the logon/logoff events are detected more efficiently across all Windows Operating Systems.

UPDATED 17th March 2020

  • Enhanced the checking for the ListofDDCs registry value by also checking the Policies key structure.

UPDATED 18th July 2019

  • The creation of the Scheduled Task needed for this script can be found in the Citrix Virtual Delivery Agent (VDA) Post Install Script. It’s important that the priority of the Scheduled Task is set to normal to prevent it from being queued.
  • Enhanced the Get-LogonLogoffEvent function for backward support of Windows 7/2008R2

UPDATED 16th May 2019

  • Added much more logging with timestamps to help debug issues and correlate events. You’ll see from the screen shot of the log file below that it’s now quite comprehensive.
  • Ensured that the format of the logging timestamp and LastBootUpTime were aligned so that its accuracy can be easily verified as I documented here.
  • Added an XDPing function I wrote to health check the Delivery Controllers.

This is a process I’ve been working on perfecting for a couple of years now. I’ve got it to a point where it works perfectly for my needs, and has been very reliable over the last few months, so I decided it was ready to release to the community.

The challenge has always been that as a Session Host boots up the Citrix Desktop Service (BrokerAgent) starts and registers with the Delivery Controllers before the boot process is complete. Therefore, a user can potentially launch an application/desktop during the tail end of the boot process. When this happens it may fail the session launch, which can leave the Session Host in an unhealthy state, such as a stuck prelaunch state, with the user potentially needing to involve the Service Desk to clear the issue. So managing the timing of the start of the Citrix Desktop Service (BrokerAgent) is extremely important to ensure that your Session Hosts have completed their startup process before registering with the Delivery Controllers. This can be easier said than done!

To add to this complexity, power managed Workstation OS pools can get into a reboot loop if you use an autologon process. I use an autologon process similar to what George Spiers documented in his article “Reduce Citrix logon times by up to 75%“. So if the Session Host has registered with the Delivery Controllers before the autologon process has logged off, the logoff process will trigger another reboot. This can become a real problem to manage.

Read more

Addressing the PowerShell Garbage Collection bug

There is a known bug where PowerShell does not correctly manage a garbage collection whilst executing a pipeline or loop of an object.

Simply using [System.GC]::Collect() within the pipeline or loop does not work as expected. Memory continually grows until the pipeline or loop has completed. This becomes a serious problem if you’re script is processing large objects. You can potentially exhaust memory resources and your script will fail with out of memory errors. This has been driving me nuts for years, as many of my Active Directory Health Check, Audit and Remediation Scripts process large objects in large environments.

There is a good overview of the bug here: No garbage collection while PowerShell pipeline is executing. Whilst this post claims that it seems to have been resolved in PowerShell 5, this doesn’t appear to be the case from my testing.

Read more

Script to modify the defaultSecurityDescriptor attribute on the Group-Policy-Container schema class object

Last week I published an article about the changes in the behavior of Group Policy processing after the deployment of security update MS16-072 under KB3163622. It included a script to assist with the remediation of Group Policy permissions: Script to report on and remediate the Group Policy security change in MS16-072.

Of course that’s not where it ends. What about new Group Policies? Do you create a procedure that requires you to add “Domain Computers” with Read permission every time you create a new Group Policy Object (GPO)? No…of course not!

What we need to do now is change the defaultSecurityDescriptor attribute on the Group-Policy-Container schema class object so that new GPOs are created with Domain Computers having Read permissions by default. Microsoft didn’t released an official script or method to do this, so here’s the next best thing.

Read more

Script to report on and remediate the Group Policy security change in MS16-072

Computer can read again!

On June 14th 2016 Microsoft released security update MS16-072 under KB3163622 that changes the behavior of Group Policy processing so that user group policies are now retrieved by using the machine’s security context instead of the user’s security context. This is a by-design behavior change from Microsoft to protect computers from a security vulnerability.

Update 23/06/2016: Microsoft finally released an official response to this patch via the Directory Services team: Deploying Group Policy Security Update MS16-072 \ KB3163622

This is a problem for people that implement security filtering on their Group Policy Objects (GPOs), as it removes the default Authenticated Users group not only from the “Apply group policy” permission, but also from the “Read” permission.

Read more

Script to Import and Bind a Certificate to the Default Web Site

SSL CertificateThis Powershell script will import and bind a certificate to the Default Web Site. I use this script for Citrix StoreFront and Director deployments, but it’s written to be very flexible and versatile so can be used for other tasks.

The original idea came from scripts written by Thomas Albaek and Jerome Quief for Citrix StoreFront.

The way I’ve written this script it will actually remove any existing certificate bindings first, which is really handy for pushing out updated certificates as I found that other scripts written to do this task would fail when run more than once.

Read more

Script to Change the Drive Letter of all CDROM and DVD Drives

CD

This PowerShell script will change the drive letter of all CDROM & DVD Drives found starting from whatever is set as $LastDriveLetter variable, working backwards until it finds an available drive letter.

Too many IT Pros leave CDROM/DVD Drives as the drive letter Windows assigns them when first detected, which is typically usually either D: or E:. Then when adding new volumes they choose the next available drive letter instead of moving the CDROM/DVD Drive(s) out of the way. I’m a stickler for this, as I like to see consecutive drives letters used for the logical disks.

The easiest way to ensure all builds are standardised is to run a script during the build process that assigns a new drive letter to the connected CDROM/DVD Drive(s).

Read more