MSEXTMZ.EXE is the tool which Exchange Administrators can use to apply time zone changes to a calendar for one or many users. MSEXTMZ does not itself contain any logic for updating calendars, that logic is contained in an Office supplied binary called TZMOVE.EXE. This document is not a guide to how to run MSEXTMZ or how to configure it. It is a detailed description of how MSEXTMZ operates, which conditions constitute a specific error, and common resolutions for known errors. It is based off of V2 of MSEXTMZ.EXE, recognizable by its binary version from the Exchange 2007 tree, 8.x.
One Binary, Two Purposes
While MSEXTMZ is a single binary, it contains two distinct modes of operation. The first, Timezone Export Mode, is used to gather information about what time zone meetings in a mailbox are generally scheduled in. The second mode, Calendar Update Mode, is used to run TZMOVE against a set of users. The intended sequence of operation is that an administrator will use MSEXTMZ in timezone export mode to create a list of mailboxes and associated time zones, then use MSEXTMZ in calendar update mode to apply timezone changes to a set of mailboxes using the timezone information.
Stage One –Configuration
When MSEXTMZ is spawned it takes exactly one parameter (and so receives two from the C Run time library, the first being the program name). The parameter is the name of the INI file from which configuration data is derived. The default is “.\MSEXTMZ.INI”, in other words, the MSEXTMZ.INI in the same directory. All configuration is held under the [Configuration] section of the INI file. Steps to initialization:
0. The INI File is used for all subsequent configuration calls. If this file does not exist, a 0x80070002 (FILE_NOT_FOUND) error can be returned from any subsequent call.
COMMON ERROR: 0x80070002 – “The System Cannot find the file”. If the INI file does not exist this error can be returned.
1. The logging level for MSEXTMZ is read from the LoggingLevel= line in the INI file. The default value (0) is used if no such line is present. Logging Level for an event must be less than the logging level for the tool for it to be displayed.
2. The MSEXTMZ Log file is read from the Logfile= line in the INI file. If no log file is set then events will not be written to a log file. If Logfile is set, then the file will be opened with write permissions (obliterating an existing file if necessary). Failure to open the log file is a fatal error, the return code will be a Win32 error.
COMMON ERROR: 0x80070003 – “The System Cannot find the path specified”. This occurs when Logfile is set to log to a directory that does not exist, such as having Logfile=c:\tamp\msextmz.log, when the directory is “temp”.
3. The Command line for TZMOVE is read from the CommandLine= line in the INI file. This should be the path to the installed TZMOVE.EXE, not the MSI installer for TZMOVE (also called TZMOVE.EXE). CommandLine must be set in all cases, regardless of whether or not MSEXTMZ is exporting timezones or actually running update, but it is not used or validated in a timezone export run. If CommandLine is not set, MSEXTMZ fails with 0x80040005 – MAPI_E_FAILED.
4. Next the serverDN is read from the ServerDN= line in the INI file. ServerDN must be the LegacyDN of the server for timezone extraction, but can be only the RDN (cn=ServerName) for calendar update mode. If ServerDN is not set, MSEXTMZ fails with 0x80040005 – MAPI_E_FAILED.
5. Next the Outputfile is read from the Outputfile= line in the INI file. The OutputFile is used in timezone export mode to write user LegacyDNs and timezone data. It is not used in CalendarUpdate mode but will still be created if set. If Outputfile is set, then the file will be opened with write permissions (obliterating an existing file if necessary). Failure to open the output file is a fatal error, the return code will be a Win32 error.
COMMON ERROR: 0x80070003 – “The System Cannot find the path specified”. This occurs when OutputFile is set to log to a directory that does not exist, such as having Outputfile=c:\tamp\mailboxes.txt, when the directory is “temp”.
6. Next the Inputfile is read from the Inputfile= line in the INI file. The InputFile can be used in both calendar update mode and timezone export mode to specify user LegacyDNs (mailboxes) to process. If Inputfile is set, then the file will be opened with read permissions and must exist. Failure to open the input file is a fatal error, the return code will be a Win32 error.
7. Next the Errorfile is read from the Errorfile= line in the INI file. The Errorfile can be used in both calendar update mode and timezone export mode. It contains the legacyDN of any user who could not be processed. Note that failure to find any timezone does not mean that a user would be in the error file. If Errorfile is set, then the file will be opened with write permissions (obliterating an existing file if necessary). Failure to open the Errorfile is a fatal error, the return code will be a Win32 error.
COMMON ERROR: 0x80070003 – “The System Cannot find the path specified”. This occurs when Errorfile is set to log to a directory that does not exist, such as having Errorfile=c:\tamp\errors.log, when the directory is “temp”.
8. Next the MAPI Profile name is read from the Profile= line in the INI file. Profile is not a required value, but is used in Timezone export mode to determine which MAPI profile should be used to access the mailbox table. The profile should point to a mailbox on the server to be processed, and the account should have “Administer Information Store” permissions on each MDB on the server. Profile is not validated at this stage and cannot cause a fatal error.
9. Default Timezone is read from the Timezone= line in the INI file. Timezone is used in update mode. This specifies a “master” timezone which will be used for mailboxes in the input file that do not contain timezone information. The value should be a Registry Key Name from HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Timezones. For instance, “Timezone=HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\E. South America Standard Time” sets the master timezone to (GMT-3:00) Brasillia. Timezone is immediately validate by calling HrReadTimezoneFromRegistry, which will fail if the Timezone does not exist, or if all parameters cannot be read from the registry.
10. Next the flag for whether or not to export timezone data is read from the ExportTimezones= line in the INI file. If ExportTimezones is 1 (or true), then MSEXTMZ will attempt to read timezone data from each mailbox processed.
11. Next the flag for whether or not to attempt to process calendar items for timezone information is read from the ReadCalendarTimezones line in the INI file. If this is 1 (or true) MSEXTMZ will search the calendar for recurring items for which the user is the organizer and attempt to identify an associated timezone from them.
12. Now the post processing delay is read from the PostMailboxDelay= line in the INI file. Post mailbox delay is used in Update mode to determine how long an instance should pause after processing a mailbox to allow the server a chance to recover. The value is specified in seconds, the default is 0 (no delay).
13. Next the Per mailbox rebasing timelimit is read from the PerMailboxTimeLimit= line in the INI file. Per Mailbox timelimit is the maximum time MSEXTMZ will wait for TZMOVE to complete rebasing a mailbox. The default is INFINITE, meaning it will wait forever. The value is specified in minutes.
14. Finally, the Logdirectory is read from the LogDirectory= line in the INI file. Log directory is where TZMOVE’s calendar update logs (if written) will be saved to. It does not indicate that the MSEXTMZ log file will wind up in this directory. Having LogDirectory set to an invalid directory will cause an 0x80070003 error during post rebase processing.
Stage Two - Main Processing
Now that configuration is done, MSEXTMZ does minor initialization and begins main processing. First MAPI is initialized. Failure to initialize MAPI results in a fatal error, and usually indicates that a previous MAPI crash on the machine has left the MAPI subsystem unstable. In that case a reboot will usually resolve the initialization failure. Before MSEXTMZ can begin full operation, it must retrieve the system timezone nformation using the Win32 API GetTimezoneInformation. This information is later used to restore the system timezone if it has been changed during a calendar update.
Warning: Killing MSEXTMZ during a calendar update session can leave the workstation in a different timezone than the run began in.
Now that we have the timezone data saved off, it is time to perform main processing. There are two major sources of information for MSEXTMZ – The input file, and the mailbox table. Mailbox table can only be used to export timezone information, but input file can be used for either export or update mode. If Inputfile is not set, then MSEXTMZ will process the mailbox table.
Mailbox Table Processing
Mailbox Table processing is performed by the function HrProcessMailboxTable. To process the mailbox table, MSEXTMZ first performs a logon. If Profile= was set in the INI file, this profile will be used Otherwise a dialog will be displayed to prompt the administrator to select a profile. The profile selected should point to a mailbox on the server being processed, and should have “Administer Information Store” priveleges on all MDBs on that server. Using the selected profile MSEXTMZ will log on to MAPI.
Possible Error (not common): 0x8004010F – MAPI_E_NOT_FOUND can occur if the profile chosen doesn’t actually exist.
After logging on, MSEXTMZ acquires mailbox table – the list of mailboxes on a given information store. Due to the limitations of the interface used, only 65,535 mailboxes can be returned in a single export run. For servers with more mailboxes than this per server, an ADSI query for users would be a better method of generating an input file. MSEXTMZ could then process that input file to generate timezone information. For each row in the mailbox table, if ExportTimezones is set to one in the INI file, then MSEXTMZ will attempt to extract timezone information for the user. If ExportTimezones is not configured, the output file will contain only user DNs, no timezone information. In order to extract timezone information, MSEXTMZ must perform an administrative logon to the mailbox (thus requiring the “Administer Information Store” permission
Common Error: 0x80040011D – MAPI_E_FAIL_ONE_PROVIDER can occur at this stage with the error “HrProcessMailboxTable – Unable to log onto user mailbox: Error – 0x8004001D.” If the account MSEXTMZ is running as does not have Full Mailbox access permissions to the mailbox, or if it does not have “Administer Information Store” privileges on the MDB object this error can occur.
Extracting Timezone Information
Extracting Timezone information is performed by the top level function HrFIndMailboxTimezone. Timezone information is divided into major sources – CDO, OWA, Outlook2007/TZMOVE, and Calendar. Each type of timezone information has a function that retrieves it, such as HrFindCDOTimezone, HrFindOWATimezone, etc. Not all mailboxes will have all types of timezone information, and if no timezone information for a particular type is found, the error 0x80040005 (MAPI_E_FAILED) is returned. This is not a fatal error, and does not signify data corruption. Some mailboxes will not contain any usable timezone information.
Common Error: 0x80040005 – MAPI_E_FAILED is used to identify when we could not find the timezone for a particular mailbox. Yes, MAPI_E_NOT_FOUND would have been a better choice. V3 (if it is ever released) will contain this change.
Where is Timezone information read from?
CDO – Information is read from the Inbox. CDO Timezone information is only available when a CDO application has logged onto the mailbox, setting the CDO Session options for timezone. This covers RIM and Good customers, as well as other consumers of CDO.
OWA – OWA 2007 is read from the root of the mailbox, OWA 2007 is read from the root folder.
Common Error: 0x8004011B – MAPI_E_CORRUPT_DATA is returned when a user has OWA settings but does not contain a timezone entry.
Outlook 2007/TZMOVE – Read from the associated message in the calendar folder.
Calendar Data Timezone – MSEXTMZ can scan the calendar, looking for timezone data. To do so it looks at each item, looking for a recurring item for which the user is an organizer, and pulling the timezone description string from that item. OWA recurring meetings are not flagged as “organized” by the user, and so MSEXTMZ may not detect timezone information from them.
After all timezone information is read, it is output to the Output file in the following format, where \t means “tab”:
Finally MSEXTMZ logs off of the user’s mailbox.
Processing an Input File
Processing an input file could mean performing an update or exporting timezone information for only a subset of users. Top level processing is performed by the function HrProcessInputFile, which reads the input file line by line. A single line in the file cannot exceed 1025 characters.
Common Error: 0x80040005 – MAPI_E_FAILED. If the input file is not correctly delimited and a single line exceeds 1025 characters, this error can be returned.
Uncommon, but possible Error: 0x80040005 – MAPI_E_FAILED. There is a possible failure case if a maximum length DN is found – there will be no space for the SERVER or Timezone information, and MAPI_E_FAILED will be returned. There is no fix as of yet for this.
After a line is read, it is split into component pieces. The input file is tab delimited, and the format (where \t means “tab”) is:
The user DN is the legacyDN of the mailbox. Server is the servername (not legacyDN) of the server. Timezone should be a Registry Key Name from HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Timezones. For instance, “E. South America Standard Time” sets the mailbox timezone to (GMT-3:00) Brasillia. Now we call HrProcessMailbox.
Processing a Single Mailbox
To process a single mailbox we begin by converting the data to Unicode. We determin the RDN of a user from their legacyDN by looking for the last “=” in the legacyDN, then create a profile (and later log) name by using “MSEXTMZ-<RDN>-<TickCount>”. HrCreateOutlookProfile is called to create a user profile.
Common Error: 0x8004011C – MAPI_E_UNCONFIGURED. This error can occur when the Input file has the wrong tab delimiters and we do not have the DN or servername correctly specified as a result.
Now that a profile is created, a decision must be made. Input files can be used to update mailboxes OR extract timezone information. If the current run is set to export timezone information (ExportTimezones=1 in the INI) then we will call HrFindDefaultMailboxTimezone.
Common Error: 0x80040011D – MAPI_E_FAIL_ONE_PROVIDER can occur at this stage with the error “HrFindDefaultMailboxTimezone – Unable Open Mailbox - 0x80040011D.” If the account MSEXTMZ is running as does not have Full Mailbox access permissions to the mailbox this error can occur. Mailbox timezone extraction is then called just as it is in the “Extracting Timezone Information” section.
If the intent of a run is to update calendars, then the next call will be to HrTestMailboxAccess, which validates that we can log onto the mailbox and in fact access folders by attempting to open the Outbox.
Common Error: 0x80040011D – MAPI_E_FAIL_ONE_PROVIDER can occur at this stage with the error “HrTestMailboxAccess – Unable Open Mailbox - 0x80040011D.” If the account MSEXTMZ is running as does not have Full Mailbox access permissions to the mailbox this error can occur. Mailbox timezone extraction is then called just as it is in the “Extracting Timezone Information” section.
Common Error: 0x800400111 – MAPI_E_LOGON_FAILED can occur at this stage with the error “HrTestMailboxAccess – Unable Open Mailbox - 0x800400111.” If the account MSEXTMZ is running as does not have Full Mailbox access permissions to the mailbox this error can occur. Mailbox timezone extraction is then called just as it is in the “Extracting Timezone Information” section.
Now the user’s timezone information must be read from the registry, using HrReadTimezoneFromRegistry. HrReadTimezoneFromRegistry will attempt to read the timezone specified as a subkey of
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
The “DLT”, “STD”, and “TZI” values must exist under the specified timezone key or timezone reading will fail.
Common Error: 0x80070002 – FILE_NOT_FOUND occurs when the timezone specified does not exist as a subkey of the “Time Zones” registry key or we cannot access that key.
Once the timezone is read from the registry, MSEXTMZ must set the system timezone to that value, using HrSetSystemTimezone. HrSetSystemTimezone will not modify the system timezone if it is already in the correct timezone for a user. If it is, then we must first adjust the token privileges to grant MSEXTMZ the timezone privilege (which is granted by default, but not present on the token). ANY Failures in HrSetSystemTimezone are usually a result of the account running MSEXTMZ not having permission to set the system timezone.
Launching TZMOVE and determining Success or Failure
Now that the system timezone is correct for the user (either by already being correct or by MSEXTMZ setting it), MSEXTMZ will prepare to launch TZMOVE, and that means gathering data to help determine if the tool succeeded or failed.
We begin by determining the record number of the newest event in the event log. TZMOVE writes a success event to the event log if it completes successfully – this is Event ID 32 from source TZMOVE. TZMOVE does not necessarily write an update log, so MSEXTMZ must scan the event log to determine if TZMOVE succeeded. MSEXTMZ will start from the newest event log record before TZMOVE was launched.
HrSpawnOutlookTool is called to spawn TZMOVE using the command line specified in Commandline= from the INI file. MSEXTMZ will wait until TZMOVE exits (either by crashing or finishing) and then begin determining if it succeeded.
Common Error: 0x80070002 – FILE_NOT_FOUND occurs when CommandLine= is not set to the correct path for tzmove.exe
If HrSpawnOutlookTool failed then no attempt will be made to read the event log or copy off a TZMOVE log. If, however, TZMOVE was successfully launched, then we need to determine if it succeeded. To do this MSEXTMZ will scan the event log, and so it will retrieve the event id of the newest event log record (and scan from the previous newest to the latest newest).
Common Error: 0x80040005 – MAPI_E_FAILED, with the error message “HrProcessMailbox:No Event log records written – treated as failure.” This event log means exactly what it says – that the previous newest event log record and the current newest event log record are the same – that nothing was written to the event log. This can occur in a number of cases:
a. No space in the event log means that TZMOVE couldn’t write to it. The mailbox might have been rebased but we cannot tell.
b. The “CommandLine=” was pointing to the TZMOVE.EXE MSI, not the installed TZMOVE.EXE binary. The MSI is about 8mb.
c. TZMOVE crashed on startup and wrote nothing, often caused by TZMOVER.DLL not being in the same directory as TZMOVE.EXE
At this point MSEXTMZ has a range of event log records to search, and calls HrScanEventLogForSuccess to look for the success event. The success event, Event ID 32 from source TZMOVE, is what signifies a successful rebase.
Common Error: 0x80040005 – MAPI_E_FAILED, with error message “HrScanEventLogForSuccess:Success Event not found in Application log, treating as failure.” This is a true failure case – it means that TZMOVE was spawned, but did not write the success event. The event log will contain more information about why TZMOVE failed, OR if LoggingLevel= is set to 2 or higher, TZMOVE event logs are also echoed to the MSEXTMZ event log when possible.
If TZMOVE completed successfully, MSEXTMZ will attempt to archive off the TZMOVE log file, called “Outlook Time Zone Update.Log”, written to the %TEMP% directory for each user. TZMOVE does not always write a log file and so it is not a failure if no log file was written. A configuration error, setting LogDirectory incorrectly will result in an error at this point.
COMMON ERROR: 0x80070003 – “The System Cannot find the path specified”. This occurs when LogDirectory is set to log to a directory that does not exist, such as having LogDirectory=c:\tamp\ when the directory is “temp”.
TZMOVE copies the update log to the same name as the MAPI profile – “MSExTmz-<RDN>-<TickCount>.LOG”
Finally, MSEXTMZ will pause for the amount of time specified by the PostMailboxDelay= line in the INI file.
In any failure case, if ErrorFile= is set in the event log, the user’s legacyDN is output to the error file, which contains (after a run) the list of users who were not successfully processed.
Interpreting MSEXTMZ Error codes
MSExTmz uses HRESULTS, and so the error codes are interpreted as such. That means that any given error can be decomposed to give more information (or less, if you didn’t understand it the first time). HRESULTS are recognizable easily because error HRESULTS begin with 0x80. The next number in the HRESULT is the “FACILITY” code, and it tells you the approximate source of the error. For System Errors, that’s 7. For application errors, that’s 4. Therefore, an HRESULT 0x80070002 would be a SYSTEM error (7), while an HRESULT 0x8004010F would be an application level HRESULT (4). After the facility, the rest of the value is the actual error code. Taking our previous example, 0x80070002, 7 is the facility, so the rest of the value (2) is the error code. An easy way to lookup system error codes is via the net command, “NET HELPMSG <error number>”, and “NET HELPMSG 2” at a command line yields “The system cannot find the file specified.”, meaning that a file (usually) could not be found. Our other example, 0x8004010F, is an application error (4) and the rest of the error code is 0x10F. If we look in mapicode.h (from MSDN or live search) we can see that it is MAPI_E_NOT_FOUND, meaning we didn’t find something (usually a property, though you could get the same error if you were looking for a particular folder and couldn’t find it).