Get Forwarding Email Address of Forwarded Mailboxes

This second article, let’s start by talking a little about the “-Filter” parameter, used in most Exch Shell cmd-lets that I’ve found myself abusing of these past days. I have supporting role in an Exchange 2007 Migration Project, and we were tasked with “cleaning up” what is left of the Legacy Exchange Servers in terms of mailboxes. The Domain structure contains multiple forests, one of which has quite a few child domains. In “everything is a possibility” domain structures say you may be required to

Task #1 Get a list of all legacy mailboxes that have forwarding addresses enabled or that DO NOT have a forwarding address at all.

and then

Task #2Based on the list from 1, create a report with forwarded email address and the forwarding address.

Task #1Is done via this one liner

$LegacyFWList = get-mailbox -ResultSize unlimited -RecipientTypeDetails LegacyMailbox -IgnoreDefaultScope -Filter {(ForwardingAddress -like '*')} | select-object ForwardingAddress,WindowsEmailAddress,RealFWAddress

Code Breakdown:

get-mailbox -ResultSize unlimited -RecipientTypeDetails LegacyMailbox -IgnoreDefaultScope -Filter {(ForwardingAddress -like '*')} -ResultSize unlimited
  • By default the cmdlet returns only the first 1000 results. I used unlimited but it also accepts a number as input
  • get-mailbox cmdlet extracts only “LegacyMailbox” objects – this means mailboxes on servers pre Exchange 2007.
  • IgnoreDefaultScope performs a forest-wide search. Without this only legacy MBX’s on exchange servers in the forest root domain would have been returned.
  • Using this does have some limitations to it, check the help for what those are.
  • Biggest limitation is that –Identity must now be the a valid DN of the object.
  • I did not want to extract all DN’s in the forest and pipe them to the cmdlet, I looked for an alternative to this.

I discovered the –Filter parameter. It allows you to apply filters to the search on more Object Properties, much better than –Identity which we cannot use because of the –IgnoreDefaultScope.

A great thing about it is that it can be used without any limitations with IgnoreDefaultScope. Full details about how to use –Filter Parameter and what properties of AD objects are filterable can be found here and here. Back to our task, you can see what we did.

-Filter {(ForwardingAddress -like '*')}

We looked for any objects that contained any value in the “ForwardingAddress” Property of the returned object

    But say you want the opposite of this “get all legacy mailboxes that have no forwarding address”…if would stand to reason that this should work:

    -Filter {(ForwardingAddress -notlike '*')}

    You are out of luck, it returns the entire list of legacy recipients. I went through a few filters until I found this:

      -Filter {(ForwardingAddress -ne $null)}

      or

      -Filter {(ForwardingAddress -ne*')}

      I have to say that it was a surprise when I stumbled upon this, as it doesn’t really make sense. TechNet articles say –like, and I assume also –notlike accept wildcards, while –eq does not, you can also assume -ne does not. Well -ne does take wildcards, which I particularly do not mind in this case. I’m not sure if this is a bug, a feature, or just a flaw in my logic somehow and it’s working because it is supposed to.

      Moving on…

        select-object ForwardingAddress,WindowsEmailAddress,RealFWAddress
        • I can save you running a “| get-member” on what the get-mailbox returned previously and tell you that only “ForwardingAddress,WindowsEmailAddress” are properties returned by get-mailbox.
        • RealFWAddress” is something I made up. Why? Well unless you know already ForwardingAddress is not an address actually, it is a collection of properties for the recipient where emails are forwarded, the list contains DN, ObjectGUID, CN and others, not an actual email address.
        • RealFWAddress is a blank property, attached to the $LegacyFWList object, as a placeholder for when we do script a way to get that email address…which is now! read on

        Task #2 – Create a list of forwarded addresses and forwarding addresses.

        Now we come to the second part of my post, the “get-recipientcmdlet. Since there is no way for us to know to what object are the emails forwarded to [it could be a DL, a contact, a mailbox, another legacy user] we have to make our search as broad as possible. If you try to run get-mailbox on a contact object you will get nothing obviously. We are using foreach-object to go through the entire list. ForwardingAddress is actually the CN of the object. We pass the DN of the Property to a cmdlet that will return a primary email address, if any.

        This following code will accomplish just that:

        $LegacyFWList | foreach-object {
         $ForwardingDN = $_.ForwardingAddress.DistinguishedName
         $Filter = "DistinguishedName -like '$ForwardingDN'"
         $_.RealFWAddress = get-recipient -Filter $Filter -IgnoreDefaultScope | select-object PrimarySmtpAddress}
        $LegacyFWList | export-csv "c:\Change\This\Path.csv"
        

        Code Breakdown:

        $ForwardingDN = $_.ForwardingAddress.DistinguishedName
        $Filter = "DistinguishedName -like '$ForwardingDN'"
        • I used these 2 variables in the code, $DistinguishedName and $Filter, trying to write a one liner resulted in somehow “deformed” filter command that get-recipient would not understand.
        $_.RealFWAddress = get-recipient -Filter $Filter -IgnoreDefaultScope | select-object PrimarySmtpAddress
        
        • Lastly, RealFWAddress property I introduced above gets populated with PrimarySmtpAddress value.
        $LegacyFWList | export-csv "c:\Change\This\Path.csv"
        • In the end all that’s left is export the $LegacyFWList variable to CSV and process however you wish, or just store it in xml / pass it on to another part of a script.

        I have to admit the last part of the code is less ideal. Why? Well, the export does not output a clean forwarding email address. I have tried various ways to fix it, but in the end I concluded that it took me 30 minutes of trying to get a nicer export, and 15 seconds to fix it after importing the csv in excel.

        UPDATE 1: 26.01.2010 – added proper way to filter people with no forwarding address
        UPDATE 1: 21.02.2010 – added syntax highlighting and small rewrites