Executive Summary:

Microsoft Exchange Server 2007's Exchange Management Shell lets you easily accomplish your mailbox management tasks with Windows PowerShell commands, known as cmdlets. You can create single mailboxes with the New-Mailbox cmdlet, or use the foreach command to create bulk mailboxes imported from comma-separated value (CSV) files. Use the Get-Mailbox cmdlet in Exchange Management Shell to view properties of a mailbox and the Set-Mailbox cmdlet to update mailbox properties. Exchange Management Shell also has commands for controlling mailbox permissions.

Exchange Server 2003 has been justly criticized for its management tools for working with mailbox objects. Exchange administrators commonly need to manipulate multiple mailboxes at one time, but the Exchange 2003 tools for doing so are weak. You can enable a group of users for mailbox access, but if you want to do something more subtle—say, turn on Exchange ActiveSync (EAS) for members of an Active Directory (AD) group—you're reduced to writing your own scripts. There's a lot of demand for how-to information about mailbox management (which is why I co-wrote Exchange Server Cookbook ), but Exchange Server 2007, and in particular Exchange Management Shell, dramatically improves the toolset we have for mailbox management.

In my conversations with Exchange administrators all over the world, one constant I've found is apprehension, or even fear, about Windows PowerShell, which is the scripting language used in Exchange Management Shell. I try hard to dispel these feelings by explaining two principles: First, PowerShell is more understandable than most scripting languages because it uses a highly regular grammar, with clearly named verbs and objects; and second, you can learn PowerShell in small, easily digestible pieces. In this article, I'm going to assume you have a basic level of Exchange Management Shell knowledge: You should be able to launch the shell, enter basic commands, and look up help. You should also be familiar with general concepts of Exchange administration.

The Three States of Mailboxes
Shakespeare defined seven ages of man. The Exchange team has given us the somewhat less universal three states that a mailbox can be in:

  • Disabled—In this state, an AD user object doesn't have a mailbox associated with it. This is the default state for new AD accounts and for accounts where you've removed the mailbox.
  • Enabled—In this state, the user account has a mailbox object defined in the Exchange database, as well as an email address to which messages can be delivered. This is the default state for accounts after you create a new mailbox.
  • Disconnected—In this state, the Exchange mailbox still exists in the database, but it's not linked to an account. The only things you can do with a disconnected mailbox are to reconnect it to an account or to permanently remove it from the Exchange database.

Unlike Exchange 2003 and Exchange 2000 Server, you can manage these transitions in Exchange 2007 only through the Exchange management tools, not by using the Microsoft Management Console (MMC) Active Directory Users and Computers snap-in. You can still use Active Directory Users and Computers to create, delete, and disable AD user accounts, of course, and Quest Software has released a free set of PowerShell extensions for working directly with AD user accounts (see http://www.quest.com/activeroles-server/arms.aspx ).

Creating a Single Mailbox
The first, and most basic, mailbox management operation that most administrators encounter is to create a single mailbox and associate it with an AD user account. To do this in Exchange Management Shell, you use the New-Mailbox cmdlet. In its simplest form, you can execute this command with only a few required parameters, including the mailbox database you want to use, the user principal name (UPN), the display name, and the target organizational unit (OU). Here's an example:

New-Mailbox -userPrincipalName `
 JohnSmith@contoso.com `
 -database "Mailbox Database" `
 -name "John Smith" -org "Sales"

Note that the backtick (`) at the end of a line indicates that the command continues on the next line. When you use this command, Exchange Management Shell prompts you for a password for the new mailbox. The password is a required parameter, but the shell won't let you enter it on the command line. You can, however, create a password in a separate string (which, to the management shell, is actually a secure string), which you can then apply to the -password parameter. So you'd do something like this:

$thePassword = Read-Host `
 "Enter a password" -AsSecureString `
 New-Mailbox -password $thePassword `
 -userPrincipalName `
 JohnSmith@contoso.com `
-database "Mailbox Database" `
-name "John Smith" -org "Sales"

This is a handy trick to know, especially for creating multiple mailboxes for a batch of new users because you'll be prompted for the password only once. It's often easier to assign the same password for bulk operations. You might want to add the -ResetPasswordOnNextLogon flag to force new users into a password change the first time they log on.

Creating Multiple Mailboxes
What if you want to create a bunch of mailboxes at one time? With previous Exchange versions, it's easy to select a group of users in Active Directory Users and Computers and use the Exchange Task Wizard to create mailboxes en masse; with Exchange 2007, you can do the same thing in Exchange Management Console. The problem with previous versions, though, is that the process for creating a group of user accounts and mailboxes at the same time is a little opaque. Because Exchange Management Shell can create an account and a mailbox in the same operation, the process becomes much simpler. In Exchange 2007, you can't use the familiar Csvde and Ldifde tools directly; instead, PowerShell offers the Import-CSV and Export-CSV cmdlets.

