Freigeben über


Testing for bad SMTP Addresses

While working on my latest project,  I encountered a significant number of objects with malformed SMTP addresses.  These appeared to have been objects that had been somehow manually modified over the years by directly writing to the proxyAddresses attribute in Active Directory, bypassing an API that would check for correctly-formatted addresses.

As part of a migration effort, I needed to identify these bad addresses that would prevent my customer from successfully migrating to Office 365.  In an AD environment with a few hundred thousand objects (each of which could have anywhere from 1 to 50 or 60 proxy addresses), where would I even start?

Here's what I did (and maybe it can be helpful to you).

  1. Get a list of objects.  The core attributes that we're looking for are Alias (because these are all Exchange mail-enabled objects, they had an alias), PrimarySmtpAddress (for UserMailboxes and distribution groups), and EmailAddresses (the Exchange name for the proxyAddresses array).When you export a multivalued attribute (such as EmailAddresses/proxyAddresses), you need to iterate through all of the values and capture them as a single string that can be written to a column.  On top of that, you need to tell it how to delimit the fields in the column (since X500 addresses can have commas, using a comma as a delimiter in this column will cause you much grief, should you decide to do other things with this CSV).  To do this:

     Get-Recipient -ResultSize Unlimited | Select Alias,PrimarySmtpAddress,@{N="EmailAddresses";E={$_.EmailAddresses -join "|"}} | Export-Csv -NoType AllObjects.csv
    

    While you can certainly just do a Get-Recipient into a variable, I find that I like to have an tangible file to work with in case I lose network connectivity, power, or something else interrupts my processing.

    Also, when specifying the character to use for the join separator, don't use a comma (since it's part of an x500 address) or a semi-colon (since it's part of an x400 address). I find that the pipe (|) is the best separator to use when dealing with the proxyAddresses array.

  2. Import the CSV into a variable.

     $AllObjs = Import-Csv AllObjects.csv
    
  3. Loop through the objects, writing the bad ones out to a file for review.

     $smtptested = 0
    $proxies = 0
    $bad = 0
    $objects = 0
    $head = """" + "Alias" + """" + "," + """" + "BadSMTPAddress" + """"
    $head | out-file badsmtp.csv
    $regex = ((?i)x500:|x400:|gwise:|notes:|ms:|sip:|\=)
    foreach ($obj in $AllObjs) 
       { 
       [array]$EmailAddresses = $obj.EmailAddresses.Split("|");
       $alias = $obj.Alias; 
       foreach ($addr in $EmailAddresses) 
         { 
         if ($addr -notmatch $regex)
           { 
           try 
             { 
             write-host "trying $($addr)"; 
             $to = New-Object Net.Mail.MailAddress($addr.SubString(5))
             $smtptested++
             } 
           catch [system.exception] 
             { 
             write-host -ForegroundColor Red "$($addr) is bad"; 
             $data = """" + $Alias + """" + "," + $addr + """"; 
             $data | out-file badsmtp.csv -append 
             $bad++
             } 
           finally 
             {
             }
           } # End If ($addr)
           $proxies++
         } # End Inner ForEach
         $objects++
       } # End Outer Foreach
    Write-Host "$($objects) objects containing addresses tested."
    Write-Host "$($proxies) proxy addresses tested."
    Write-Host "$($smtptested) smtp addresses tested."
    Write-Host "$($bad) bad smtp addresses found."
    

That's it!

The output file, badsmtp.csv, will have have two columns: the Exchange alias of the affected object, and the offending SMTP entry in that object's EmailAddresses/proxyAddresses array.

Happy hunting!

Comments

  • Anonymous
    July 24, 2016
    Thanksmuch appreciated
  • Anonymous
    July 25, 2016
    The comment has been removed
    • Anonymous
      July 25, 2016
      The comment has been removed
      • Anonymous
        July 25, 2016
        The comment has been removed
  • Anonymous
    August 03, 2016
    Hi Aaron,i was wondering(i will test that too:) when i have few minutes)but wouldnt idfix identify these?Thanks
    • Anonymous
      August 05, 2016
      In this particular environment, I don't have the ability to run IDFix against these objects. They are being synced into a BPOS-D tenant and written directly without any API checking. In my instance, I also have a lot of objects with an unprintable characters that this catches.
      • Anonymous
        August 05, 2016
        Thanks for getting back to me:)Now i get itI'm wondering if there is a character "flaw" that idfix wont catch and this will
        • Anonymous
          August 08, 2016
          I'm guessing Bill probably uses Net.Mail.MailAddress or something that performs a similar function in IDFix; I didn't have the ability to run IDFix in the source environment, since it's in Office 365 Dedicated, so I had to deal with whatever results were given to me. :-)
  • Anonymous
    August 22, 2016
    Great work - thanks
    • Anonymous
      May 02, 2017
      Thanks!