Downloads
46799.zip

Microsoft Office Outlook 2003's Cached Exchange Mode lets Outlook store a copy of a user's mailbox and requested public folders in an offline folder store (OST) file. With Cached Exchange Mode enabled, Outlook is more tolerant of temporary network outages. The setting can sometimes reduce the amount of network traffic between the client and the Exchange server, and you must enable Cached Exchange Mode for Outlook's Junk E-mail Filter to work. But Cached Exchange Mode isn't always the best choice. In an environment in which users infrequently log on to geographically dispersed computers, the setting can cause extra network traffic as OST files are synchronized with the server. Over slow network links, it can take some time for users to see an up-to-date Inbox. In such scenarios, disabling (or not enabling) Cached Exchange Mode is often the better option.

Cached Exchange Mode is simple enough to configure for the default Outlook profile. Simply open the Control Panel Mail applet and click E-mail Accounts (or select E-mail Accounts from Outlook's Tools menu). Choose the View or change existing e-mail accounts option and click Next. Select Microsoft Exchange Server from the resulting list, then click Change. Select or clear the Use Cached Exchange Mode check box, click Next, then click Finish. If Outlook is running, you must close it before the change will take effect. Setting Cached Exchange Mode for new Outlook profiles is also fairly straightforward. You can use Office's Custom Installation Wizard or the outlk11.adm Outlook Administrative Template. Unfortunately, these methods apply only to new profiles and don't let you change the configured Cached Exchange Mode for existing profiles. To do this, you have to configure the appropriate setting in the registry. Although this method might not be the first choice for a simple change in setting, it can provide diagnostic information that's otherwise unavailable and can be used to change settings for nondefault mail profiles or multiple profiles—a task that's difficult to do using other methods.

Using CachedExchange.vbs to Set Cached Exchange Mode
The Cached Exchange Mode setting is stored under the HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Profile\13dbb0c8aa05101a9bb000aa002fc45a registry subkey (where Profile is the name of an Outlook profile). In the registry entry 00036601, you'll find a REG_BINARY value that holds 32 bits (4 bytes). REG_BINARY entries are sometimes treated as an array of bits, with each bit representing a discrete binary value.

To determine which bit or bits control Cached Exchange Mode, I used Regedit to export the registry subkey both before and after enabling and disabling the setting. I found that the 17th bit in the array (counting from the right) corresponds to Cached Exchange Mode. When the bit is set, Cached Exchange Mode is enabled, and vice versa. The 32nd bit (i.e., the leftmost bit) must match the 17th bit. Because the 4 bytes of data are profile-dependent and can vary among profiles even on the same computer, using a .reg file or a similar method to overwrite the data isn't the best idea. A better solution is to read, enable, or disable the appropriate bits without changing the other bits.

To do this, I wrote a VBScript script, CachedExchange.vbs, that you can use to read the registry entry and determine whether Cached Exchange Mode is enabled. You can also use the script to enable or disable the setting. To run the script, use the following syntax:

cscript CachedExchange.vbs \[/P:<profile>\]
  \[/enable | /disable\] \[/V\]</profile>

The script requires Windows Script Host's (WSH's) CScript host; the cscript keyword at the beginning of the command is required only if CScript isn't your default script host. Other than that keyword, the command options can appear in any order and aren't case sensitive. The /p switch lets you specify a particular Outlook profile (in case you use multiple profiles). If the profile name contains spaces, enclose it in double quotes (e.g., "My Profile"). If you don't specify a profile name, the script will read or configure Cached Exchange Mode for the default profile. Specify /enable or /disable to enable or disable Cached Exchange Mode. If you don't specify either switch, the script will report the current mode. The /v option causes the script to return verbose output, useful for troubleshooting purposes. Before running the script, be sure you understand its supporting functions.

Supporting Functions
WSH's WshShell object provides the RegRead and RegWrite methods for reading and writing data to the registry. When you use RegRead to read a REG_BINARY value (such as the one that defines the Cached Exchange Mode setting), the method's return value is an array of bytes. However, the RegWrite method doesn't support writing an array; you must specify a single value. Because of this limitation, I decided to use the Windows Management Instrumentation (WMI) StdRegProv class methods to read from and write to the registry.

Using the StdRegProv class for registry manipulation requires calling methods according to the registry data type. To simplify the StdRegProv method calls, I wrote a set of three wrapper functions: ReadValue(), KeyExists(), and ByteArrayToString().

The ReadValue() function enumerates a registry subkey by calling the StdRegProv method's EnumValues method, which returns two arrays that contain the value names and data types. This function iterates the array of value names, looking for the requested value. If it finds a match, the function uses the StdRegProv method call that corresponds to the returned data type. The function then returns the contents of the registry value and its data type to the calling code by modifying the ByRef arguments that are passed to the function. The function's return value will be 0 if the data was retrieved successfully. The WriteValue function is similar to the ReadValue function and calls the appropriate StdRegProv method depending on the type of data to be written.

