Exchange Server 2010 Windows PowerShell: Troubleshooting Mailboxes

This brilliant Cookbook is packed with step-by-step instructions on writing scripts for Exchange 2010. You’ll be able to use the recipes straightaway and take your Microsoft Exchange management capabilities to another level.


Microsoft Exchange 2010 PowerShell Cookbook

Microsoft Exchange 2010 PowerShell Cookbook

Manage and maintain your Microsoft Exchange 2010 environment with the Exchange Management Shell and Windows PowerShell 2.0 using this book and eBook

        Read more about this book      

(For more resources on this subject, see here.)

The reader will benefit from referring two previous articles: Managing Mailboxes and Reporting on Mailbox.

Performing some basic steps

To work with the code samples in this article, follow these steps to launch the Exchange Management Shell:

  1. Log onto a workstation or server with the Exchange Management Tools installed.
  2. Open the Exchange Management Shell by clicking on Start | All Programs | Exchange Server 2010.
  3. Click on the Exchange Management Shell shortcut.

Checking mailbox logon statistics

If you have worked with Exchange 2000 or 2003, you probably remember that you could easily view several mailbox-related details for each mailbox under the Logons node of the Exchange System Manager. These details included the user-name, last access time, and more. When viewing mailboxes in the Exchange Management Console in Exchange 2010, these details are not displayed. In this recipe, we will take a look at how we can gather some of this information the Get-LogonStatistics cmdlet.

How to do it...

The following command will provide a logon statistics report for all mailboxes in the organization:

Get-MailboxServer |
Get-LogonStatistics |
Select UserName,ApplicationId,ClientVersion,LastAccessTime

How it works...

The Get-LogonStatistics cmdlet c an be useful for doing some basic checks on client logons, but the information returned from the previous command can be a little confusing and might seem inaccurate. For example, the ClientVersion property returned for each logon will always be reported as the same version number for end-user logons. This is due to the fact that client connections go through the Client Access role in Exchange 2010. Whether or not this will be fixed in future versions is unknown.

The ApplicationId property will indicate whether clients are connected via RPC or through Outlook Web App. Keep in mind that, depending on the client, multiple connections could be reported. Client's applications initiate multiple connections, so you will likely notice that this cmdlet will return anywhere from three to five records for each user connected to a mailbox. You will also see connections where the username is reported as the name of one or more databases or a system mailbox. These are generated by transport servers and mailbox assistant agents.

There's more...

There are a couple of other ways you can run this cmdlet. First, you can generate a report for an individual user. Instead of selecting individual properties, you can pipe the command to Format-List with a wildcard to display all of them:

Get-LogonStatistics -Identity testuser | Format-List *

You can also retrieve the logon statistics for a particular database using the -Database parameter:

Get-LogonStatistics -Database DB1

When users access their mailbox through Outlook Web App you may find that logon statistics for these sessions are missing or not what you would expect when running the Get-LogonStatistics cmdlet. This is because OWA users are not continuously connected to the Exchange server and the OWA client only connects to the server as needed to perform a task.

Setting storage quotas for mailboxes

One thing that has been around for several versions of Exchange is the concept of storage quotas. Using quotas, we can control the size of each mailbox to ensure that our mailbox databases don't grow out of control. In addition to setting storage quotas at the database level, we can also configure storage quotas on a per-mailbox basis. In this recipe, we will take a look at how to configure mailbox storage quotas from the Exchange Management Shell.

How to do it...

Use the following command syntax to set custom limits on mailbox:

Set-Mailbox -Identity testuser `
-IssueWarningQuota 1gb `
-ProhibitSendQuota 1.5gb `
-ProhibitSendReceiveQuota 2gb `
-UseDatabaseQuotaDefaults $false

How it works...

The Set-Mailbox cmdlet is used to configure the quota warning and send and receive limits for each mailbox. In this example, we are setting the -IssueWarningQuota parameter to one gigabyte. When the user's mailbox exceeds this size, they will receive a warning message from the system that they are approaching their quota limit.

