| Improving Upon Microsoft's Daylight Saving Time Patch |
|
|
|
|
Like the original scripts, the new scripts work on all the Windows platforms mentioned in the article. However, with the new scripts, machines that have been updated once don't need to be updated again if the users move to a different time zone. All the users need to do is to select the new time zone in the machine's Date and Time Properties dialog box and they're covered.
By now, most IT professionals are aware of the daylight saving time changes that will take effect starting this year as a result of the Energy Policy Act passed by the U.S. government in August 2005. The Energy Policy Act changes the start and end dates of daylight saving time. This year, daylight saving time starts three weeks earlier (2 A.M. on March 11) and ends one week later (2 A.M. on November 4) compared with last year. These daylight saving time changes will affect more than just U.S. organizations because Canada has adopted the changes as well. In addition, the changes can affect organizations with worldwide operations. On the "Daylight Saving Time Help and Support Center" Web page (http://www.microsoft.com/windows/timezone/dst2007.mspx), Microsoft states that, "While the change in daylight saving time applies to U.S. and Canada, the change may impact customers based outside North America. Companies or organizations with operations, customers or vendors based in North America may be affected. In addition customers who interact or integrate with systems that are based in North America or rely on date/time calculations may be impacted." Although the daylight saving time changes don't pose as much a threat as the Y2K changes seven years ago, some IT professionals have already raised concerns about the negative impact the daylight saving time changes will have, especially on those organizations that still have a large number of computers running Windows 2000 Server and Windows 2000 Professional. This concern stems from the fact that Microsoft released a daylight saving time patch for Windows Server 2003 and Windows XP (http://support.microsoft.com/kb/928388) but not for Win2K because Microsoft ended mainstream support for it. The Microsoft article “How to configure daylight saving time for the United States in 2007” (http://support.microsoft.com/kb/914387) provides workaround methods for updating the daylight saving time dates of those OSs excluded from mainstream support. These methods involve either using the Time Zone Editor (tzedit.exe) or scripts that use registry imports. However, for large environments with hundreds of Win2K servers and workstations in use, these methods aren't feasible. Using the Time Zone Editor isn't practical because you must be physically at the machine. And using a registry import script isn't practical because the registry import may pose a security risk for large enterprise environments. Some companies disable the regfile association on all their servers because of such security risks. My company has a large, mixed environment of Windows OSs, so I wrote my own script, SetDSTDates.vbs, to automate the daylight saving time changes. Unlike the Microsoft patch, SetDSTDates.vbs applies the daylight saving time changes to Win2K as well as Windows 2003 and XP machines. Specifically, you can use the script on the following platforms:
You can download SetDSTDates.vbs from the Scripting Pro VIP Web site. Before I tell you how to use and test SetDSTDates.vbs, let's explore how this script works. Exploring SetDSTDates.vbs As Listing 1 (bottom of the page) shows, the setDSTValue function begins by declaring all its variables, then calls the getTimeZoneName function. When I was writing SetDSTDates.vbs, I discovered that three binary values in the registry had to be updated. However, the path to one of those values is based on the time zone set for the target computer. So, the getTimeZoneName function obtains the name of the time zone for the target computer. As Listing 2 (bottom of the page) shows, the function obtains the time-zone name by querying Windows Management Instrumentation's (WMI's) Win32_TimeZone class. After the setDSTValue function has the time-zone name, it appends this name to the registry path HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\ and sets the resulting registry key to the strKeyPath1 variable, as callout A in Listing 1(bottom of the page) shows. With this setup, you can launch the script from a machine that has a different time zone than that of the target machine, assuming you pass in the remote computer's name as an input parameter to the function. (More information about using the script on remote computers appears in the "Using the Script" section.) The value name for the registry key in strKeyPath1 is TZI. In the registry, TZI is a REG_BINARY value. Because SetDSTDates.vbs uses WMI's StdRegProv class to manipulate the target computer's registry, the script uses the WMI data type of uint8 array (i.e., an array of hexadecimal values that don't exceed 255, or hex FF) to specify the TZI value. (For information about how registry data types map to the WMI data types used by StdRegProv, see the Microsoft article "Mapping a Registry Data Type to a WMI Data Type" at http://msdn2.microsoft.com/en-us/library/aa392326.aspx.) As callout B in Listing 1 shows, the array value is set to the arrDSTTZValue variable. The value in arrDSTTZValue defines the new dates for daylight saving time. Changing the TZI value alone will change the daylight saving time dates. However, in order for the daylight saving time changes to update automatically, you need to update two other binary values—StandardStart and DaylightStart—in the registry. Both binary values are part of the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation key. The setDSTValue function defines the StandardStart and DaylightStart values in uint8 array format and sets to them to the arrDSTSSValue and arrDSTDSValue variables, respectively. The value in arrDSTSSValue updates the date when standard time starts, whereas the value in arrDSTDSValue updates the date when daylight saving time begins. With the correct registry keys and binary values defined in their respective variables, the compareDSTDate function, which Listing 3 shows, takes center stage. The setDSTValue function calls the compareDSTDate function three times to compare the target machine's current TZI, StandardStart, and DaylightStart binary values with the values in the arrDSTTZValue, arrDSTSSValue, and arrDSTDSValue variables, respectively. The compareDSTDate function returns the value "Updated" when the corresponding values match and "NotUpdated" when they don't match, as callout A in Listing 3 shows. The setDSTValue function stores the returned values from the three compareDSTDate function calls in the variables named strDSTTZComp, strDSTSSComp, and strDSTDSComp. When the strDSTTZComp, strDSTSSComp, and strDSTDSComp values all read "Updated", the setDSTValue function returns the value “Already updated,” as callout C in Listing 1 shows. This value prompts the script's RuntheScript subroutine to display a message that the machine has already been updated, and the script ends. When one or more of the strDSTTZComp, strDSTSSComp, and strDSTDSComp values read "NotUpdated", the setDSTValue function calls the setDSTDate function three times (once for each binary value), as callout D in Listing 1 shows. The setDSTDate function, which Listing 4 shows, performs the actual registry modifications. As callout A in Listing 4 shows, if the setDSTDate function fails to make a registry modification, the returned value for that particular function call is "Error". Otherwise, the returned value is "Success". The setDSTValue function stores the returned values from the three setDSTDate function calls in the strSetDST1, strSetDST2 and strSetDST3 variables. The setDSTValue function then checks the values in these variables to see whether all three setDSTDate function calls were successful. If so, the script displays a screen message that reports the daylight saving time operation was successful. Otherwise, the message reports that the operation failed. The script then ends. Using the Script Also included in this article's download package is the SetDSTDates_Cmd.vbs script, which you can use to update daylight saving time on a remote machine from a command line. (SetDSTDates_Cmd.vbs will only run from the command line. Double-clicking this script will generate an error message.) Because SetDSTDates_Cmd.vbs uses WMI to update the registry, you can run the script against multiple machines from a single location. In this case, you'd need to integrate SetDSTDates_Cmd.vbs into another script, such as a script that can query computers in an Active Directory (AD) domain. When the daylight saving time update is deployed in this manner, there's no need to restart the machines for the changes to take effect. Before you use SetDSTDates_Cmd.vbs in this manner, though, remember that the daylight saving time dates in other countries likely differ from the new daylight saving time dates in the United States and Canada. (The Microsoft article "How to configure daylight saving time for the United States in 2007" contains information about the countries adopting the new daylight saving time standard and the countries that use different daylight saving time dates.) In addition, two states (Arizona and Hawaii) and five U.S. territories (American Samoa, Guam, the Northern Marianas, Puerto Rico, and the Virgin Islands) have chosen not to observe daylight saving time. If you update multiple machines in a domain but some of the machines in that domain are in areas that don't follow the new daylight saving time standard, you'll be creating problems for those machines. One way to avoid this problem is to group computers in AD domains into organizational units (OUs), then have the script target only those machines in certain OUs. Another way you can make the daylight saving time changes on multiple machines is to use Group Policy to deploy SetDSTDates_Silent.exe as a single startup script. SetDSTDates_Silent.exe is a self-executable program and is encrypted, so the deployment of this script with Group Policy will be more secure than a script that uses a registry import. You'll find SetDSTDates_Silent.exe in this article's download package. In this case, each target computer will require a restart. Because SetDSTDates_Silent.exe runs in silent mode, it writes two application event log entries to let you know the script's results:
Testing the Script and Validating Its Results You can validate the results by following these steps:
After you update the machines in your network, you'll likely want to keep SetDSTDates.vbs and the other scripts handy. You should apply the daylight saving time update to any newly built machine (with the exception of Windows Vista) or rebuilt machine you later install in your network. You can easily accomplish this by using SetDSTDates_Silent.exe and Group Policy. Script Can Help Alleviate Mixed Platform Problems
Listing 1 ' Listing 1: The setDSTValue Function Private Function setDSTValue(ByVal strComputer) Dim strTimeZoneName, strKeyPath1, strValueName1, strKeyPath2, strValueName2 Dim strKeyPath3, strValueName3, arrDSTTZValue, arrDSTSSValue, arrDSTDSValue Dim strDSTTZComp, strDSTSSComp, strDSTDSComp, strSetDST1, strSetDST2, strSetDST3 ' Get the name of the time zone for the target computer. strTimeZoneName = getTimeZoneName(strComputer) ' Define variables for the registry key and value names. ' ******* BEGIN CALLOUT A ******* strKeyPath1 = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\" & _ strTimeZoneName ' ******* END CALLOUT A ******* strValueName1 = "TZI" strKeyPath2 = "SYSTEM\CurrentControlSet\Control\TimeZoneInformation" strValueName2 = "StandardStart" strKeyPath3 = "SYSTEM\CurrentControlSet\Control\TimeZoneInformation" strValueName3 = "DaylightStart" ' Define the variables for the three registry settings. ' ******* BEGIN CALLOUT B ******* arrDSTTZValue = Array(&H68,&H01,&H00,&H00,&H00,&H00,&H00,&H00, _ &HC4,&HFF,&HFF,&HFF,&H00,&H00,&H0B,&H00,&H00,_ &H00,&H01,&H00,&H02,&H00,&H00,&H00,&H00,&H00, _ &H00,&H00,&H00,&H00,&H03,&H00,&H00,&H00,&H02, _ &H00,&H02,&H00,&H00,&H00,&H00,&H00,&H00,&H00) ' ******* END CALLOUT B ******* arrDSTSSValue = Array(&H00,&H00,&H0B,&H00,&H01,&H00,&H02,&H00, _ &H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00) arrDSTDSValue = Array(&H00,&H00,&H03,&H00,&H02,&H00,&H02,&H00, _ &H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00) ' Check the current daylight saving time dates to see whether they've already been updated. strDSTTZComp = compareDSTDate(strComputer, strKeyPath1, strValueName1, arrDSTTZValue) strDSTSSComp = compareDSTDate(strComputer, strKeyPath2, strValueName2, arrDSTSSValue) strDSTDSComp = compareDSTDate(strComputer, strKeyPath3, strValueName3, arrDSTDSValue) ' ******* BEGIN CALLOUT C ******* ' If the current daylight saving time dates have been updated, skip the update routines below. If strDSTTZComp = "Updated" And strDSTSSComp = "Updated" _ And strDSTDSComp = "Updated" Then setDSTValue = "Already updated" Exit Function ' ******* END CALLOUT C ******* Else ' ******* BEGIN CALLOUT D ******* ' Set daylight saving time for the current time zone. strSetDST1 = setDSTDate(strComputer, strKeyPath1, strValueName1, arrDSTTZValue) ' Set the start date of standard time. strSetDST2 = setDSTDate(strComputer, strKeyPath2, strValueName2, arrDSTSSValue) ' Set the start date of daylight saving time. strSetDST3 = setDSTDate(strComputer, strKeyPath3, strValueName3, arrDSTDSValue) ' ******* END CALLOUT D ******* ' Check to see whether all the setDSTDate function calls were successful. If so, report ' that the daylight saving time operation was a success. Otherwise, report that it failed. If strSetDST1 = "Success" And strSetDST2 = "Success" And strSetDST3 = "Success" Then setDSTValue = "Success" Else setDSTValue = "Failed" End If End If End Function
Listing 2 ' Listing 2: The getTimeZoneName Function Private Function getTimeZoneName(ByVal strComputer) Dim objWMIService, colTimeZone, objItem Set objWMIService = GetObject("winmgmts:" _ & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") Set colTimeZone = objWMIService.ExecQuery("Select * from Win32_TimeZone") For Each objItem In colTimeZone getTimeZoneName = objItem.StandardName Next Set objWMIService = Nothing: Set colTimeZone = Nothing End Function
Listing 3 ' Listing 3: The compareDSTDate Function Private Function compareDSTDate(strComputer, strKeyPath, strValueName, arrBinValue) Const HKEY_LOCAL_MACHINE = &H80000002 Dim objRegistry, arrCurrentValue, objItem, strBinValue1, strBinValue2 Set objRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _ strComputer & "/root/default:StdRegProv") objRegistry.GetBinaryValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,arrCurrentValue If Not IsNull(arrCurrentValue) Then For Each objItem In arrCurrentValue strBinValue1 = strBinValue1 & objItem Next For Each objItem In arrBinValue strBinValue2 = strBinValue2 & objItem Next ' ******* BEGIN CALLOUT A ******* If strBinValue1 = strBinValue2 Then compareDSTDate = "Updated" Else compareDSTDate = "NotUpdated" End If ' ******* END CALLOUT A ******* End If Set objRegistry = Nothing End Function
Listing 4 ' Listing 4: The setDSTDate Function Private Function setDSTDate(strComputer, strKeyPath, strValueName, arrBinValue) Const HKEY_LOCAL_MACHINE = &H80000002 Dim objRegistry Set objRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _ strComputer & "/root/default:StdRegProv") On Error Resume Next objRegistry.SetBinaryValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,arrBinValue ' ******* BEGIN CALLOUT A ******* If Err Then setDSTDate = "Error" Else setDSTDate = "Success" End If ' ******* END CALLOUT A ******* Err.Clear On Error Goto 0 Set objRegistry = Nothing End Function |
| < Prev | Next > |
|---|








