Exchange Proxy Address (alias) Report

EDIT (April 4 2015):

This script has been updated significantly, please make sure you’re using version 5.

————–

Exchange Server stores user’s alternate email addresses as a multi-valued attribute within Active Directory.  For example, if my colleague Jorge has jdiaz@demolab.local as well as diazj@demolab.local, his proxyAddresses attribute would look like this:

ADUC - ProxyAddresses

Notice, the capital SMTP vs. the lowercase smtp.  There can be only one uppercase SMTP, and this represents the primary, or “reply to” address.

While, it’s very easy to view someone’s proxy addresses (often called aliases, but don’t confuse it with the “alias” attribute) within the Exchange Management Console, it can be tough to work with in the Exchange Management Shell (PowerShell) due to the data being stored as a  “Multi-Valued” attribute.  The usual “Get-Mailbox” output not only shows all addresses as a single item, but in the case “mcrowley” below, we can see the shell truncates:

get-mailbox mcrowley | select emailaddresses

While there are ways (example1, example2) to manipulate this output on the screen, I recently needed to create a complete list of all users possessing one or more secondary email address, and document what those addresses were.

On the surface, this sounds simple.  We want a list of users who have more than 1 proxy address.  At first, I thought of something like this:

Get-Mailbox -Filter {emailaddresses -gt 1} | Select EmailAddresses

Get-Mailbox -Filter {emailaddresses -gt 1} | Select EmailAddresses

But we can see this doesn’t actually capture the correct users.  In the above example, LiveUser1 only has a single proxy address, but it was returned anyway.  This is because the result is actually converted to a number, and the “-gt” or “greater than” operation is done on this number; not what we want.

I have written a script to help!

Features:

  1. This script creates a CSV output of everyone’s SMTP proxy addresses.
  2. Reports to the screen the total number of users found.
  3. Reports to the screen the user(s) with the most proxy addresses.
  4. You can configure the threshold of users reported. For example, if you only wanted users with 2 or more proxy addresses included, you should change the line: “$Threshold = 0” to “$Threshold = 2”

Misc:

  1. Does not currently work with Exchange Online (planned enhancement).
  2. This uses “get-recipient” with no filters by default.  You may want to  replace this with something more restrictive, like “get-mailbox”, or use the -filter parameter.
  3. Requires PS 2.0 (for Exchange 2007, see here)

Here is a sample output, shown in excel:

Sample output to screen:

The guts of this script might help with this exact scenario, or really, anywhere you want to break out and evaluate multi-valued attributes.  Feel free to use it and adjust as you see fit!

Download the script here, or copy from the text below:

<#

Features:
    1) This script Creates a TXT and CSV file with the following information:
        a) TXT file: Recipient Address Statistics
        b) CSV file: Output of everyone's SMTP proxy addresses.

Instructions:
    1) Run this from "regular" PowerShell.  Exchange Management Shell may cause problems, especially in Exchange 2010, due to PSv2.
    2) Usage: RecipientReportv5.ps1 server5.domain.local

Requirements:
    1) Exchange 2010 or 2013
    2) PowerShell 4.0

 
April 4 2015
Mike Crowley
 
http://BaselineTechnologies.com
 
#>

param(
    [parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false,HelpMessage='Type the name of a Client Access Server')][string]$ExchangeFQDN
    )

if ($host.version.major -le 2) {
    Write-Host ""
    Write-Host "This script requires PowerShell 3.0 or later." -ForegroundColor Red
    Write-Host "Note: Exchange 2010's EMC always runs as version 2.  Perhaps try launching PowerShell normally." -ForegroundColor Red
    Write-Host ""
    Write-Host "Exiting..." -ForegroundColor Red
    Sleep 3
    Exit
    }


if ((Test-Connection $ExchangeFQDN -Count 1 -Quiet) -ne $true) {
    Write-Host ""
    Write-Host ("Cannot connect to: " + $ExchangeFQDN) -ForegroundColor Red
    Write-Host ""
    Write-Host "Exiting..." -ForegroundColor Red
    Sleep 3
    Exit
    }

cls

 
#Misc variables
#$ExchangeFQDN = "exchserv1.domain1.local"
$ReportTimeStamp = (Get-Date -Format s) -replace ":", "."
$TxtFile = "$env:USERPROFILE\Desktop\" + $ReportTimeStamp + "_RecipientAddressReport_Part_1of2.txt"
$CsvFile = "$env:USERPROFILE\Desktop\" + $ReportTimeStamp + "_RecipientAddressReport_Part_2of2.csv"

