Tuesday 7 May 2013

Microsoft: Microsoft Exchange Server 2010 Email Traffic Reporting


This Powershell script allows you to easily generate the past one month email traffic report that consists of the following information:

  1. User
  2. Total Sent
  3. Total Sent (MB)
  4. Total Received
  5. Total Received (MB)
  6. Sent Internal
  7. Sent Internal (MB) 
  8. Sent External 
  9. Sent External (MB)
  10. Received Internal 
  11. Received Internal (MB) 
  12. Received External 
  13. Received External (MB) 
  14. Total Sent Unique 
  15. Total Sent Unique (MB)
  16. Sent Internal Unique
  17. Sent Internal Unique (MB) 
  18. Sent External  Unique
  19. Sent External Unique (MB) 

The report is in CSV format and it is stored in C drive.


$today = get-date
$rundate = $($today.adddays(-30)).toshortdatestring()

$outfile_date = ([datetime]$rundate).tostring("yyyy_MM")
$outfile = "Email_traffic_" + $outfile_date + ".csv"

$dl_stat_file = "DL_stats.csv"

$accepted_domains = Get-AcceptedDomain |% {$_.domainname.domain}
[regex]$dom_rgx = "`(?i)(?:" + (($accepted_domains |% {"@" + [regex]::escape($_)}) -join "|") + ")$"

$mbx_servers = Get-ExchangeServer |? {$_.serverrole -match "Mailbox"}|% {$_.fqdn}
[regex]$mbx_rgx = "`(?i)(?:" + (($mbx_servers |% {"@" + [regex]::escape($_)}) -join "|") + ")\>$"

$msgid_rgx = "^\<.+@.+\..+\>$"

$hts = get-exchangeserver |? {$_.serverrole -match "hubtransport"} |% {$_.name}

$exch_addrs = @{}

$msgrec = @{}
$bytesrec = @{}

$msgrec_exch = @{}
$bytesrec_exch = @{}

$msgrec_smtpext = @{}
$bytesrec_smtpext = @{}

$total_msgsent = @{}
$total_bytessent = @{}
$unique_msgsent = @{}
$unique_bytessent = @{}

$total_msgsent_exch = @{}
$total_bytessent_exch = @{}
$unique_msgsent_exch = @{}
$unique_bytessent_exch = @{}

$total_msgsent_smtpext = @{}
$total_bytessent_smtpext = @{}
$unique_msgsent_smtpext=@{}
$unique_bytessent_smtpext = @{}

$dl = @{}


$obj_table = {
@"
User = $($address.split("@")[0])
Total Sent = $(0 + $total_msgsent[$address])
Total Sent (MB) = $("{0:F2}" -f $($total_bytessent[$address]/1mb))
Total Received = $(0 + $msgrec[$address])
Total Received (MB) = $("{0:F2}" -f $($bytesrec[$address]/1mb))
Sent Internal = $(0 + $total_msgsent_exch[$address])
Sent Internal (MB) = $("{0:F2}" -f $($total_bytessent_exch[$address]/1mb))
Sent External = $(0 + $total_msgsent_smtpext[$address])
Sent External (MB) = $("{0:F2}" -f $($total_bytessent_smtpext[$address]/1mb))
Received Internal = $(0 + $msgrec_exch[$address])
Received Internal (MB) = $("{0:F2}" -f $($bytesrec_exch[$address]/1mb))
Received External = $(0 + $msgrec_smtpext[$address])
Received External (MB) = $("{0:F2}" -f $($bytesrec_smtpext[$address]/1mb))
Total Sent Unique = $(0 + $unique_msgsent[$address])
Total Sent Unique (MB) = $("{0:F2}" -f $($unique_bytessent[$address]/1mb))
Sent Internal Unique  = $(0 + $unique_msgsent_exch[$address])
Sent Internal Unique (MB) = $("{0:F2}" -f $($unique_bytessent_exch[$address]/1mb))
Sent External  Unique = $(0 + $unique_msgsent_smtpext[$address])
Sent External Unique (MB) = $("{0:F2}" -f $($unique_bytessent_smtpext[$address]/1mb))
"@
}

$props = $obj_table.ToString().Split("`n")|% {if ($_ -match "(.+)="){$matches[1].trim()}}

$stat_recs = @()

