Share via

Using the Exchange Management Shell for Bulk Recipient Management


By Serdar Soysal

In Microsoft Exchange Server 2007, you can do most of your recipient management tasks in both the Exchange Management Shell and the Exchange Management Console. For tasks that involve single recipients, it is usually simpler to use the Exchange Management Console (unless you are immune to typos). However, when you are trying to configure multiple recipients, there simply is no alternative to the power and ease of using the Exchange Management Shell.

For me, the learning curve for the Exchange Management Shell consisted of three stages:

  1. "Wow, this is cool, but it looks a bit complicated."

  2. "Hey, I just created a mailbox without using the mouse!"

  3. "I'll never go back to the UI. I can't! I won't! Nothing you say can make me!"

Okay, maybe the description for the third stage is a bit overenthusiastic, but you get the point. The feature article A Primer on the Exchange Management Shell that was published in January 2007 will help you go through the first two phases. Hopefully, what you're about to read will help you get to the third stage, at least for recipient management.

To make it more fun, let's follow how a recipient administrator, Amy, uses the Exchange Management Shell to take care of the tasks assigned to her on a Monday.

Creating Mailboxes

First thing Amy has to do every Monday is to create mailboxes for all new hires that week. The Human Resources (HR) department sends a comma-separated value file (CSV) to Amy every Monday morning that has the names and user names of the new hires. A typical CSV file from HR looks like this:

Name,User Name
David Hamilton,DHamilton
Ezio Alboni,EAlboni
Rajesh M. Patel,RPatel
Kevin Liu,KLiu

When creating the new mailboxes, Amy needs to accomplish all of the following tasks:

  • Add the user principal name (UPN) extension to each user name.

  • Assign pass@word1 as the initial password.

  • Configure the user to change the password at first logon.

  • Specify the mailbox database and the organizational unit (OU) in which to place the new mailboxes.

When this recurring task was first assigned to her, she decided to use the Exchange Management Shell to accomplish it in a rapid manner. She started out by running the following New-Mailbox command, which creates a test user called Test User 1.

New-Mailbox -Name "Test User 1" -UserPrincipalName "" -OrganizationalUnit "" -Database "Server01\Mailbox Database" -ResetPasswordOnNextLogon $true

The command worked, but prompted her to enter the password for the new user. The New-Mailbox cmdlet only accepts secure strings for the password parameter, so she couldn't use the value of the default password as clear text in the command. To get around this, she used the ConvertTo-SecureString cmdlet to create a secure string from the default password and store it in the user-defined variable $Temp. She could then pass the variable to the password parameter of the New-Mailbox cmdlet.

$Temp = ConvertTo-SecureString "pass@word1" -asPlainText -force
New-Mailbox -Name "Test User 1" -UserPrincipalName "" -OrganizationalUnit "" -Database "Server01\Mailbox Database" -Password $Temp -ResetPasswordOnNextLogon $true

The next step was to read the user information from the CSV file and automate the provisioning. After reviewing the bulk management examples in the Microsoft Exchange Team blog Exchange Server 2007 recipient management one-liners, she modified her own script to accomplish this task.


The content of each blog and its URL are subject to change without notice. The content within each blog is provided "AS IS" with no warranties, and confers no rights. Use of included script samples or code is subject to the terms specified in the Microsoft Terms of Use.

$Temp = ConvertTo-SecureString "pass@word1" -asPlainText -Force
Import-CSV "C:\NewUsers.csv" | ForEach-Object -Process {New-Mailbox -Name $_.Name -UserPrincipalName "$($_.UserName)" -OrganizationalUnit "" -Database "Server01\Mailbox Database" -Password $Temp -ResetPasswordOnNextLogon $true}

Amy was able to set up this script by copying the syntax from the example in the blog article. However, she didn't quite understand what the $_ syntax did. After doing a little research, she found the topic Shell Variables. The article states that $_ is an Exchange Management Shell variable that contains the current pipeline object. Therefore, every time the script block specified with the Process parameter is executed in her script, the $_ variable contains the data from the next row of the CSV file.

Another part that was not clear to Amy was the syntax used when setting the UPN. It was different because the value of the variable was not directly assigned to a parameter of the New-Mailbox cmdlet, but rather it was used to modify a string that was assigned to the parameter. Amy reviewed the topic Syntax, which discusses the command syntax for the Exchange Management Shell and found out that the $() syntax is used to substitute the output of a command as an argument in a script. In the Exchange Management Shell, if you input only a variable, the output is the value of that variable. Therefore, when you place a variable inside a $() block, that block is substituted with the value of the variable. In her script, the variable $_.UserName contains the user name. By placing this variable inside a $() syntax, Amy was able to insert the value of the variable to the string that is assigned to the UserPrincipalName parameter.

After learning more about the command syntax in the Exchange Management Shell, Amy went one step further and moved the first line of her script to the Begin parameter of the ForEach-Object cmdlet and turned this into her very own bulk recipient management one-liner. Every Monday, she has simply been plugging the latest CSV file from HR to the following script.

