Exchange Server sometimes gets a bad rap for providing GUI tools for most operations. Many administrators think Exchange relies on graphical tools because it has poor scripting capabilities. However, the truth of the matter is that many administrators just aren't aware of how many tasks they can script in Exchange. You might find that you can make your job much easier by applying the scripting technologies available in Exchange, plus a few well-chosen third-party tools. Let's look at some of the objects you need to know about and operations that you can perform related to mailbox stores, or databases. Some of the scripts I'll show you also apply to public folder databases, so I'll note the differences where appropriate.
Objects You Should Know About
The Collaboration Data Objects for Exchange Management (CDOEXM) interface is what you'll typically use to manipulate mailbox and public folder databases in Exchange Server 2003 and Exchange 2000 Server. The Microsoft Developer Network (MSDN) has complete documentation about the various object classes and methods that CDOEXM implements at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_e2k3_reference_cdoexm.asp?frame=true. You can do all sorts of fascinating things with these classes and methods, but in this article, I focus on just three CDOEXM classes.
The ExchangeServer object represents a single Exchange server. It has a variety of properties (shown in Table 1), but for our purposes, the most interesting property is StorageGroups, which contains a list of URLs for storage groups (SGs) on the server. Each StorageGroup object has properties (shown in Table 2), including a set of 0 or more mailbox databases and 0 or more public folder databases. These collections are actually MailboxStoreDB or PublicStoreDB objects, each of which has its own set of properties. Table 3 shows the properties for the MailboxStoreDB class.
For most operations involving mailbox and public folder databases, you can write a script that follows a predictable pattern. First, you set an object reference to an ExchangeServer object, then you set a reference to the SG that contains the database you want to work with, then you create a reference to the database object. At that point, you can get or set the database properties as necessary.
Getting and Setting Properties
All the properties in Tables 1, 2, and 3 are directly readable through object references. You might have noticed that some of the properties in the tables are read only. You can change some of these properties by using methods on the objects; for example, you can move an SG's log files (and thus change the value of the LogFilePath property) by using the MoveLogFiles method. However, other properties (like, say, the DirectoryServer property of the Exchange Server class) can't be changed.
Speaking of change: When you change object properties in a script, you must commit the changes to Exchange by using the SaveTo method. Changing a property in an object reference changes it in the local cache. Calling the SaveTo method writes the change to Exchange. If you don't use the SaveTo method, any property changes your script makes will be lost when the script is finished running.
Creating and Deleting SGs
Let's start scripting with a simple example: creating and removing SGs. You shouldn't need to perform these operations very often, but I'll describe them here for two reasons: They simply illustrate the pattern of object access I described above, and they're useful if you want to build multiple servers with the same configuration. If you're not familiar with the basic requirements for running CDO and CDOEXM scripts, you can find out what they are in "Script User Account and Mailbox Creation," September 2002, InstantDoc ID 25843. The article "Deleting User Accounts and Exchange 2000 Mailboxes," June 2003, InstantDoc ID 38529 also has good basic CDOEXM scripting information.
Listing 1 shows a script for creating an SG. The fairly straightforward script begins by creating object references for the ExchangeServer and StorageGroup objects, then establishes the connection to the server; you'll need to replace BATMAN with the NetBIOS name or Fully Qualified Domain Name (FQDN) of your Exchange server.
Next, the script finds the URL of the first SG on the server. There's no elegant way to do this, so the script in Listing 1 takes the ugly but functional route of starting a For Each loop and then immediately exiting from it. A better way for experienced scripters is to coerce the returned array of StorageGroups objects to a string array, then reference the first element, as the code in Listing 2 shows. However, the distinction between the string and array versions can be confusing to new scripters.
After the script has the URL of the first SG, creating the new SG is a simple matter of inserting the desired name in place of the existing name in the URL and using the SaveTo method to make the change persist.
Deleting an SG is somewhat similar, but the script author must supply the complete path to the SG because the script must open the SG before deleting it. The short but dangerous script in Listing 3 removes all SGs from the specified target server. If an SG has any associated databases, the deletion will fail with CDOEXM error c1034a7d, This storage group contains one or more stores. Only empty storage groups can be deleted. Even after you delete an SG, its log files remain on disk; this safeguard prevents you from accidentally wiping out critical transaction logs with an ill-written script.
Creating and Deleting Mailbox Databases
The next step up the evolutionary ladder is being able to create and remove individual databases within an SG. As long as we have the name of the SG in which we want to create the database, this process too is fairly simple. The script in Listing 4 connects to the specified server and creates a new mailbox database at the given URL; it requires that you correctly specify the path to the SG in which you want the database created. Note that you must also give the new database a name by setting its Name property before you can save it. In this case, the script gets the path of the first SG it finds, then uses it to construct a URL for an SG named First Storage Group. The new mailbox database is created within that SG, given the name SpiffyNew MDB, saved, and mounted.
The process for deleting a database is similar, except that after specifying the database's name, the script must actually open it, then use the Delete method to get rid of it. Doing so doesn't actually remove the associated database files (one EDB file and one STM file per database) from the server. Listing 5 shows what the script looks like; note that the only differences between the Listing 5 script and the Listing 4 script is in the last lines, which, in Listing 5, open the mailbox database and delete it.
Mounting and Dismounting Databases
In ordinary server operations, you probably don't need to frequently create and delete databases and SGs. However, being able to mount and dismount databases from a script opens up all sorts of interesting possibilities. For example, you could write a script to perform el-cheap-o offline backups by dismounting a database, copying its EDB and STM files to another volume, and remounting it. In fact, you could write a script to automatically run the command
to perform an offline defragmentation—not because you'd want to do it often but because a script would make it easy to repeat the process on multiple servers when needed.
Once you know how to open the database object, mounting it and dismounting it are extremely simple—the Mount and Dismount methods are all you need. The last line of Listing 4 uses the Mount method to mount the newly created database. The script in Listing 6 checks the Status property, which indicates whether the database is mounted (0), dismounted (1), mounting (2), or dismounting (3). The script checks for a mounted or dismounted database and dismounts or mounts it, respectively.
Where to Learn More
Exchange scripting isn't well understood by most administrators, not least because Microsoft's own documentation doesn't present nearly as much detail as it could. (Adding insult to injury, many of the MSDN CDOEXM samples have bugs or typographical errors that render them worthless; for example, the documentation for the MailboxStoreDB object's Dismount method doesn't mention that the timeout parameter to Dismount is ignored.) The CDOEXM documentation, though, is probably the best place to start because it has a decent overview of the CDOEXM classes and their properties and methods.
Beyond that, the aforementioned Exchange & Outlook Administrator articles are helpful resources, and a good book about Windows scripting (such as Microsoft Press's Windows 2000 Scripting Guide) could be useful, even though it has little to do with Exchange. The Exchange Cookbook (O'Reilly & Associates, due in spring 2005), which I co-wrote, has many more examples of ways to script Exchange, and the companion Web site (http://www.exchangecookbook.com) contains all the scripts from the book, so you can find samples that illustrate whatever it is you're trying to do. Learning the intricacies of CDOEXM can be frustrating, but after you learn how to use it to automate your Exchange management tasks, you'll find it a worthwhile investment of your time and effort.