function time_pipeline {
param ($increment  = 1000)
begin{$i=0;$timer = [diagnostics.stopwatch]::startnew()}
process {
    $i++
    if (!($i % $increment)){Write-host “`rProcessed $i in $($timer.elapsed.totalseconds) seconds?-nonewline}
    $_
    }
end {
    write-host “`rProcessed $i log records in $($timer.elapsed.totalseconds) seconds?
    Write-Host "   Average rate: $([int]($i/$timer.elapsed.totalseconds)) log recs/sec."
    }
}

foreach ($ht in $hts){

    Write-Host "`nStarted processing $ht"

    get-messagetrackinglog -Server $ht -Start "$rundate" -End "$today" -resultsize unlimited |
    time_pipeline |%{
   
   
    if ($_.eventid -eq "DELIVER" -and $_.source -eq "STOREDRIVER"){
   
        if ($_.messageid -match $mbx_rgx -and $_.sender -match $dom_rgx) {
           
            $total_msgsent[$_.sender] += $_.recipientcount
            $total_bytessent[$_.sender] += ($_.recipientcount * $_.totalbytes)
            $total_msgsent_exch[$_.sender] += $_.recipientcount
            $total_bytessent_exch[$_.sender] += ($_.totalbytes * $_.recipientcount)
       
            foreach ($rcpt in $_.recipients){
            $exch_addrs[$rcpt] ++
            $msgrec[$rcpt] ++
            $bytesrec[$rcpt] += $_.totalbytes
            $msgrec_exch[$rcpt] ++
            $bytesrec_exch[$rcpt] += $_.totalbytes
            }
           
        }
       
        else {
            if ($_messageid -match $messageid_rgx){
                    foreach ($rcpt in $_.recipients){
                        $msgrec[$rcpt] ++
                        $bytesrec[$rcpt] += $_.totalbytes
                        $msgrec_smtpext[$rcpt] ++
                        $bytesrec_smtpext[$rcpt] += $_.totalbytes
                    }
                }
       
            }
               
    }
   
   
    if ($_.eventid -eq "RECEIVE" -and $_.source -eq "STOREDRIVER"){
        $exch_addrs[$_.sender] ++
        $unique_msgsent[$_.sender] ++
        $unique_bytessent[$_.sender] += $_.totalbytes
       
            if ($_.recipients -match $dom_rgx){
                $unique_msgsent_exch[$_.sender] ++
                $unique_bytessent_exch[$_.sender] += $_.totalbytes
                }

            if ($_.recipients -notmatch $dom_rgx){
                $ext_count = ($_.recipients -notmatch $dom_rgx).count
                $unique_msgsent_smtpext[$_.sender] ++
                $unique_bytessent_smtpext[$_.sender] += $_.totalbytes
                $total_msgsent[$_.sender] += $ext_count
                $total_bytessent[$_.sender] += ($ext_count * $_.totalbytes)
                $total_msgsent_smtpext[$_.sender] += $ext_count
                 $total_bytessent_smtpext[$_.sender] += ($ext_count * $_.totalbytes)
                }
                             
           
        }
       
    if ($_.eventid -eq "expand"){
        $dl[$_.relatedrecipientaddress] ++
        }
    }    
   
}

foreach ($address in $exch_addrs.keys){

$stat_rec = (new-object psobject -property (ConvertFrom-StringData (&$obj_table)))
$stat_recs += $stat_rec | select $props
}

$stat_recs | export-csv C:\$outfile -notype

if (Test-Path $dl_stat_file){
    $DL_stats = Import-Csv $dl_stat_file
    $dl_list = $dl_stats |% {$_.address}
    }
   
else {
    $dl_list = @()
    $DL_stats = @()
    }


$DL_stats |% {
    if ($dl[$_.address]){
        if ([datetime]$_.lastused -le [datetime]$rundate){
            $_.used = [int]$_.used + [int]$dl[$_.address]
            $_.lastused = $rundate
            }
        }
}
   
$dl.keys |% {
    if ($dl_list -notcontains $_){
        $new_rec = "" | select Address,Used,Since,LastUsed
        $new_rec.address = $_
        $new_rec.used = $dl[$_]
        $new_rec.Since = $rundate
        $new_rec.lastused = $rundate
        $dl_stats += @($new_rec)
    }
}

Write-Host "`nRun time was $(((get-date) - $today).totalseconds) seconds."
Write-Host "Email stats file is $outfile" 

9 comments:

  1. Got this when I tried to run the script:

    [PS] D:\lou>./EmailTrafficReporting.ps1
    The string starting:
    At D:\lou\EmailTrafficReporting.ps1:49 char:2
    + <<<< @"
    is missing the terminator: "@.
    At D:\lou\EmailTrafficReporting.ps1:204 char:1
    + <<<<
    + CategoryInfo : ParserError: ( User = $($addr...$outfile`"
    :String) [], ParseException
    + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString

    ReplyDelete
    Replies
    1. How did you run the script? Did you modify the script according to your environment?

      Delete
  2. Which values do I need to modify? I didn't set the environment either. Please help!

    ReplyDelete
  3. Exchange 2010 powershell

    ReplyDelete
    Replies
    1. I think the problem is because of the spacing and paragraph problem. Please try to copy the code to MS Word or Notepad and eliminate the extra spacing and paragraph. I think it should work.

      Delete
  4. Hi Andres,

    Could you provide the script in the form of PS1 file as a downloadable link? That would help us to run it smooth.

    ReplyDelete
    Replies
    1. Hi Kishore,

      I prefer you generate the PS1 yourself because you may need to customize the code based on your environment.

      Delete
  5. Thanks for sharing helpful script, it allows to easily generate the email traffic report, but I already tried this exchange reporter tool ( http://www.lepide.com/exchange-reporter/general-reports.html ) which assists to generate the email flow reports in both graphical and tabular format and export the collected data in different files formats like html, csv, xls, mht and rtf.

    ReplyDelete