Import-CSV "C:\NewUsers.csv" | ForEach-Object -Begin {$Temp = ConvertTo-SecureString "pass@word1" -asPlainText -Force} -Process {New-Mailbox -Name $_.Name -UserPrincipalName "$($_.UserName)" -OrganizationalUnit "" -Database "Server01\Mailbox Database" -Password $Temp -ResetPasswordOnNextLogon $true}

However, today's CSV file looks a little different. The HR department added titles and departments of the new employees to the CSV file.

Name,User Name,Title,Department
Deepak Kumar,DKumar,Marketing Analyst,Marketing
Ray Chow,RChow,Sales Associate,Sales
David Simpson,DSimpson,Sales Associate,Sales
Isabel Martins,IMartins,Administrative Assistant,Accounting

Amy's script as it stands won't work with the new CSV file because the Title and Department fields can only be updated by using the Set-User cmdlet. At first thought, she considers writing another script to read the same file and then use the Get-User cmdlet and pipeline its output to Set-User cmdlet. However, because she can also pipeline the output of the New-Mailbox cmdlet to the Set-User cmdlet, she ends up simply modifying her existing one-liner.

Import-CSV "C:\NewUsers.csv" | ForEach-Object -Begin {$Temp = ConvertTo-SecureString "pass@word1" -asPlainText -force} -Process {New-Mailbox -Name $_.Name -UserPrincipalName "$($_.UserName)" -OrganizationalUnit "" -Database "Server01\Mailbox Database" -Password $Temp -ResetPasswordOnNextLogon $true | Set-User -Title $_.Title -Department $_.Department}

To make sure that her syntax is correct, Amy consults the Using the Exchange Management Shell and Mailbox and Recipient Cmdlets topics in Microsoft Exchange Server 2007. After running her new one-liner, she browses Scripting with Windows PowerShell: Script Center to learn more about scripting in Microsoft Windows PowerShell.

Using Filters with Recipient Tasks

Just as she was about to leave for lunch, Amy receives an urgent e-mail message from her manager, Joe. Joe has received a complaint from the Marketing department: Because the Marketing employees regularly send messages that have large attachments, the current corporate storage quota is too small for this department. Joe asks Amy to increase the prohibit send quota for everybody in Marketing to 500 megabytes (MB) and remove the prohibit receive quota. He also asks her to do the same for all the managers in the company.

Amy knows that she can use the Get-User cmdlet to get a list of all the people who work in the Marketing department or have specific titles. However, she is not sure about how to set up the correct filters to do this. Once again, Amy consults the product documentation. To learn more about setting up custom recipient filters, she reads Creating Filters in Recipient Commands. To examine the list of available operators she can use in her filters, she reads Comparison Operators. Amy then verifies that the following command would return all user mailboxes in the Marketing department.

Get-User -Filter {Department -eq 'Marketing' -and RecipientTypeDetails -eq 'UserMailbox'}

Thanks to the consistent mailbox provisioning standards in her company, Amy knows that all managers, and only the managers, in the organization have either the word Manager, VP, or Officer in their title. To return the mailboxes of all managers in the organization, she sets up the following filter.

Get-User -Filter {((Title -like '*Manager*') -or (Title -like '*VP*') -or (Title -like '*Officer*')) -and (RecipientTypeDetails -eq 'UserMailbox')}

Amy then combines the two filters and feeds the output to the Set-Mailbox command in the following one-liner. She sets the warning quota to 450 MB because the company policy is to send a warning when a user's mailbox is at 90 percent capacity.

Get-User -Filter {((Title -like '*Manager*') -or (Title -like '*VP*') -or (Title -like '*Officer*') -or (Department -eq 'Marketing')) -and (RecipientTypeDetails -eq 'UserMailbox')} | Set-Mailbox -IssueWarningQuota 450MB -ProhibitSendQuota 500MB -ProhibitSendReceiveQuota unlimited -UseDatabaseQuotaDefaults $false 

Amy sends a note to her manager that she has taken care of the mailbox quotas for the Marketing department and management. She makes a mental note to schedule a meeting with her manager to revisit the storage requirements for the mailbox servers. Time for a well-deserved lunch.

Configuring Recipients

When Amy returns from lunch, she sees a message from Joe thanking her for taking care of the storage quotas so quickly. He asks if she could send him a list of the people whose storage quotas have been updated so he can send them a message introducing the change. She decides to make it easier for him by creating a distribution group. First she creates a distribution group called Quota Exceptions. To populate the membership list for the new distribution group, she uses the ForEach-Object cmdlet and the filter she had used to configure the mailboxes.

New-DistributionGroup -Name "Quota Exceptions" -OrganizationalUnit "" -SamAccountName "QuotaExceptions" -Type Distribution
Get-User -Filter {((Title -like '*Manager*') -or (Title -like '*VP*') -or (Title -like '*Officer*') -or (Department -eq 'Marketing')) -and (RecipientTypeDetails -eq 'UserMailbox')} | ForEach-Object -Process {Add-DistributionGroupMember -Identity "Quota Exceptions" -Member $_.Name}