The -ProhibitSendQuota is set to 1.5 gigabytes, and when the total mailbox size exceeds this limit, the user will no longer be able to send messages, although new incoming e-mail messages will still be received.

We've set the -ProhibitSendReceiveQuota parameter value to two gigabytes. Once this mailbox reaches this size, the user will no longer be able to send or receive mail.

It's important to point out here that we have disabled the option to inherit the storage quota limits from the database by setting the -UseDatabaseQuotaDefaults to $false. If this setting were set to $true, the custom mailbox quota settings would not be used.

There's more...

By default, mailboxes are configured to inherit their storage quota limits from their parent database. In most cases, this is ideal since you can centrally control the settings for each mailbox in a particular database. However, it is unlikely that having single quota limit for the entire organization will be sufficient. For example, you will probably have a group of managers, VIP users, or executives that require a larger amount of space for their mailboxes.

Even though you could create a separate database for these users with higher quota values, this might not make sense in your environment, and instead, you may want to override the database quota defaults with a custom setting on an individual basis. Let's say that all users with their Title set to Manager should have a custom quota setting. We can use the following commands to make this change in bulk:

Get-User -RecipientTypeDetails UserMailbox `
-Filter {Title -eq 'Manager'} |
Set-Mailbox -IssueWarningQuota 2gb `
-ProhibitSendQuota 2.5gb `
-ProhibitSendReceiveQuota 3gb `
-UseDatabaseQuotaDefaults $false

What we are doing here is searching Active Directory with the Get-User cmdlet and filtering the results so that only mailbox-enabled users with their title set to Manager are returned. This command is piped further to get the Set-Mailbox cmdlet which configures the mailbox quota values and disables the option to use the database quota defaults.

Finding inactive mailboxes

If you support a large Exchange environment, it's likely that users come and go frequently. In this case, it's quite possible over time that you will end up with multiple unused mailboxes. In this recipe, you will learn a couple of techniques used when searching for inactive mailboxes with the Exchange Management Shell.

How to do it...

The following command will retrieve a list of mailboxes that have not been logged on to in over 90 days:

