Keeping Time using the Windows Time Service


Please click the +1 button if you find this post helpful.


Time is important. We rely on time to coordinate our activities with other people and prevent confusion. Just as time is important to us, so it is to our computers. The more connected they are, the more important it becomes. On a Windows PC, there's not much to worry about. If it's part of a domain, it is automatically configured to sync it's time with the domain controllers. Today, Windows computers, which are not joined to a domain, will try to sync with one of Microsoft's time servers by default.

This article will briefly discuss time synchronization within an Active Directory domain, and how to configure your PDC as an authoritative time source. Search the internet and you'll find countless articles on this very subject.

Network time synchronization is hierarchical, starting with Stratum 0, and extending down as far as to Stratum 256. Stratum 0 devices are at the root of it all. These are generally atomic clocks or GPS clocks, which are extremely reliable. They are directly connected to servers, which we refer to as Stratum 1 time servers. Stratum 2 time servers, synchronize directly with the Stratum 1 servers, employing special algorithms to ensure they maintain the best possible time. 

First, you'll need to pick a source to sync your domain time with. Some government agencies and larger organizations may have pre-designated authoritative time sources to sync with. If you don't then there's three basic options.

  1. Your Internet Service Provider
    First check with your ISP. This option is often overlooked, but if they have public NTP servers (most do), it's a good option. They're close by, so there's going to be less network latency & generally aren't heavily loaded. Many larger ISP's may even have Stratum 1 or 2 NTP servers, making them a better option than some NTP Pools.
  2. NTP Pools (http://support.ntp.org/bin/view/Servers/NTPPoolServers)
    Pools can included hundreds of NTP servers (although can include as few as 1 or 2 when using specific country pools) and employ a DNS round-robin method to load balance requests made to the pool. Because of this, you lose a bit of control over where you're really getting your time, though for most users, these pools provide a good source. The US pool (us.pool.ntp.org), at the time of this posting, included 710 sources.

    A major disadvantage of using NTP Pools is that that because they're based off DNS round-robin, the reliability of your time service is tied to the reliability of your DNS service.
  3. Stratum 2 NTP Servers (http://support.ntp.org/bin/view/Servers/StratumTwoTimeServers)
    These may appear to be the most reliable option, but that often isn't the case. Stratum 2 NTP servers may be farther away than other options, and since they're usually more heavily loaded, you may incur greater latency or on rare instances your requests may time out.

NOTE: Examples and screen shots in this article will use "pool.ntp.org", however this can be replaced with almost any other pool, Stratum 1 or Stratum 2 source.

Another option would be to obtain an atomic, GPS or other radio clock, that can connect to your server & establish your own Stratum 1 time server. While this option is out of the scope of this article, with the decreased cost of these types of devices, it is a viable option for many organizations.

Now that you've selected your source you need to tell your server how to use it. While you can install third party software, we're going to stick to using the built in time service. All of the following tasks should be performed on the domain controller which holds the PDC Emulator FSMO role. 

Open a command prompt, then type:
>  w32tm /config /syncfromflags:manual /manualpeerlist:0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org
> w32tm /config /update
> w32tm /resync

In general that will do the trick, however on Windows Server 2008, you may first need to register the time service. To do this simply type "w32tm /register" at a command prompt, then restart the server.

Using the Registry to Configure an Authoritative Windows Time Server
Alternativly you can also edit the registry to configure Windows Time. This can give you a greater degree of control. Below  is the body of a reg file, which could be used to set up a PDC as an authoritative time service.It can be copied and pasted in to Notepad and saved as time.reg then executed.


Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\Config]
"AnnounceFlags"=dword:00000005
"MaxNegPhaseCorrection"=dword:00000708
"MaxPosPhaseCorrection"=dword:00000708
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\Parameters]
"Type"="NTP"
"NtpServer"="0.pool.ntp.org,0x1 1.pool.ntp.org,0x1 2.pool.ntp.org,0x1 3.pool.ntp.org,0x1"
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\TimeProviders\NtpClient]
"SpecialPollInterval"=dword:00000384
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\TimeProviders\NtpServer]
"Enabled"=dword:00000001


Once the changes have been entered in to the registry, simply restart the Windows Time Service. You can do this through the Services MMC or by typing net stop w32time && net start w32time at a command prompt.