#Connect to Exchange
Write-Host ("Connecting to " + $ExchangeFQDN + "...") -ForegroundColor Cyan
Get-PSSession | Where-Object {$_.ConfigurationName -eq 'Microsoft.Exchange'} | Remove-PSSession
$Session = @{
    ConfigurationName = 'Microsoft.Exchange'
    ConnectionUri = 'http://' + $ExchangeFQDN + '/PowerShell/?SerializationLevel=Full' 
    Authentication = 'Kerberos'
    }
Import-PSSession (New-PSSession @Session) 

#Get Data
Write-Host "Getting data from Exchange..." -ForegroundColor Cyan
$AcceptedDomains = Get-AcceptedDomain
$InScopeRecipients = @(
    'DynamicDistributionGroup'
    'UserMailbox'
    'MailUniversalDistributionGroup'
    'MailUniversalSecurityGroup'
    'MailNonUniversalGroup'
    'PublicFolder'
    )
$AllRecipients = Get-Recipient -recipienttype $InScopeRecipients -ResultSize unlimited | select name, emailaddresses, RecipientType
$UniqueRecipientDomains = ($AllRecipients.emailaddresses | Where {$_ -like 'smtp*'}) -split '@' | where {$_ -NotLike 'smtp:*'} | select -Unique

Write-Host "Preparing Output 1 of 2..." -ForegroundColor Cyan
#Output address stats
$TextBlock = @(
    "Total Number of Recipients: " + $AllRecipients.Count
    "Number of Dynamic Distribution Groups: " +         ($AllRecipients | Where {$_.RecipientType -eq 'DynamicDistributionGroup'}).Count
    "Number of User Mailboxes: " + 	                    ($AllRecipients | Where {$_.RecipientType -eq 'UserMailbox'}).Count
    "Number of Mail-Universal Distribution Groups: " + 	($AllRecipients | Where {$_.RecipientType -eq 'MailUniversalDistributionGroup'}).Count
    "Number of Mail-UniversalSecurity Groups: " + 	    ($AllRecipients | Where {$_.RecipientType -eq 'MailUniversalSecurityGroup'}).Count
    "Number of Mail-NonUniversal Groups: " + 	        ($AllRecipients | Where {$_.RecipientType -eq 'MailNonUniversalGroup'}).Count
    "Number of Public Folders: " + 	                    ($AllRecipients | Where {$_.RecipientType -eq 'PublicFolder'}).Count
    ""
    "Number of Accepted Domains: " + $AcceptedDomains.count 
    ""
    "Number of domains found on recipients: " + $UniqueRecipientDomains.count 
    ""
    $DomainComparrison = Compare-Object $AcceptedDomains.DomainName $UniqueRecipientDomains
    "These domains have been assigned to recipients, but are not Accepted Domains in the Exchange Organization:"
    ($DomainComparrison | Where {$_.SideIndicator -eq '=>'}).InputObject 
    ""
    "These Accepted Domains are not assigned to any recipients:" 
    ($DomainComparrison | Where {$_.SideIndicator -eq '<='}).InputObject
    ""
    "See this CSV for a complete listing of all addresses: " + $CsvFile
    )

Write-Host "Preparing Output 2 of 2..." -ForegroundColor Cyan

$RecipientsAndSMTPProxies = @()
$CounterWatermark = 1
 
$AllRecipients | ForEach-Object {
    
    #Create a new placeholder object
    $RecipientOutputObject = New-Object PSObject -Property @{
        Name = $_.Name
        RecipientType = $_.RecipientType
        SMTPAddress0 =  ($_.emailaddresses | Where {$_ -clike 'SMTP:*'} ) -replace "SMTP:"
        }    
    
    #If applicable, get a list of other addresses for the recipient
    if (($_.emailaddresses).count -gt '1') {       
        $OtherAddresses = @()
        $OtherAddresses = ($_.emailaddresses | Where {$_ -clike 'smtp:*'} ) -replace "smtp:"
        
        $Counter = $OtherAddresses.count
        if ($Counter -gt $CounterWatermark) {$CounterWatermark = $Counter}
        $OtherAddresses | ForEach-Object {
            $RecipientOutputObject | Add-Member -MemberType NoteProperty -Name (“SmtpAddress” + $Counter) -Value ($_ -replace "smtp:")
            $Counter--
            }
        }
        $RecipientsAndSMTPProxies += $RecipientOutputObject
    }
  
 