$mailboxes = Get-Mailbox -ResultSize Unlimited
$mailboxes | ?{
(Get-MailboxStatistics $_).LastLogonTime -and `
(Get-MailboxStatistics $_).LastLogonTime -le `

How it works...

You can see here that we're retrieving all of the mailboxes in the organization using the Get-Mailbox cmdlet and storing the results in the $mailboxes variable. We then pipe this collection to the Where-Object cmdlet (using the ? alias) and use the Get-MailboxStatistics cmdlet to build a filter. This first part of this filter indicates that we only want to retrieve mailboxes that have a value set for the LastLogonTime property. If this value is $null, it indicates that these mailboxes have never been used, and have probably been recently created, which means that they will probably soon become active mailboxes. The second part of the filter compares the value for the LastLogonTime. If that value is less than or equal to the date 90 days ago then we have a match and the mailbox will be returned.

There's more...

Finding unused mailboxes in your environment might be as simple as searching for disabled user accounts in Active Directory that are mailbox-enabled. If that is the case, you can use the following one-liner to discover these mailboxes:

Get-User -ResultSize Unlimited -RecipientTypeDetails UserMailbox |
?{$_.UserAccountControl -match 'AccountDisabled'}

This command uses the Get-User cmdlet to search through all of the mailbox-enabled users in Active Directory. Next, we filter the results even further by piping those results to the Where-Object cmdlet to find any mailboxes where the UserAccountControl property contains the AccountDisabled value, indicating that the associated Active Directory user account has been disabled.

        Read more about this book      

(For more resources on this subject, see here.)

Detecting and fixing corrupt mailboxes

For years, Exchange administrators have used the Information Store Integrity Checker, more commonly known as the ISInteg utility, to detect and repair mailbox database corruption. You may have used ISInteg in previous versions of Exchange to correct a corruption ssue preventing a user from opening their mailbox or from opening a particular message. Unfortunately, in order to repair a mailbox with ISInteg, you had to dismount the database hosting the mailbox, taking it offline for everyone else that had a mailbox homed on that database. Obviously, taking an entire mailbox database down for maintenance when it is only affecting one user is less than ideal. Exchange 2010 SP1 alleviates this pain point by introducing a new cmdlet that replaces the ISInteg tool and allows you to detect and repair mailbox corruption while the database is online and mounted. In this recipe, we will take a ook at how to use these cmdlets and automate the detection and repair of corrupt mailboxes.

How to do it...

  1. To detect corruption for a single mailbox, use the New-MailboxRepairRequest cmdlet with the following syntax:

    New-MailboxRepairRequest -Mailbox testuser `
    -CorruptionType SearchFolder, ProvisionedFolder,FolderView `

  2. The -DetectOnly switch parameter indicates that we do not want to perform a repair and that we only want to check for corruption within this mailbox. To perform a repair, simply remove the -DetectOnly switch parameter from the previous command:

    New-MailboxRepairRequest -Mailbox testuser `
    -CorruptionType SearchFolder, ProvisionedFolder,FolderView

How it works...

The New-MailboxRepairRequest cmdlet can be run against a single mailbox or an entire mailbox database. In the previous example, we specified the testuser mailbox using the -Mailbox parameter. If needed, we could instead use the -Database parameter and provide the name of a database that we want to check or repair. The -CorruptionType parameter accepts several values that are outlined as follows:

  • SearchFolder: Used to detect and repair links to folders that no longer exist
  • AggregateCounts: Specifies that aggregate counts on folders that are not indicating the correct values should be repaired or detected
  • FolderView: Used to detect and repair views with incorrect content
  • ProvisionedFolder: Specifies that links between provisioned and unprovisioned folders should be detected and repaired

In the previous example, we specified the SearchFolder, ProvisionedFolder, and FolderView corruption types when performing mailbox repair detection for the testuser mailbox. The -CorruptionType parameter is required, so you need to provide at least one of the preceding values when running the cmdlet. If you want to check for all of them, just separate each corruption type with a comma when assigning the values to the parameter, as shown previously.

As always, we can take advantage of the PowerShell pipeline to perform operations in bulk. Perhaps you want to perform detection on a group of mailboxes, but not on every mailbox in the entire database. Just pipe the results of the Get-Mailbox cmdlet to the New-MailboxRepairRequest cmdlet:

Get-Mailbox -OrganizationalUnit uss.local/sales |
New-MailboxRepairRequest `
-CorruptionType SearchFolder,ProvisionedFolder,FolderView `

In this example, we're only performing detection on mailboxes in the Sales OU. This is just one example of how you can do this. Use the -Filter parameter in combination with Get-Mailbox or the Where-Object cmdlet to limit which mailboxes are sent down the pipeline.

The New-MailboxRepairRequest cmdlet can also be used against archive mailboxes when using the -Archive switch parameter.

There's more...

After working with mailbox move requests and mailbox import requests, you might assume that there is an entire set of cmdlets that allow you to get, set, or remove mailbox repair requests, but that is not the case as of Exchange 2010 SP1. In this version, all we have to work with is a single cmdlet: New-MailboxRepairRequest. Fortunately, detailed information about the mailbox repair requests are written to the event log so you can still check the status of these operations, but it will either require that you manually check the logs or write some PowerShell code that will check the logs for you.

The following Event IDs will be written to the application log, depending on the parameters used with your command:

  • 10047: A mailbox repair request has started
  • 10048: The repair request successfully completed
  • 10049: The mailbox or database repair request failed
  • 10050: The mailbox repair request task skipped a mailbox
  • 10059: A database-level repair request has started
  • 10062: Corruption was detected

These are some of the more common Events that you will want to keep an eye on. For a complete list, visit the TechNet documentation at the following URL:

In order to provide some automation when reviewing the logs, we can use the Get-EventLog cmdlet , which is a PowerShell core cmdlet. We can retrieve the logs from the mailbox server where the mailbox resides by filtering the request ID and the event IDs. One way we can do this is by saving the repair request in a variable:

$repair = New-MailboxRepairRequest -Mailbox testuser `
-CorruptionType SearchFolder

Next, if we want to retrieve the status for event IDs 10047, 10048, 10049, we can use the following command syntax:

Get-EventLog -LogName Application -ComputerName ex01 | ?{
('10047','10048','10049' -contains $_.EventID) -and `
($_.Message -match $repair.RequestID)

What we should get back here is all events that match the event IDs and the mailbox repair RequestID for the testuser mailbox. Of course, you can extend this to support multiple mailboxes and simply use PowerShell's looping constructs to iterate through each mailbox repair request and check the logs for each one.

Restoring deleted items from mailboxes

One of the more common requests that Exchange administrators are asked to perform is restoring deleted items from a user's mailbox. In previous versions of Exchange, there were usually a couple of ways to handle this. First, you could use your traditional brick-level backup solution to restore individual items to a mailbox. Of course, there was also the more time-consuming process of exporting data from a mailbox located in a recovery database. Exchange 2010 reduces the complexity of restoring deleted items by implementing a feature called single item recovery. When this feature is enabled, administrators can recover purged data from an end-users mailbox using the Search-Mailbox cmdlet . In this recipe, we will take a look at how this restore process works from within the Exchange Management Shell.

How to do it...

  1. If you have not already done so, you will need to use the following command syntax to assign the Mailbox Import Export RBAC role to your account. You will need to restart the shell after running this command in order for the assigned cmdlet to be visible:

    New-ManagementRoleAssignment -Role "Mailbox Import Export" `
    -User administrator

  2. To restore deleted data from an end-user mailbox, use the Search-Mailbox cmdlet:

    Search-Mailbox -Identity testuser `
    -SearchQuery "subject:'Expense Report'" `
    -TargetMailbox restoremailbox `
    -TargetFolder "Test Restore" `

How it works...

The Search-Mailbox cmdlet provides the capability to search only the dumpster containing the deleted items for a given mailbox using the -SearchDumpsterOnly switch parameter. In this example, we've used the -SearchQuery parameter to limit the search results to items that contains the term Expense Report within the subject line. After this command has been run, an administrator can access the target mailbox to retrieve the restored data. The items that matched the search query will have been restored to a subfolder of the target folder in the target mailbox specified.

To learn more about Single Item Recovery, see the following Exchange Team blog post:

The -SearchQuery parameter uses Advanced Query Syntax (AQS) to define the conditions for your search.

There's more...

You can perform very granular searches with AQS and the -SearchQuery parameter . Let's say that we wanted to restore all deleted items from the mailbox that were received after a certain date. We can use the following command to accomplish this:

Search-Mailbox -Identity testuser `
-SearchQuery "received:>11/01/2010" `
-TargetMailbox administrator `
-TargetFolder "Testuser Restore" `

Similar to the previous example, we are restoring data from the testuser mailbox to the same target folder in the administrator mailbox. The difference is that, this time, the search query is only going to look for messages that have been received after November 1 2010. You can see here that we are using the greater than (>) symbol to indicate that any message older than 11/01/2010 should be restored.

You can open the target mailbox in Outlook to retrieve the restored messages or export them using the New-MailboxExportRequest cmdlet.

Keep in mind that the -SearchQuery parameter is optional. If you want to restore all of the end-user deleted items you can do so by simply omitting this parameter for the commands in the previous examples. Also, you can restore messages when performing a discovery search with the New-MailboxSearch cmdlet


Having covered Reporting on mailbox, in the next articles we will cover Troubleshooting Mailboxes and Managing Mailboxes.


Having covered Troubleshooting Mailboxes, in the next two articles we will cover Managing Mailboxes and Reporting on Mailbox.

Further resources on this subject:

Books to Consider

comments powered by Disqus

An Introduction to 3D Printing

Explore the future of manufacturing and design  - read our guide to 3d printing for free