Bookmark and Share

 

Microsoft Scripting Guy Ed Wilson here. I finally had a chance to sit down and catch my breath from the 2010 Scripting Games. I reviewed some awesome scripts, and learned many new tricks. I happened to notice that my desktop computer clock was about five minutes slow. I checked and the domain controller was also slow. After looking around, I realized I had never set an external time source for my domain controller—something that was kind of easy to miss because it is running Windows Server 2008 R2 Core Edition.

After doing a bit of research, I ran across an excellent knowledge base article that talks about configuring an authoritative time server in Windows Server. The article KB816042 contains a number of registry entries. Hmm, I thought, an opportunity to write a Windows PowerShell script.

The complete ConfigureInternetTimeSource.ps1 script is seen here.

 

ConfigureInternetTimeSource.ps1

Param($computer = "Hyperv", $user = "nwtraders\administrator")
$psSession = New-PSSession -ComputerName $computer -Credential $user

Invoke-Command -Session $PSSession -ScriptBlock {
 $timeRoot = "HKLM:\SYSTEM\CurrentControlSet\services\W32Time"
 $ntpServer = "time.windows.com,0x1 nist1-ny.ustiming.org,0x1"
 Set-ItemProperty -path "$timeroot\parameters" -name type -Value "NTP"
 Set-ItemProperty -path "$timeroot\parameters" -name NtpServer -Value $ntpServer
 
 Set-ItemProperty -path "$timeroot\config" -name AnnounceFlags -Value 5
 Set-ItemProperty -path "$timeroot\config" -name MaxPosPhaseCorrection -Value 1800
 Set-ItemProperty -path "$timeroot\config" -name MaxNegPhaseCorrection -Value 1800
   
 Set-ItemProperty -path "$timeroot\TimeProviders\NtpServer" -name Enabled -Value 1
 Set-ItemProperty -path "$timeroot\TimeProviders\NtpClient" -name SpecialPollInterval -Value 900
 
 Register-WmiEvent -Query `
  "select * from __InstanceModificationEvent within 5 where targetinstance isa 'win32_service'" `
  -SourceIdentifier stopped

 Stop-Service -Name w32Time
 Wait-Event -SourceIdentifier stopped
 Start-Service -Name w32Time
 
 Unregister-Event -SourceIdentifier stopped
 Remove-Event -SourceIdentifier stopped
} # end invoke-command

Remove-PSSession -Session $psSession

Because I want to run this script against a remote computer, I create a Windows PowerShell remote session:

$psSession = New-PSSession -ComputerName $computer -Credential $user

After the session has been created, I use it to set the registry keys. But because I want all of my commands to be executed at the same time, I use a single Invoke-Command ScriptBlock. The command therefore begins as seen here:

Invoke-Command -Session $PSSession -ScriptBlock {

Everything else is basically between the curly brackets for the ScriptBlock. The commands to modify the registry are seen here:

$timeRoot = "HKLM:\SYSTEM\CurrentControlSet\services\W32Time"
 $ntpServer = "time.windows.com,0x1 nist1-ny.ustiming.org,0x1"
 Set-ItemProperty -path "$timeroot\parameters" -name type -Value "NTP"
 Set-ItemProperty -path "$timeroot\parameters" -name NtpServer -Value $ntpServer
 
 Set-ItemProperty -path "$timeroot\config" -name AnnounceFlags -Value 5
 Set-ItemProperty -path "$timeroot\config" -name MaxPosPhaseCorrection -Value 1800
 Set-ItemProperty -path "$timeroot\config" -name MaxNegPhaseCorrection -Value 1800
   
 Set-ItemProperty -path "$timeroot\TimeProviders\NtpServer" -name Enabled -Value 1
 Set-ItemProperty -path "$timeroot\TimeProviders\NtpClient" -name SpecialPollInterval -Value 900

After the registry entries have been made, it is time to stop and to start the w32time service. Before stopping the w32time service, I create a temporary WMI event consumer by using the Register-WmiEvent cmdlet. This will monitor the status of services on the computer. When an __InstanceModificationEvent occurs (such as stopping or starting a service), an event is triggered. The code to do this is seen here:

Register-WmiEvent -Query `
  "select * from __InstanceModificationEvent within 5 where targetinstance isa 'win32_service'" `
  -SourceIdentifier stopped

Now I stop the w32time service, and wait for the WMI event to be generated. After the event has been generated, I know that it is safe to start the service back up again:

Stop-Service -Name w32Time

 Wait-Event -SourceIdentifier stopped

 Start-Service -Name w32Time

The last thing to do is to clean up a little bit by unregistering the event consumer and deleting the events:

Unregister-Event -SourceIdentifier stopped

 Remove-Event -SourceIdentifier stopped

} # end invoke-command

When I am finished doing that, I remove the Windows PowerShell session by using the Remove-PSSession cmdlet as shown here:

Remove-PSSession -Session $psSession

Regedit can be used remotely to view registry keys in Hkey_Local_Machine and in Hkey_Users. Some of the registry settings modified by the script are seen in the following image.

Image of some registry settings modified by script

 

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys