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.
Here’s a screen shot from an image I built in Perth, Australia. Notice how the LastBootUpTime is several hours into the future as Perth is GMT +8.
Here’s a screen shot from an image I built in Saskatoon, Canada. Notice how the LastBootUpTime is several hours into the past as Saskatoon is GMT -6.
So to fix this we simply run a script in the master/gold image to…
- Remove the trigger from the Windows Time (w32time) Service
sc triggerinfo w32time delete
- Set the Windows Time (w32time) Service to start automatically
sc config w32time start= auto
Then the LastBootUpTime is accurate as seen in the following screen shot.
Microsoft provides some different options here.
- Method 1 is preferred and provides accuracy, which is what I’ve discussed here.
- remove the trigger from the Windows Time (w32time) Service
- sc triggerinfo w32time delete
- set the Windows Time (w32time) Service to start automatically
- sc config w32time start= auto
- remove the trigger from the Windows Time (w32time) Service
- Method 2 is better than default, but is not as accurate as method 1
- Change it to start when the network is ready (has an IP address)
- sc triggerinfo w32time start/networkon stop/networkoff
- Set the Windows Time (w32time) Service to start manually
- sc config w32time start= manual
- Change it to start when the network is ready (has an IP address)
- Method 3 is not a workable solution
I’ve documented this to provide discussion and guidance on how the Windows Time service should be configured for these use cases. From my findings tools such as the Citrix Optimizer and VMware OS Optimization Tool do not contain changes to this service.
Here is the ConfigureWindowsTimeService.ps1 (1271 downloads ) script
<#
This script will configure the Windows Time (w32time) Service
We need to reconfigure the Windows Time (w32time) Service to ensure that the
LastBootUpTime is accurate, as the default Manual trigger based on domain
membership seems to cause issues when using image deployment mechanisms for
RDSH and VDI workloads, such as Citrix PVS, Citrix MCS, View Composer, etc.
The default trigger stops (or does not start) the Windows Time service when
it's not domain joined. Without having a deep enough understanding on the
inner workings of these technologies, I assume that the default trigger on
the Windows Time service is not compatible with the way the imaging software
works on bootup to change the computer name and join to an Active Directory
computer object, as there may be a point during startup when it's not domain
joined.
Microsoft documents the issue and different options here:
- https://support.microsoft.com/en-au/help/2385818/windows-time-service-doesn-t-start-automatically-on-a-workgroup-comput
- https://learn.microsoft.com/en-au/troubleshoot/windows-client/active-directory/w32time-not-start-on-workgroup
As per the Microsoft documentation:
- Method 1 is preferred and provides accuracy, which is what this script provides.
- remove the trigger from the Windows Time (w32time) Service
sc triggerinfo w32time delete
- set the Windows Time (w32time) Service to start automatically
sc config w32time start= auto
- Method 2 is better than default, but is not as accurate as method 1
- Change it to start when the network is ready (has an IP address)
sc triggerinfo w32time start/networkon stop/networkoff
- Set the Windows Time (w32time) Service to start manually
sc config w32time start= manual
- Method 3 is not a workable solution
To query the existing triggers...
- sc qtriggerinfo W32Time
To add the Domain Join trigger back in and set startup to manual...
- sc triggerinfo w32time start/domainjoin
- sc config w32time start= manual
Script name: ConfigureWindowsTimeService.ps1
Release 1.0
Written by Jeremy Saunders (jeremy@jhouseconsulting.com) 14th April 2019
#>
#-------------------------------------------------------------
# Set Powershell Compatibility Mode
Set-StrictMode -Version 2.0
# Enable verbose, warning and error mode
$VerbosePreference = 'Continue'
$WarningPreference = 'Continue'
$ErrorPreference = 'Continue'
#-------------------------------------------------------------
$Service = "w32time"
# We can use the sc.exe command line utility
# Possible results using the sc.exe command line tool:
# [SC] ChangeServiceConfig SUCCESS
# [SC] OpenSCManager FAILED 5: Access is denied.
# [SC] OpenSCManager FAILED 1722: The RPC server is unavailable." --> Computer shutdown
# [SC] OpenService FAILED 1060: The specified service does not exist as an installed service." --> Service not installed
write-verbose "Removing the trigger for the `"$Service`" service..." -verbose
Invoke-Command {cmd /c sc.exe triggerinfo $Service delete} | out-null
write-verbose "Setting the `"$Service`" service to Automatic..." -verbose
Invoke-Command {cmd /c sc.exe config $Service start= auto} | out-null
# Unfortunately we need to force the $ExitCode variable to 0 when using Set-StrictMode
# in PowerShell scripts used in MDT/SCCM Task Sequences. It's a known bug.
$ExitCode = 0
Write-Verbose "Completed with an exit code of $ExitCode"
Exit $ExitCode
I hope this helps.