Now you have a Domain Controller in an Active Directory domain obtaining the correct time, (every 10 minutes if you used the registry settings above) and announcing itself as authoritative to other clients and servers in the domain. As long as things work the way they're suppose to, your set. Unfortunately, all too often I've seen the PDC Emulator drop it's list of NTP Servers to sync with resulting in time drift. We'll discuss how to prevent that in a future post.


PST (or other file) Locator Logon Script


Please click the +1 button if you find this post helpful.


Many organizations use Exchange for e-mail, and set mailbox size limits. In order to retain e-mail, users are then forced to archive e-mail to PST files stored on local PC's. For organizations concerned with retaining corporate knowledge and for administrations, these PST files can cause a problem, particularly since most of the time, users don't pay attention to where they are located. They easily get lost, and e-mail goes missing.

The logon script below was created a while back in order to track down PST files scattered across network shares and thousands of workstations in order to re-collect the e-mail and import it back in to a centralized e-mail archive system. While it's a pretty basic VB script, it dose the job and saved the organization (and US taxpayers) about $40,000.

The script can be easily modified to locate any file type, based on the extension, so it many possible uses. To use it you will first need to set up a database with a single table and five columns. The table name used in the script below is "PSTIndex". The column names used in the script are "ID", "LIUser", "Computer", "FileName", "FileSize". Once the database is created, you'll also need to modify the connection string in the  script to contain the proper database name, username and password. 

This script was thrown together pretty quickly, so it's pretty stupid. It simply finds PST's and writes them to the database. There is not checking to see if the data already exists or filtering out of undesirable objects. Used in conjunction with a SQL stored procedure to eliminate duplicates or a set of views or queries that gives you the results  you need & your in business. Also, while the script can be run independently, the nice part of having it run as a login script is that it runs in the user context, assigning a user name to any PST they have permissions to access. Also, since it runs every time the user logs in, if the file locations change, or new files are added, those changes are captured. The downside is that unless it's cleaned up, this database table can get very large very quickly.


'NAME:        PST Locator'
'AUTHOR:      England, Matthew D.'
'LANGUAGE:    VBScript'
'DESCRITPION: This script uses WMI to search for all PST files located on _'
'             drives that are mapped to the system it is running on. It then _'
'             writes the Computer Name, the File Name, including it's full _'
'             path, and the size of the file (in MB) to a SQL database OR text_'
'             file. This is intended to be used as a login script to locate PST _'
'             files for the LiveLink Archive Service to begin collecting & _'
'             archiving. It can also be scheduled to run on a per machine basis.'


'***************************** START OF CODE *****************************'
On Error Resume Next


Const ForAppending = 8
Const CONVERSION_FACTOR = 1024


DIM vLIUser


strComputer = "."


'DETERMINE LOGGED IN USER & STORE TO VARIABLE
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") 


Set colComputer = objWMIService.ExecQuery _
("Select * from Win32_ComputerSystem")


For Each objComputer in colComputer
vLIUser = objComputer.UserName
Next




'******USE FOR WRITING TO A DATABASE******'
Const adOpenStatic = 3
Const adLockOptimistic = 3


Set objConnection = CreateObject("ADODB.Connection")
Set objRecordSet = CreateObject("ADODB.Recordset")


      objConnection.Open("Provider=SQLOLEDB;Data Source=DATABASECONNECTION;" & _
        "Initial Catalog=DATABASENAME;" & _
             "User ID=USERNAME;Password=PASSWORD;")
             
'*****************************************'


'****ABSTRACT DATA FROM LOCAL MACHINE ****'
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")


Set colFiles = objWMIService.ExecQuery _
    ("Select * from CIM_Datafile Where Extension = 'pst'")
'*****************************************'




'******USE FOR WRITING TO A DATABASE******'
For Each objFile in colFiles
     objRecordset.Open "SELECT * FROM PSTIndex", _
        objConnection, adOpenStatic, adLockOptimistic
    
    objRecordset.AddNew
'   objrecordset("ID") = ""
    objRecordset("LIUser") = vLIUser
    objRecordset("Computer") = objFile.CSName
    objRecordset("FileName") = objFile.Name
    objRecordset("FileSize") = FormatNumber(objFile.FileSize / CONVERSION_FACTOR / CONVERSION_FACTOR, Default, Default, Default, GroupDigits)
    objRecordset.Update
    
    objRecordset.Close
Next
    objConnection.Close
'*****************************************'
'****************************** END OF CODE ******************************'