Because Amy wants to make sure that this distribution group is not accidentally used, she configures it to accept messages only from her manager and hides it from Exchange address lists by running the following command.

Set-DistributionGroup -Identity "Quota Exceptions" -AcceptMessagesOnlyFrom "Joe Healy" -HideFromAddressListsEnabled $true

Just as Amy is about to notify Joe to use this distribution group, she realizes that in the future, there might be a need to configure the quotas for these mailbox users again. It would be useful to have an up-to-date distribution group for these users. So, she decides to use a dynamic distribution group instead because it will always be up to date. She removes the distribution group she had just created and instead creates the dynamic distribution group called Managers and Marketing Department Users. She uses the filter she had used for the Get-User cmdlet as the recipient filter for the new dynamic distribution group.

New-DynamicDistributionGroup -Name "Managers and Marketing Department Users" -Alias "MgrsMktgUsers" -OrganizationalUnit Users -RecipientFilter {((Title -like '*Manager*') -or (Title -like '*VP*') -or (Title -like '*Officer*') -or (Department -eq 'Marketing')) -and (RecipientTypeDetails -eq 'UserMailbox')} | Set-DynamicDistributionGroup -AcceptMessagesOnlyFrom "Joe Healy" -HiddenFromAddressListsEnabled $true

Using the steps outlined in How to View Members of a Dynamic Distribution Group, she verifies that the dynamic distribution group is set up correctly. She sends a message telling her manager to simply send his message to the e-mail address and explains how the dynamic distribution group is configured.

Connecting Mailboxes

Amy then logs on to her company's incident management tool and reviews the service tickets that were escalated to her from the Help desk. There is a request to reconnect a mailbox, Don Hall, which was disabled two weeks ago. Amy had to connect another mailbox the previous month. At the time, she didn't know which database held that user mailbox when it was disconnected. Using the Exchange Management Console, she had to connect to every Mailbox server to see if the disconnected mailbox was stored on it.

Amy doesn't want to go through the same search again. Therefore, she decides to figure out an easier way of determining which server contains the disconnected mailbox. She finds out that the data returned by the Get-MailboxStatistics cmdlet includes information about disconnected mailboxes. However, she wants to narrow the output of this cmdlet to the mailbox she is looking for. After reading the topic Working with Command Output, she learns that she can use the Where cmdlet to accomplish this. To test this, she creates a test mailbox called Test User 1 in the mailbox database MBX4 on Server03 and disables it. She then runs the following command.

Get-MailboxStatistics -Database "Server03\MBX4" | Where {$_.DisplayName -eq 'Test User 1'}

The cmdlet returns the following result:

DisplayName         ItemCount    StorageLimitStatus    LastLogonTime
-----------         ---------    ------------------    -------------
Test User 1         434                  BelowLimit

The filter works as expected, but the output of the cmdlet is not really useful to Amy in its current form. Because she plans to use this cmdlet to locate the server in the organization on which the disconnected mailbox exists, she requires that the output display the display name, server name, and the database name. Therefore, she formats the output of her cmdlet to accomplish this.

Get-MailboxStatistics -Database "Server03\MBX4" | Where {$_.DisplayName -eq 'Test User 1'} | Format-Table DisplayName,ServerName,DatabaseName

The following result is displayed and is now more useful for her purposes:

Display Name        ServerName          DatabaseName
------------        ----------          ------------
Test User 1         Server03            MBX4

Now that Amy has the command syntax she wants, she needs to have the command look at all the mailbox databases in the organization instead of a specific one. So, she pipelines the output of the Get-MailboxDatabase cmdlet to the command syntax she has built and runs the following one-liner.

Get-MailboxDatabase | Get-MailboxStatistics | Where {$_.DisplayName -eq 'Don Hall'} | Format-Table DisplayName,ServerName,DatabaseName

The cmdlet works as expected, and she locates the mailbox database in which Don Hall's mailbox existed when it was disconnected. She goes one step further and combines the steps outlined in How to Connect a Mailbox with her one-liner and uses the following command to connect the mailbox.

Get-MailboxDatabase | Get-MailboxStatistics | Where {$_.DisplayName -eq 'Don Hall'} | Connect-Mailbox -User

Amy spends the rest of the day browsing the Microsoft Exchange Server TechCenter and the Microsoft Exchange Team Blog for new information.


The content of each blog and its URL are subject to change without notice. The content within each blog is provided "AS IS" with no warranties, and confers no rights. Use of included script samples or code is subject to the terms specified in the Microsoft Terms of Use.

For More Information

As you can see from the preceding examples, you can rapidly accomplish seemingly complex recipient management tasks by combining multiple cmdlets and various features of the Exchange Management Shell.

To learn more about recipient management in Exchange 2007 and the Exchange Management Shell, see the following resources:

Serdar Soysal Serdar Soysal - Senior Technical Writer, Microsoft Exchange Server