Mailbox forwarding inventory report

NOTE: an updated version of the script that works with the latest V3 version of the Exchange Online module can be found here.

Continuing our “Permissions inventory” series, in this article we will cover something rather different – getting a report on all the mailboxes in the company that have some form of forwarding configured. As usual, we will cover the basic cmdlets you can use to gather this information, discuss some tips and provide you with a script that generates a sample report.

To get started, let’s examine the different ways forwarding can be configured in Exchange. Users can setup forwarding on their own by opening OWA, navigating to the Settings page, selecting Mail, then Accounts and then Forwarding, or directly by accessing https://outlook.office.com/owa/?path=/options/forwarding. Setting an address here populates the ForwardingSmtpAddress attribute for the mailbox, and one can also control whether a copy of the message should be preserved in the user mailbox. Both end users and admins have access to these settings.

Admins have another way to configure forwarding, by populating the ForwardingAddress attribute for a mailbox. In the GUI, this action is performed by accessing the EAC, navigating to the Recipients tab and double-clicking on the mailbox in question, then clicking the Mailbox features tab on the left and clicking the View details link under Mail flow. This option is a bit more restrictive, as it only allows forwarding to recipients recognized by Exchange. In addition, the presence of two similar settings has created some confusion, and recently Microsoft has announced plans to consolidate them and encourage the use of ForwardingSmtpAddress only, going forward.

To cover those two forwarding settings, one can simply use the Get-Mailbox cmdlet. What’s even better, those two properties are filterable, and for the purposes of minimizing the time it takes to run a script, one can utilize the following one-liner to get all mailboxes that have at least one of these settings configured:

Get-Mailbox -Filter {ForwardingSmtpAddress -ne $null -or ForwardingAddress -ne $null} -ResultSize Unlimited | select Name,*forward*

Simple stuff, right? Unfortunately, this does not cover all the methods available for forwarding or redirecting messages to a different recipient. Another method that can be used to achieve that is by setting up Inbox rules. Fortunately, we can use the Get-InboxRule cmdlet to report on just such rules, for example by using:

Get-InboxRule -Mailbox user@domain.com | ? {$_.ForwardTo -ne $null -or $_.ForwardAsAttachmentTo -ne $null -or $_.RedirectTo -ne $null} | Select Name,ForwardTo,ForwardAsAttachmentTo,RedirectTo

That’s for a single mailbox only though, if we are to cover all such rules, we need to cycle over every mailbox in the company as there is no filterable property we can use this time. This in turn means that covering Inbox rules in our script will substantially increase the run time. For this reason, we have added an optional parameter in the script, namely CheckInboxRules, which you can invoke only when necessary. More on this later.

Apart from Inbox rules, a form of forwarding can be configured by using the Delegate functionality. Namely, this is the option to forward Calendar requests to delegates. To configure it, the user opens Outlook, selects File, then presses the Account Settings button and selects Delegate Access. On the Delegate Access dialog, he can add or remove delegates, as well as control the forwarding settings for meeting requests and responses. In order for these options to become available, the “Delegate receives copies of meeting-related messages sent to me” checkbox must be selected.

To check for the presence of this setting via PowerShell, one can use the Get-CalendarProcessing cmdlet. The ResourceDelegates attribute indicates the delegates for which this setting is configured. Exchange Online no longer allows this attribute to be configured via PowerShell for User mailboxes, but viewing it is still possible. As with the Inbox rules however, in order to get this information across the company, you will have to loop each individual mailbox. Here’s an example on how to do that:

Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox | % {Get-CalendarProcessing $_.PrimarySmtpAddress | select Identity,ResourceDelegates }

Lastly, a form of forwarding can also be configured by some admin-only functionalities such as Transport rules, Journaling, Supervisory review, and more. While it’s possible to cover all these in a single script, the intention here is to simply give you a good starting point, so we will just include Transport rules as an example:

Get-TransportRule | ? {$_.RedirectMessageTo -ne $null -or $_.BlindCopyTo -ne $null -or $_.AddToRecipients -ne $null -or $_.CopyTo -ne $null -or $_.AddManagerAsRecipientType -ne $null}

So, after covering the basic building blocks, let’s turn to the actual script. As with the previous sample scripts, a set of parameters is made available to cover the different mailbox types: User, Shared, Room and Equipment, Discovery, and Team mailboxes. If you don’t specify any of these, the full list of mailboxes in the company will be returned.

Similarly, parameters are introduced for the different types of forwarding, for which to obtain data. Those include Inbox rules (via the –CheckInboxRules parameter), Calendar delegation (via –CheckCalendarDelegates) and Transport rules (via –CheckTransportRules). For the “regular” mailbox forwarding parameters, server-side filtering is possible and data is always returned. You can of course customize the script to make any of these mandatory or optional.

Different handling is applied in terms of gathering mailbox inventory depending on the parameters specified when invoking the script. Because both the ForwardingSmtpAddress and the ForwardingAddress attributes support server-side filtering, we can directly return all the mailboxes that have them configured. On the other hand, checking Inbox rules or Calendar delegation requires cycling over each mailbox, as explained above. Thus, if the -CheckCalendarDelegates or the -CheckInboxRules switches are used, we use Invoke-Command to gather the list of mailboxes and only a very small subset of their attributes, similarly to what we did in the Mailbox permissions inventory scenario.

The script will output the results to the console host by default, and will also store them in the global $varForwarding variable. You can specify a different variable name via the –OutVariable parameter, or simply reuse the existing one:

Mailbox forwarding inventory script output

You can find the full script over at my GitHub repo: Mailbox_Forwarding_inventory.ps1

Note that the intention of the script is just to give you a pointer where to look for and surface some basic information, not give you a full-blown solution to discover and manage all forms of forwarding. We’ve tried to use the same formatting for the output of all types of forwarding, allowing you to get information about the object you should look at as well as the recipient to which the messages will be forwarded or redirected to. If you want to export the output to CSV, either use the $varForwarding variable or simply remove the comment mark on the last line of the script.

As with previous script samples, the script does not handle connectivity to Exchange Online PowerShell. If an existing session is detected, the script will try to reuse it, otherwise it will return an error. You can of course incorporate it with your login script or modify it as you see fit. Don’t forget to leave comments and feedback!

2 thoughts on “Mailbox forwarding inventory report

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.