$AttributeList = @(
    'Name'
    'RecipientType'
    )
$AttributeList += 0..$CounterWatermark | ForEach-Object {"SMTPAddress" + $_}


Write-Host "Saving report files to your desktop:" -ForegroundColor Green
Write-Host ""
Write-Host $TxtFile -ForegroundColor Green
Write-Host $CsvFile -ForegroundColor Green

$TextBlock | Out-File $TxtFile
$RecipientsAndSMTPProxies | Select $AttributeList | sort RecipientType, Name | Export-CSV $CsvFile -NoTypeInformation

Write-Host ""
Write-Host ""
Write-Host "Report Complete!" -ForegroundColor Green

24 thoughts on “Exchange Proxy Address (alias) Report

  1. Nice powershell work 🙂 I added SMTP addresses and primary SMTP address attributes to my AD querying tool AD Info not long ago so for anyone that doesn’t want to use powershell you can probably get what you need out of the free edition of that (http://cjwdev.co.uk/Software/ADReportingTool/Info.html). Hope you don’t mind the plug Mike, only mentioning it because I think it might be useful for people that stumble upon this post of yours 🙂

  2. Pingback: Combining PowerShell Cmdlet Results « Mike Crowley's Whiteboard
  3. Here’s a one-liner that will get all SMTP addresses; 1st column is name and 2nd column is SMTP address. So each user will have one line per SMTP address.

    Get-Recipient -resultSize unlimited | select name,company -expand emailAddresses | where {$_.smtpAddress} | ft name,smtpAddress

    • Cool, thanks! I wasn’t aware of the -expand switch. When I wrote this however, my requirement was to have each person on a single row, and only those with multiple SMTP addresses.

  4. Building on your ideas, this one will get you all SMTP addresses from all Recipient Objects and their DNs.

    $SmtpProxyAddresses = Get-Recipient -ResultSize Unlimited | select-object DistinguishedName -expand emailAddresses | where {$_.prefixstring -like ‘smtp’}
    $SmtpProxyAddresses | Select-Object DistinguishedName, SmtpAddress | Export-Csv -NoTypeInformation C:\scripts\All-RecipientSMTP.csv

  5. Heh Mike, best script Ive seen so far!….great work. Is there any way of showing the primary SMTP as the first column or with a diifferent column header?? Thanks

  6. I modified the script to get all the proxy addresses by changing the section building the placeholder object.

    #Create a new placeholder object so that we don’t store the x400/x500 proxy addresses
    $UserAndSmtpObject = New-Object PSObject -Property @{
    Name = $user.name }
    $i = 0
    $SmtpProxyAddresses | foreach {
    $smptaddress = $_ -replace “smtp:”
    $i += 1
    if ($i -eq 1) {
    $UserAndSmtpObject | Add-Member -MemberType NoteProperty -Name PrimarySmtpAddress -Value $smptaddress
    }
    else {
    $UserAndSmtpObject | Add-Member -MemberType NoteProperty -Name (“SmtpAddress” + $i) -Value $smptaddress
    }
    }

    Then in the output section I just remove the select.
    Write-Host “”
    $TooManyProxies | Export-CSV c:\TooManyProxies.csv -notype
    $TooManyProxies
    Write-Host “”

  7. Pingback: Exchange Proxy Address Report Update | Mike Crowley's Whiteboard
  8. Hi, I’ve ran v4 of this script and it’s working fine. However I can see a few email addresses in the CSV file that I can’t see anywhere in EMC or AD…?

    Worried they’re being used to relay spam etc….how can I find/identify them?! They must be *somewhere* if this script is picking them up…

    Cheers.

  9. Pingback: PowerShell Scripts for your Exchange Server Toolkit
  10. Hello Mike,

    Great script. Just one question I had. On this line of the script:

    $RecipientOutputObject | Add-Member -MemberType NoteProperty -Name (“SmtpAddress” + $Counter) -Value ($_ -replace “smtp:”)

    Shouldn’t it be this instead ?

    $RecipientOutputObject | Add-Member -MemberType NoteProperty -Name (“SmtpAddress” + $Counter) -Value ($_)

    I removed the “-replace “smtp:” part with just $_ since you have already taken care of that when storing smtp addresses in the variable $OtherAddresses.

    • Hey, thanks for the comment John. You might be right, its been a while since I worked on this. FYI proxy addresses appear differently in EMC vs vanilla remote PowerShell, so it might have been related to that. it’s also possible i pieced stuff together and didn’t clean up!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s