There are many potential sources for the list of mailboxes you want to create. For example, you might get the list from a Microsoft Access database, a foreign LDAP directory, a Microsoft Excel spreadsheet, or an HR system like PeopleSoft. This array of possible sources might seem like a daunting problem at first, but fortunately we can use comma-separated value (CSV) files as a sort of universal language. Many programs can export data as CSV files; for those that can't, you can use Word, Excel, or your favorite scripting language to turn them into a CSV file.

To create mailboxes, remember that you need six required parameters: the mailbox alias, the username, the mailbox database that will hold the mailbox, the AD OU where the user object should live, the UPN for the new account, and a password. Your CSV file should contain the name of each attribute you choose to specify on the first line, separated by commas. Figure 1 shows a simple example CSV file with four values for each account: the UPN, username, account alias, and display name. In this case, the password and OU will be specified as part of the import command, which is why they're not included in the file.

After you've created a CSV file in the proper format, you can test it with the Import-CSV cmdlet. That's right: Exchange Management Shell includes a command whose job is to read in a CSV file and parse it into a set of parameters that can be fed to other commands, such as, say, New-Mailbox. Import-CSV parses each line of the file (after the first, which defines the file's fields) and treats it as a separate object. To test your CSV file, you can run Import-CSV and pipe its output to the Format-List cmdlet:

Import-CSV `
 c:\temp\newMailboxList.csv `
 | Format-List

Figure 2 shows output from this command. Import-CSV has a counterpart cmdlet, Export-CSV, which you can use to create CSV files containing pretty much any information you can extract. You'll see an example of Export-CSV in the next section.

When you have a correctly formed CSV file that Import-CSV can display without error, creating the mailboxes is simple. You need to know how to use the PowerShell foreach construct, though. As its name implies, foreach gives you a way to perform the same operation on every object it sees. By wrapping the call to New-Mailbox inside a foreach loop, we can create multiple mailboxes at once by doing something like this:

Import-CSV `
 c:\temp\newMailboxList.csv `
 | foreach \{ New-Mailbox `
 -alias $_.Alias `
 -name $_.Name `
 -DisplayName $_.DisplayName `
 -UserPrincipalName $_.UPN `
 -Database "mailbox database" `
 -OrganizationalUnit "Users" \}

You might not be familiar with PowerShell's $_ operator; it's a placeholder that means “the current object.” In a foreach loop, when you see something such as $_.UPN, it means that the script or task should use the UPN property of the current object in the pipeline. Note that in this example, the name of the mailbox database and OU are fixed. You could easily change either of them or even supply values from the CSV file. For the password, you can use the same procedure described for creating a single account to capture a password from the keyboard and store it for use as a secure string.

It turns out that this method has another very valuable feature. You can use the -template parameter with New-Mailbox to have it copy the settings from a template mailbox to the new mailboxes you create. This is a handy alternative to the standard method of creating a batch of mailboxes, then modifying their properties. New-Mailbox expects to see a mailbox as the parameter for -template, but it's easy to get a single mailbox using the Get-Mailbox cmdlet:

$defaultMailbox = Get-Mailbox `
 "New Employee Template"

You can then pass the mailbox object in defaultMailbox as a parameter to the New-Mailbox command.

Viewing Mailbox Properties
To retrieve the properties of a mailbox, you use the Get-Mailbox cmdlet. As its name implies, this command retrieves a mailbox object, from which you can query individual properties. If you use Get-Mailbox by itself, the only properties displayed are the mailbox name and alias, the server where the mailbox is stored, and the mailbox quota (if any) at which sending messages will be disabled. You'll see many other useful properties—including the legacy Exchange distinguished name (DN), the current DN, and the last modification date—if you pipe the output of Get-Mailbox to the Format-List cmdlet. However, using Format-List isn't terribly useful because by default it gives you all the properties of an object, most of which you aren't interested in.

Here's a useful approach. First, identify the names of the properties you're interested in. The quickest method to do this is to use Get-Mailbox with Format-List on your own mailbox to identify the properties you want. When you have the property names in hand, you can pass them to the Format-Table command to get a tabular listing showing only the desired properties. For example, let's say you want a table showing the mailbox alias and the deleted item retention time. The fastest way to do it is this:

Get-Mailbox | format-table `
 Alias,RetainDeletedItemsFor

Figure 3 shows sample output from this command. You can add as many properties as you like to the Format-Table command. For extra fun, you might try piping the output to the Export-CSV command:

Get-Mailbox | format-table `
 Alias,RetainDeletedItemsFor `
 | export-csv c:\temp\retention.csv

When you open the resulting file, though, you're in for a surprise: The parameters you asked for aren't there; instead, you'll see a bunch of object fields. That's because Format-Table and Format-List turn a stream of objects into text. You actually want the properties of the object, which you can get with the Select-Object cmdlet:

Get-Mailbox | select-object `
 Alias,RetainDeletedItemsFor `
 | export-csv c:\temp\retention.csv

In this example, you get a list of mailboxes, then select the specific properties you want, then pipe the resulting objects to Export-CSV, which puts them into a CSV file.

Setting Mailbox Properties in Bulk
The natural next step after getting mailbox properties is changing them. The basic pattern you follow is simple:

  1. Get a group of mailboxes.
  2. Select the specific ones you want.
  3. Pass the resulting set of objects to Set-Mailbox, along with the parameters you want to set or change.

The same general get/select/set pattern is something you'll see over and over again in PowerShell and Exchange Management Shell scripts. This pattern is a simple and useful way to think about the process. In this case, you start by getting all the mailboxes in your Exchange organization, which you can do with the Get-Mailbox cmdlet with no arguments. However, let's say that you don't want every mailbox. You can get smaller groups of mailboxes in several ways so that you can inspect or set their properties:

  • Use the Get-DistributionGroupMember cmdlet to expand a mail-enabled group, then pipe the output to Get-Mailbox. (Note that the expansion happens on the domain controller your shell session is connected to.) For example, the following command dumps all the mailbox properties for the specified Distribution Group (DG) to a CSV file:
    Get-DistributionGroupMember `
     "Field Sales" | Get-Mailbox | `
     Export-CSV c:\temp\sales.csv
  • You can get a group of mailboxes by using the Get-Mailbox cmdlet's ability to do ambiguous name resolution. For example,
    Get-Mailbox R* returns all mailboxes whose alias starts with the letter R .
  • If you want to get all the mailboxes on a particular database, use Get-MailboxDatabase with the name of the database, then pass the results to Get-Mailbox.
  • To get all the mailboxes on a specified server, use Get-ExchangeServer, pipe its output to Get-MailboxDatabase, then use Get-Mailbox.

You can selectively restrict which objects you get back. Say you want a list of all the mailboxes on servers whose names start with NYC. You could use the following command:

Get-ExchangeServer NYC* `
 | Get-MailboxDatabase | Get-Mailbox

You can also include Select-Object to pick out individual properties of the returned mailboxes.

There are two primary types of properties you'll normally need to set: properties of the mailbox itself, such as the deleted item retention time or the applicable unified messaging (UM) mailbox policy; and properties that control what the mailbox user is allowed to do through a Client Access server. Let's say you want to set the “office” value for a group of users who are moving from one location to another. At my company, we have site-specific DGs so we can quickly send mail to all users in a given location. To update this particular property, I could type

Get-DistributionGroupMember `
 "Toledo" | Get-Mailbox | `
 Set-Mailbox -office "Perrysburg"

There are many other properties you can set. For example, you can set send and receive quota limits; you can hide objects from the Global Address List (GAL); and you can set all the custom attributes, which organizations often use for storing extended data. Bear in mind that there are some properties you shouldn't change through the shell. For example, it's usually not a good idea to change any of the properties associated with UM, such as the user's telephone extension, unless you use Exchange Management Console. It's easy to accidentally break something by changing a property whose value you don't completely understand. You can, however, use Set-Mailbox to set the custom attributes often used for site- or company-specific purposes; use -CustomAttribute X as the name, where X is a number from 1 to 10.

The second group of properties includes things you normally control with the Get-CASMailbox and Set-CASMailbox cmdlets. Note that these aren't direct replacements for Get-Mailbox and Set-Mailbox. For example, you can't pass a mailbox database object to Get-CASMailbox. If you want to see which users have EAS enabled, you'd use this command:

Get-CASMailbox | select-object `
 name,ActiveSyncEnabled

The Set-CASMailbox cmdlet lets you set several useful flags on mailboxes, including the devices that are allowed to use EAS against a particular mailbox and whether individual protocols (EAS, POP, IMAP, and Messaging API—MAPI) can be used. You can also control whether users have access to the EAS features embedded in OWA, which is useful if you want to prevent certain users from seeing or changing their EAS settings. Check the online help for Set-CASMailbox for a complete list of all the things you can change.

Controlling Mailbox Permissions
There are two sets of permissions associated with each mailbox: AD permissions for “send as” and “receive as” and mailbox-level permissions that control “send on behalf of” and full mailbox access. This split results in having three separate tasks to control permissions. You use Set-Mailbox with the -GrantSendOnBehalfTo parameter to grant “send on behalf of” permission; you use Add-ADPermission with the -ExtendedRights parameter and a value of Send-As to grant send permission or a value of Receive-As to grant receive permission; and you use Add-MailboxPermission to grant full or partial mailbox access. Making these changes in bulk follows the method I outlined earlier: Find the mailboxes you want to modify, then pass the set of mailbox objects to the appropriate permission task.

Give It a Try
By now you should be able to perform some of the basics of mailbox management by using Exchange Management Shell. There are lots of other tasks you can perform through the shell, including exporting mailbox contents, searching mailboxes for a string, and setting options on various parts of the Exchange transport and client access architecture. As you've seen, the shell presents a powerful set of tools for mailbox management that go far beyond what Exchange 2003 offers. The commands are straightforward to learn and use, and you can get a lot done quickly if you master them—which doesn't take long. Give the shell a try, and I think you'll be pleased with the results!