The KeyExists() function calls the StdRegProv EnumKey method, which returns an array of subkey names. The function iterates the array and returns True if it finds a match.

The ByteArrayToString() function requires a parameter that contains an array of bytes. The function returns a string representation of this array as a series of hexadecimal digit pairs. The script uses this function to output the byte pairs in the REG_BINARY data.

Retrieving Outlook Information
To get the default Outlook profile, the script's GetDefaultProfile() function uses the ReadValue function to read the DefaultProfile value from the HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles registry subkey. The function returns an empty string if it can't find the DefaultProfile value or if the value isn't a REG_SZ value type.

The ProfileKeyExists() function uses the KeyExists() function to determine whether the specified Outlook profile exists in the registry; if so, the function returns True. The Main subroutine, which Listing 1 shows, uses the ProfileKeyExists() function to check for a valid profile name.

To determine the version of Outlook being used (and thus confirm that the system supports Cached Exchange Mode), the GetOutlookVersion() function uses the ReadValue() function to determine the path to outlook.exe from the HKEY_CLASSES_ROOT\CLSID\\{0006F03A-0000-0000-C000-000000000046\}\LocalServer32 registry subkey. This subkey exists when Outlook is installed, and the subkey's default entry contains the folder name and filename of the Outlook executable. The function's return value is a string representation of the executable's version number as returned by the FileSystemObject object's GetFileVersion method. The Main subroutine then uses the GetVersionPortion() function to determine whether outlook.exe is version 11 or later.

The GetExchangeConfig() function retrieves the REG_BINARY data from the specified Outlook profile. This function's return value contains an array of bytes, which the script uses as a parameter for the GetCachedExchangeMode() function. That function first verifies that the arrBytes parameter contains an array and that the array contains more than one member. If these conditions are met, the function determines whether the first bit in the second byte is set. If so, the function returns vbTrue (-1); otherwise, the function returns vbFalse (0). If the arrBytes parameter doesn't contain an array of at least one member, the function returns -2.

Setting the Mode
The SetCachedExchangeMode subroutine requires two parameters: a Boolean value that indicates whether to enable or disable Cached Exchange Mode and an array of bytes returned by the GetExchangeConfig() function. Similar to the GetCachedExchangeMode() function, the SetCachedExchangeMode subroutine first makes sure that the arrBytes parameter contains an array and has at least two members. If these conditions are met, the subroutine modifies the first two bytes in the array to enable or disable Cached Exchange Mode. To enable Cached Exchange Mode, the script uses the bitwise Or operator; to disable Cached Exchange Mode, it uses the bitwise And operator. Let's take a look at how the script uses these functions.

Inside the Main Subroutine
After declaring a set of constants and a single global variable to hold a StdRegProv object instance, the script calls the Main subroutine. The Main subroutine is responsible for parsing the script's command-line parameters, reading and writing the registry data, and so forth.

First, the Main subroutine uses the WScript.Arguments collection to determine the command-line parameters passed to the script. If the /? switch is present, the subroutine calls the Usage subroutine, which displays a usage message, then exits. If the /v switch exists, the subroutine sets the blnVerbose variable to True, which causes the script to output useful diagnostic information (i.e., the outlook.exe version, profile name, and the bytes stored in the registry).

The script uses the lngCLFlags variable as a bit map value and the CL_xxx constants as flags to detect which command-line switches were used. If /enable was specified, the CL_ENABLE bit is set; if /disable was specified, the CL_DISABLE bit is set. If both switches were used, the script displays a usage message, then exits.

Next, the script tries to call the GetOutlookVersion() function to retrieve the Outlook version and the GetVersionPortion() function to retrieve the major version number. If the major version is less than 11, the script displays an error message, then exits.

If no profile name has been specified, the script calls the GetDefaultProfile() profile function to determine the default profile name. Whether or not a profile name has been specified, the script then calls the ProfileKeyExists() function to determine whether the profile key exists in the registry. (If the key doesn't exist, the script returns an error message and quits.)

The script then calls the GetExchangeConfig() function to retrieve the contents of the 00036601 registry entry for the specified profile. The script then calls the GetCachedExchangeMode() function. (If this function returns the error value of -2, the script returns an error message and quits.)

Using the lngCLFlags variable, the script then decides what to do next. If neither /enable or /disable were specified in the command, the script simply reports whether Cached Exchange Mode is enabled or not. The script's exit code is 1 for enabled or 0 for not enabled. If /enable or /disable were specified, the script calls the SetCachedExchangeMode subroutine to modify the byte array appropriately, then calls the UpdateRegistry() function to write the bytes back to the registry. The script's exit code is 0 if the bytes were written successfully or non-0 in the event of a failure.

Overcoming the Limitations
CachedExchange.vbs provides an important capability that's missing from Group Policy: the ability to enable or disable Cached Exchange Mode for existing Outlook profiles. As with any script that modifies the registry, make backups, test thoroughly, and use the script with care.