www.SAMURAJ-cz.com 

19.04.2024 Rostislav Translate to English by Google     VÍTEJTE V MÉM SVĚTĚ

Články

Exchange server a statistiky posílání zpráv

Upraveno 25.04.2019 10:00 | vytvořeno 19.10.2013 15:18 | Samuraj - Petr Bouška |
Článek je aktualizován pro Exchange 2016! Myslím, že Exchange serveru chybí jedna zásadní věc, a to jsou různé statistiky o provozu. U konkurenčních produktů je běžné zobrazení řady informací, které Exchange přímo neobsahuje. Například hodinové, denní, týdenní a měsíční statistiky o odeslaných a přijatých emailech, jak interně tak z internetu. Statistiky pro různé konektory. Údaje o nedoručitelnosti, nejčastější příjemci a odesílatelé, populární domény. A když už mluvíme o různých informacích, tak by také mohl Exchange přehledně informovat o svém zdraví. Tento článek je malým navedením, jak některé informace získat.

Pozn.: Popisované informace byly otestovány na Exchange Serveru 2010 SP3.

Tento článek jsem psal pro Exchange 2010, řada věcí vycházela z praktických testů. S příchodem Exchange 2016 přestal nastíněný skript fungovat, protože došlo ke změně některých událostí a třeba také způsobu logování adres. Prostudoval jsem informace k nové verzi a hlavně provedl analýzu mnoha různých vzorků dat pro hlavní situace (dokumentaci, jaké události se logují pro určité situace, jsem nenalezl). Nechtěl jsem přepisovat celý článek, takže v druhé polovině článku jsem doplnil svoje poznámky, které se týkají Exchange 2016, ale také nového pohledu na logy (takže jsou některé věci jinak, než popisuje starý článek).

Aktuální popis použití Get-MessageTrackingLog je v článku Exchange Server 2016 DSN, Message Tracking a analýza posílání zpráv.

Co jsou to Message Tracking Logs

Jediné, co na Exchange serveru máme k dispozici, jsou Message Tracking Logs. Do těch zapisuje role Hub Transport, Edge Transport a Mailbox server všechny aktivity o přenosu zpráv. Logy jsou textové soubory, které se ukládají na serveru. Defaultně se uchovávají po dobu 30 dní a nachází se v cestě C:\Program Files\Microsoft\Exchange Server\V14\TransportRoles\Logs\MessageTracking. Na aktuální nastavení se můžeme podívat pomocí Exchange Management Shell (EMS, tedy PowerShellu).

Get-MailboxServer SERVER | FL Message*
Get-TransportServer SERVER | FL Message*

Pokud bychom chtěli nějakou hodnotu změnit, tak opět využijeme PowerShell. Detailní popis je u Microsoftu v Configure Message Tracking.

Jak s logy pracovat

S logy můžeme pracovat několika způsoby. V Exchange Management Console (EMC) se pod Toolbox nachází Tracking Log Explorer. Můžeme využít další nástroj Microsoftu, což je Log Parser Studio. Nebo můžeme použít EMS, kde máme k dispozici cmdlet Get-MessageTrackingLog.

Příklady procházení tracking logu

Následující příklady slouží pouze k nastínění syntaxe cmdletu Get-MessageTrackingLog. Na začátku si definujeme časový interval jednoho dne.

$Start = (Get-Date).AddDays(-1)
$End = (Get-Date)

Najdeme všechny zprávy (a události) odeslané z adresy jmeno@firma.cz a k nim zobrazíme vyjmenované informace.

Get-MessageTrackingLog -Start $Start -End $End -ResultSize Unlimited | Where-Object { $_.Sender -eq "jmeno@firma.cz" } | FT Timestamp,EventId,Source,ClientHostname,ServerHostname,Sender,Recipients,TotalBytes,RecipientCount,MessageId -AutoSize 

Najdeme všechny události k jedné zprávě s daným MessageId.

Get-MessageTrackingLog -Start $Start -End $End -ResultSize Unlimited | Where-Object { $_.MessageId -eq "<928D4983D1BD6A4790DB8323A23E8A8B4AB386AF@server.firma.local>" }| FT EventId,Sender,Recipients,MessageSubject -AutoSize 

Zobrazíme všechny události daných typů RECEIVE, SEND, DELIVER.

Get-MessageTrackingLog -Start $Start -End $End -ResultSize Unlimited | Where-Object { $_.EventId -eq "RECEIVE" -or $_.EventId -eq "SEND" -or $_.EventId -eq "DELIVER" } | FT EventId,Sender,Recipients -AutoSize 

Jiný způsob zápisů pro vyhledání událostí jednoho typu RECEIVE (stejně můžeme provést i hledání odesílatele pomocí parametru Sender, atd).

Get-MessageTrackingLog -Start $Start -End $End -EventID "RECEIVE" -ResultSize Unlimited | FT Sender, Recipients, TotalBytes -AutoSize 

Informace v logu

Do logů se ukládá velké množství událostí různých typů (EventID). Hlavní události, které nás asi budou zajímat, jsou RECEIVE, SUBMIT, SEND a DELIVER. Související údaj je zdroj události (Source), kde hlavní je SMTP a STOREDRIVER.

Určitý popis událostí a dalších hodnot nalezneme v článku Understanding Message Tracking, Message Tracking (Exchange Server 2013) a Search Message Tracking Logs. Bohužel nikde není graf nebo popis posloupnosti jednotlivých událostí při nějaké akci (například odeslání emailu mimo firmu). Něco popisuje článek Exchange 2013 Mail Flow (Part 3), ale není to vše, co by bylo třeba znát a více informací jsem nenalezl.

Další důležitou hodnotou v logu je MessageId, což je jednoznačný identifikátor, který určuje jednu zprávu kolující v naší organizaci. Můžeme pak vyfiltrovat unikátně všechny zprávy (vždy pouze jednu událost) za určité časové období (zde si je ukládáme do proměnné).

$log = Get-MessageTrackingLog -Start $Start -End $End -ResultSize Unlimited | Where-Object { $_.EventId -eq "RECEIVE" -or $_.EventId -eq "SEND" -or $_.EventId -eq "DELIVER" } | Sort-Object MessageID -Unique | Select-Object Sender,Recipients 

Následně si je vypsat (zde vracíme pouze odesílatele a příjemce) nebo spočítat jejich počet.

$log | FT * -AutoSize 
$log | Measure-Object 

Všechny vlastnosti, které cmdlet vrací, jsou Timestamp, ClientIp, ClientHostname, ServerIp, ServerHostname, SourceContext, ConnectorId, Source, EventId, InternalMessageId, MessageId, Recipients, RecipientStatus, TotalBytes, RecipientCount, RelatedRecipientAddress, Reference, MessageSubject, Sender, ReturnPath, MessageInfo, MessageLatency, MessageLatencyType, EventData.

Varianty posílání zpráv

V praxi nastává mnoho situací, které chceme zaznamenat a které generují různé zprávy do logu. Zprávy máme Inbound (příchozí), Outbound (odchozí), Local (lokální), Remote (vzdálené). Navíc se do procesu zapojuje více rolí Exchange serveru, které si zprávu předávají a také generují události. Role mohou být nainstalovány na jednom serveru, ale také každá samostatně, což způsobí jiné chování. Také můžeme mít více serverů se stejnou rolí (kvůli redundanci a rozložení zátěže, využívá se DAG, CAS Array, apod.), třeba i v různých Site.

Záleží pak na tom, ke kterému Client Access Server (CAS) je uživatel připojen a na kterém se nachází jeho mailbox databáze. V běžných případech v praxi nastává situace, že i když máme v síti více Exchange serverů, tak skoro každou zprávu si předávají mezi sebou dva z nich. Na obrázku níže můžeme nalézt všechny možné varianty, kdy si dva uživatelé posílají zprávu.

Varianty posílání zpráv

Mnoho návodů na internetu využívá příkaz Get-MessageTrackingLog a jednoduše filtruje události SEND pro odeslané zprávy a RECEIVE pro přijaté. To je, ale dle mého názoru, špatně. Když si vypíšeme události pro jednu zprávu, tak zjistíme, že třeba událost RECEIVE se zaloguje několikrát (protože si zprávu předávají ještě servery mezi sebou).

Počítání zpráv

Další důležitá věc na zamyšlení je, jaké zprávy chceme počítat jako odchozí a jaké jako příchozí. Já počítám zprávu mezi odeslané, pokud je odesílatel v mé Exchange organizaci. Stejně tak mezi přijaté, pokud je příjemce v mé organizaci. Pokud si posílají zprávu dva uživatelé organizace, tak se započítá mezi odeslané i přijaté. Otázka je, jak počítat zprávu, která je odeslána více příjemcům (to v tuto chvíli neřeším).

Abych shrnul výše uvedené informace, jedna zpráva (jedno jak poslána) vždy vygeneruje více než jednu událost v logu. V hodně případech se vygeneruje vícekrát událost RECEIVE (protože se zpráva posílá mezi interními servery) a někdy i SEND. Naopak jsou i situace, kdy se při odeslání zprávy vůbec událost SEND negeneruje.

Můžeme si vypsat nějakou část logu seřazenou dle času, pro přesnost včetně milisekund, a analyzovat jaké události se při jaké příležitosti používají.

Get-MessageTrackingLog -Start $Start -End $End -ResultSize Unlimited | Sort-Object Timestamp | FT @{label=’Timestamp [ms]’;Expression={"{0:dd.MM.yyyy HH:mm:ss.fff}" -f $_.Timestamp}}, EventId, Source, ClientHostname, ServerHostname, Sender, Recipients, MessageId

Chtěl jsem dát dohromady tabulku všech situací odeslání a příjmu zprávy, jaké se při ní generují události a v jakém pořadí. Po analýze většího množství praktických situací, jsem zjistil, že pořadí v logu patrně neodpovídá skutečnosti. Několikrát mám u zprávy z internetu dříve zalogované přijetí (receive) na druhém poštovním serveru, než na tom, který přijímá zprávy z internetu. Protože pracujeme s milisekundami, tak patrně hraje roli i nepatrný rozdíl v čase mezi servery.

Takže alespoň události, které se nejčastěji logují pro hlavní situace. Zkratky: I - internet, E1 - první Exchange server přijímá z internetu, E2 - druhý Exchange server.

komunikace počítaná situace události v logu
I - E1 - E2 1x receive RECEIVE - RECEIVE - DELIVER - SEND
E2 - E1 - I 1x send SUBMIT - RECEIVE - SEND
E1 - E2 1x receive, 1x send RECEIVE - SUBMIT - SEND (ne vždy) - RECEIVE - DELIVER

Jak je vidět, tak nemůžeme jednoduše počítat události RECEIVE a SEND. V prvním případě, kdy se má započítat pouze jednou příjem zprávy, by se započítal dvakrát příjem a jednou odeslání. Takže pro určení odeslaných a přijatých zpráv musíme použít něco jiného.

Výpis událostí dle operace

Jedna věc, která nám může pomoci je, že si můžeme vyfiltrovat zprávy odeslané nebo přijaté z firemních adres (domén), případně poslané mezi firemními adresami. Zde si nejprve připravíme proměnné, které budeme používat i dále. Definujeme časový interval 10 minut. Vytvoříme seznam serverů, které generují logy, a seznam všech událostí z těchto serverů za časový interval uložíme do proměnné $log.

$Start = (Get-Date).AddMinutes(-10)
$End = (Get-Date)
$hubs = Get-ExchangeServer | where {$_.isHubTransportServer -eq $true -or $_.isMailboxServer -eq $true} 
$log = $hubs | Get-MessageTrackingLog -Start $Start -End $End -ResultSize Unlimited | Select-Object Timestamp,EventId,Source,ClientHostname,ServerHostname,Sender,Recipients,TotalBytes,RecipientCount,MessageId

Dále již budeme pouze filtrovat údaje v proměnné $log. Zobrazíme záznamy, kde je adresa odesílatele nebo příjemce ukončena názvem naší domény.

$log | Where-Object { $_.Sender -like "*firma.cz" } | FT Timestamp,EventId,Source,ClientHostname,ServerHostname,Sender,Recipients,MessageId
$log | Where-Object { $_.Recipients -like "*firma.cz*" } | FT Timestamp,EventId,Source,ClientHostname,ServerHostname,Sender,Recipients,MessageId
$log | Where-Object { $_.Sender -like "*firma.cz" -and $_.Recipients -like "*firma.cz*" } | FT Timestamp,EventId,Source,ClientHostname,ServerHostname,Sender,Recipients,MessageId

Pro naši situaci výhodnější je jiná možnost, kdy využijeme komunikující servery. Příchozí zprávy do firmy by měli mít právě jednu událost RECEIVE, kde je jako ClientHostname adresa jiná než firemní poštovní servery. Mohou zde být firemní aplikační servery (které můžeme také odfiltrovat, většinou dle domény). Pokud máme nějaký předřazený server (třeba jako Antispam GW), přes který chodí veškerá příchozí pošta, tak můžeme využít jeho adresu.

$log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.ClientHostname -notlike "mailfirma*" } | Sort-Object Timestamp | FT Timestamp,EventId,Source,ClientHostname,ServerHostname,Sender,Recipients,MessageId 

Stejně tak odchozí zprávy do internetu by měli mít právě jednu událost SEND, kde je ServerHostname nějaká adresa serveru v internetu (ne náš poštovní server).

$log | Where-Object { $_.EventId -eq "SEND" -and $_.ServerHostname -notlike "mailfirma*" } | Sort-Object Timestamp | FT Timestamp,EventId,Source,ClientHostname,ServerHostname,Sender,Recipients,MessageId 

Pomocí výše popsaných úvah můžeme spočítat různé statistické údaje. Ze všech zpráv můžeme získat informaci o velikosti největšího emailu, průměrné velikosti a celkovém objemu zpráv.

$mail_all_stats = $log | Sort-Object MessageID -Unique | Measure-Object -Property TotalBytes -Sum -Maximum -Average 

Spočítáme počet přijatých zpráv z internetu, z aplikačních serverů a odeslaných zpráv do internetu. Když tyto hodnoty odečteme od celkového počtu zpráv, tak by nám měl vyjít počet zpráv zaslaných lokálně (to znamená, že je počítáme jako odeslané i jako přijaté). Chybu nám tu budou zavádět zprávy odeslané více příjemcům a zvlášť pokud část příjemců je interní a část mimo firmu. Tyto zprávy se většinou započítají jako jedna (buď interní, nebo externí).

Nejčastější příjemci a odesilatelé

Další zajímavý údaj může být, jaký odesílatel odeslal nejvíce zpráv a jaký příjemce jich nejvíce obdržel. Někoho to může zajímat pouze z pohledu odeslaných zpráv z firmy, mne ale zajímá údaj ze všech zpráv. Pro seznam dvaceti nejčastějších odesílatelů vyfiltrujeme události, kde je vyplněn odesílatel, dle MessageID získáme unikátní události (tedy jednotlivé zprávy), ty seskupíme dle odesílatele, tím získáme i počty (Count). Pak již pouze seřadíme od největšího a vypíšeme požadovaný počet hodnot.

$log | Where-Object { $_.Sender } | Sort-Object MessageID -Unique | Group-Object Sender | Sort-Object Count -Descending | Select -First 20 | FT Count, Name -AutoSize 

Seznam nejčastějších příjemců získáme obdobně.

$log | Where-Object { $_.Recipients } | Sort-Object MessageID -Unique | Group-Object Recipients | Sort-Object Count -Descending | Select -First 20 | FT Count, Values -AutoSize 

Dlouhodobé údaje

To, co jsme si popsali v předchozích kapitolách, můžeme využít třeba ve skriptu, který spustíme každý den v noci a výsledek si necháme zaslat na email. Skript můžeme spustit i za delší období (maximálně takové, jak dlouho se nám ukládají logy), ale to nemusí být praktické. Jiná možnost je, při pravidelném denním spouštění, ukládat denní statistiky do CSV textového souboru. Poté můžeme, třeba v Excelu, získávat dlouhodobější statistiky a grafy.

Komplexní skript

Výše jsem popsal svoje úvahy, které vedly k sestavení následujícího skriptu, který při denním spouštění přináší určité statistické údaje o mailové komunikaci. Hodnoty nejsou stoprocentně přesné a část skriptu vychází z praktického pozorování chování určitého prostředí, takže v jiné konfiguraci může být trochu jiné. Rozhodně je potřeba upravit podmínky v řádcích, kde se počítají hodnoty $mail_receive_inet, $mail_receive_app, $mail_send_inet, tak jak bylo popsáno výše.

Když se skript spustí na poštovním serveru, tak vytvoří textový soubor c:\Skripty\Mail-statistics.txt, který následně odešle jako email (zde jsou další hodnoty, které je třeba upravit dle vašeho prostředí). Potom je dobré připravit soubor c:\Skripty\mail-statistics.csv, do kterého se vloží jeden řádek hlavičky CSV souboru:

date;total;processed;size[MB];receive;receive-inet;receive-app;receive-local;send;send-inet;send-local

Do tohoto souboru se budou doplňovat denní statistické údaje.

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010

$Start = (Get-Date -Hour 00 -Minute 00 -Second 00).AddDays(-1)
$End = (Get-Date -Hour 23 -Minute 9 -Second 59).AddDays(-1)

$hubs = Get-ExchangeServer | where {$_.isHubTransportServer -eq $true -or $_.isMailboxServer -eq $true}

$log = $hubs | Get-MessageTrackingLog -Start $Start -End $End -ResultSize Unlimited | Where-Object { $_.EventId -ne "NOTIFYMAPI" -and $_.EventId -ne "HAREDIRECT" } | Select-Object EventId,ClientHostname,ServerHostname,Sender,Recipients,TotalBytes,MessageId

$mail_all_stats = $log | Sort-Object MessageID -Unique | Measure-Object -Property TotalBytes -Sum -Maximum -Average
$mail_all_unique = $mail_all_stats.Count
$mail_receive_inet = ($log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.ClientHostname -notlike "mailserver1" -and $_.ClientHostname -notlike "mailserver2" -and $_.ClientHostname -notlike "*firma.local" } | Measure-Object).Count
$mail_receive_app = ($log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.ClientHostname -notlike " mailserver1" -and $_.ClientHostname -notlike " mailserver2" -and $_.ClientHostname -like "*firma.local" } | Measure-Object).Count
$mail_send_inet = ($log | Where-Object { $_.EventId -eq "SEND" -and $_.ServerHostname -notlike " mailserver1" -and $_.ServerHostname -notlike " mailserver2" } | Measure-Object).Count
$mail_local = $mail_all_unique - $mail_receive_inet - $mail_receive_app - $mail_send_inet
$mail_send = $mail_send_inet + $mail_local
$mail_receive = $mail_receive_inet + $mail_receive_app + $mail_local
$mail_all = $mail_send + $mail_receive

$str = "Mail servers statistics for date " + $Start.ToShortDateString() +"`r`n`r`n"
$str += "Servers:`r`n" + $hubs
$str += "`r`n`r`nTotal emails:`r`n"
$str += " count: " + "{0:N0}" -f $mail_all + "`r`n"
$str += " processed messages: " + "{0:N0}" -f $mail_all_unique + "`r`n"
$str += " size: " + "{0:N2}" -f ($mail_all_stats.Sum / (1024 * 1024)) + " MB `r`n"
$str += " biggest mail: " + "{0:N2}" -f ($mail_all_stats.Maximum / (1024 * 1024)) + " MB `r`n"
$str += " average size: " + "{0:N2}" -f ($mail_all_stats.Average / 1024) + " kB `r`n"
$str += "`r`n`r`nReceive emails:`r`n"
$str += " count: " + "{0:N0}" -f $mail_receive + "`r`n"
$str += " from internet: " + "{0:N0}" -f $mail_receive_inet + "`r`n"
$str += " from application servers: " + "{0:N0}" -f $mail_receive_app + "`r`n"
$str += " local: " + "{0:N0}" -f $mail_local + "`r`n"
$str += "`r`n`r`nSend emails:`r`n"
$str += " count: " + "{0:N0}" -f $mail_send + "`r`n"
$str += " to internet: " + "{0:N0}" -f $mail_send_inet + "`r`n"
$str += " local: " + "{0:N0}" -f $mail_local + "`r`n"
$str += "`r`n`r`nTop senders:"
$str += $log | Where-Object { $_.Sender } | Sort-Object MessageID -Unique | Group-Object Sender | Sort-Object Count -Descending | Select -First 20 | FT Count, Name -AutoSize | Out-String
$str += "Top recipients:"
$str += $log | Where-Object { $_.Recipients } | Sort-Object MessageID -Unique | Group-Object Recipients | Sort-Object Count -Descending | Select -First 20 | FT Count, Values -AutoSize | Out-String
$str | Out-File -FilePath "c:\Skripty\Mail-statistics.txt" -Width 300

Send-MailMessage -From "admin@firma.cz" -To "prijemce@firma.cz" -Subject "Statistiky z poštovních serverů" -SmtpServer "mailserver1.firma.local" -Attachments "c:\Skripty\Mail-statistics.txt" -Encoding ([System.Text.Encoding]::Unicode) -Body "Ahojda,`n`nStatistiky z posílání pošty za včerejší den.`n`nVáš administrátor ;-)`n`nPS: Vše naleznete v příloze`n"

#date;total;processed;size[MB];receive;receive-inet;receive-app;receive-local;send;send-inet;send-local 
$out = $Start.ToShortDateString() + ";" + $mail_all + ";" + $mail_all_unique + ";" + ($mail_all_stats.Sum / (1024 * 1024)) + ";" + $mail_receive + ";" + $mail_receive_inet + ";" + $mail_receive_app + ";" + $mail_local + ";" + $mail_send + ";" + $mail_send_inet + ";" + $mail_local
$out | Out-File c:\Skripty\mail-statistics.csv -Append -Encoding default

Exchange 2016 a statistiky odeslaných zpráv

Popis níže jsou moje úvahy, které vychází z pozorování a testů. Nemusí tedy být správné nebo přesné. Stejně tak výpočty různých typů zpráv jsou přibližné hodnoty, protože některé speciální situace vyžadují další podmínky a jiné započítaní do celku. Ale řekl bych, že výsledná nepřesnost je pár procent.

Připojení na server

Pokud pracujeme na Exchange serveru (v PowerShellu a ne v Exchange Management Shellu), tak musíme přidat Exchange SnapIn.

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn 

Druhá možnost je připojit se vzdáleně.

$ExchSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI http://SERVER/PowerShell/?SerializationLevel=Full -Authentication Kerberos
Import-PSSession -Session $ExchSession

Pro zrychlení můžeme načítat pouze vybrané příkazy.

Import-PSSession -Session $ExchSession -CommandName Get-Mailbox, New-Mailbox, Enable-Mailbox, Set-Mailbox,
 Add-MailboxFolderPermission, Set-CASMailbox -FormatTypeName *

Na závěr je třeba se odpojit.

Remove-PsSession $ExchSession

Výběr dat z logů

Nejprve si z Exchange serverů uložíme data, za určité období, do proměnné. Při analýze událostí (EventId) zjistíme, že nás zajímají pouze některé. Stejně tak nepotřebujeme ve výsledku všechny atributy (položky, protože počítáme statistické údaje).

Get-MessageTrackingLog -Start $Start -End $End -ResultSize Unlimited | Where-Object {
 $_.EventId -eq "RECEIVE" -or $_.EventId -eq "SEND" -or $_.EventId -eq "DELIVER" -or $_.EventId -eq "SENDEXTERNAL" `
 -or $_.EventId -eq "FAIL" } | Select-Object Timestamp, EventId, Source, Sender, Recipients, ClientIp, OriginalClientIp,
 ServerIp, TotalBytes, MessageId, Directionality, RecipientCount 

Zpracování zpráv

Email (zpráva) je odeslán jedním odesílatelem na jednu nebo více adres, tedy přijat jedním nebo více příjemci (může být také poslán na DG, pak dojde k expand Distribution Group a doručení jednotlivým členům). Události k jedné zprávě jsou identifikovány stejným MessageId. Takže můžeme vyfiltrovat pro každé MessageId jednu událost (dostaneme unikátní zpracované zprávy).

$log | Sort-Object MessageID -Unique 

Tímto způsobem se vybere nějaká událost, kterou nemůžeme určit, a určité atributy se pro různé události mění (třeba velikost zprávy zpracováním narůstá, seznam příjemců může být různý, protože k jedné zprávě může být více událostí doručení), takže nedostaneme úplně přesné hodnoty. Ale můžeme získat počet zpracovaných zpráv a třeba zhruba celkovou velikost (ve skriptu na konci článku je tento příkaz upraven, aby vracel událost s největší velikosti pro zprávu).

$log | Sort-Object MessageID -Unique | Measure-Object -Property TotalBytes -Sum -Maximum -Average 

Pokud bychom chtěli zprávu více příjemcům počítat vícekrát (jako samostatné zprávy odesílatel a každý příjemce), tak bychom museli využít atribut RecipientCount.

Některé zprávy automaticky generují další zprávy, například DSN, Inbox Rules, Out Of Office. Ty mají nové MessageId a v atributu Reference bývá odkaz na zprávu, z které vznikli.

Standardně je každá zpráva odeslaná (jedenkrát) a přijatá (i vícekrát - více příjemců). Když se díváme z pohledu poštovního serveru, tak při odesílání zprávy server nejprve zprávu přijme a pak ji odesílá nebo lokálně doručuje. Interně probíhá často více SMTP odesílání a doručování, pokud máme více serverů a zpráva se posílá mezi nimi.

Ve skriptu (na konci článku) počítáme:

  • $mail_all_stats.Count - počet unikátních MessageId, tedy zpracovaných zpráv, každá by měla mít příjem a odeslání
  • $mail_receive_inet - počet událostí přijetí zprávy z internetu
  • $mail_receive_local - počet událostí přijetí zprávy z lokální schránky
  • $mail_receive_app_anon - počet událostí přijetí zprávy z aplikačního serveru anonymně
  • $mail_receive_app_auth - počet událostí přijetí zprávy z aplikačního serveru autentizovaně
  • $mail_send_inet - počet událostí odeslání zprávy do internetu (jedna zpráva může mít více událostí)
  • $mail_send_local - počet událostí doručení do lokální schránky (jedna zpráva může mít více událostí)
  • $mail_fail - všechny chybové události (nepodařilo se doručit)
  • $mail_send - celkový počet odeslání
  • $mail_receive - celkový počet přijetí
  • $mail_receive_app - celkový počet přijetí z aplikačních serverů

Přijaté zprávy - Receive

Jedná se o zprávy přijaté

  • od lokální schránky (k doručení lokálně nebo mimo) - vyzvednuté ze schránky
  • od odesílatelů mimo organizaci (z internetu, k doručení lokálně) - přes SMTP Receive konektor
  • od firemních aplikačních serverů (k doručení lokálně nebo mimo) - přes SMTP Receive konektor

Některé události nemají standardní příjem, třeba automatická odpověď má Source MAILBOXRULE. Logy zpracováváme za určitou dobu, tak se může stát, že pro nějakou zprávu chybí události ze začátku nebo konce. Proto je v praxi celkový počet zpráv větší, než počet událostí příjmu.

$mail_all_stats.Count >= $mail_receive_inet + $mail_receive_local + $mail_receive_app_anon + $mail_receive_app_auth

Příjem z lokální schránky

  • každá zpráva má jednu STOREDRIVER událost RECEIVE, v OriginalClientIp je většinou adresa odesílatele
$log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.Source -eq "STOREDRIVER" } 

Identifikace dalších přijatých zpráv je složitější, protože SMTP události RECEIVE existují i při předávání zprávy mezi interními servery.

Příjem mimo organizaci

  • jde o anonymní (neautentizovaný) příjem přes SMTP Receive konektor
  • SMTP událost RECEIVE
  • OriginalClientIp je adresa odesílatele
  • pro anonymní příjem nastavuje Exchange atribut Directionality na Incoming
  • takto můžeme posílat i emaily z aplikačních serverů, které nechceme započítat mezi příjem z internetu, takže ještě vynecháme interní adresy odesílatelů (uvedené adresy jsou pouze příklad)
$log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.Source -eq "SMTP" -and $_.Directionality -eq "Incoming" `
 -and $_.OriginalClientIp -notlike "10.0.*" -and $_.OriginalClientIp -notlike "192.168.*" } 

Příjem od aplikačních serverů

  • anonymní - podobné jako příjem mimo organizaci, ale naopak specifikujeme adresy aplikačních serverů, z kterých se zprávy přijímají
$log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.Source -eq "SMTP" -and $_.Directionality -eq "Incoming" `
 -and ($_.OriginalClientIp -like "10.0.*" -or $_.OriginalClientIp -like "192.168.*") } 
  • autentizované - nejsložitější situace
  • SMTP události RECEIVE
  • Directionality je Originating
  • takto se identifikují i zprávy mezi poštovními servery
  • OriginalClientIp může být IP našich serverů nebo klienta (Outlook, může se připojovat i z internetu), potřebujeme tedy určit možné adresy aplikačních serverů mimo poštovních serverů
$log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.Source -eq "SMTP" -and $_.Directionality -eq "Originating" `
 -and $_.OriginalClientIp -notlike "10.0.0.100" -and $_.OriginalClientIp -notlike "10.0.0.110" `
 -and ($_.OriginalClientIp -like "10.0.0.*" -or $_.OriginalClientIp -like "192.168.*") } 

Odeslané (doručené) zprávy - Send

Jedná se o zprávy odeslané

  • k doručení do lokální schránky - vložení do schránky
  • příjemcům mimo organizaci (internet) - pomocí SMTP Send konektoru

Pokud se posílá zpráva na více příjemců, tak pro jedno MessageId existuje jedna událost příjmu (odesílatel je vždy jeden), ale může existovat více událostí odeslání. Zpráva se doručuje do každé databáze schránek, kde se nachází některý příjemce (vždy je jedna událost pro všechny příjemce v jedné DB), případně se odesílá mimo organizaci (jedna událost pro každý cílový server). Většinou je tedy odeslaných zpráv více než celkový počet zpráv.

$mail_all_stats.Count <= $mail_send_inet + $mail_send_local

Odeslání mimo organizaci

  • každá zpráva má jednu SMTP událost SENDEXTERNAL
  • v ServerIp je adresa serveru příjemce
$log | Where-Object { $_.EventId -eq "SENDEXTERNAL" -and $_.Source -eq "SMTP" } 

Doručení do lokální schránky

  • pro každou skupinu příjemců, kteří jsou ve stejné databázi, existuje jedna STOREDRIVER událost DELIVER
  • OriginalClientIp je většinou adresa odesílatele
$log | Where-Object { $_.EventId -eq "DELIVER" -and $_.Source -eq "STOREDRIVER" } 

Nejčastější odesílatelé

Odesílatel zprávy je vždy jeden, takže můžeme vzít unikátní zprávy a seskupit podle odesílatele. Tím dostaneme počty zpráv od jednotlivých odesílatelů.

$log | Where-Object { $_.Sender } | Sort-Object MessageID -Unique | Group-Object Sender | Sort-Object Count -Descending |
 Select-Object -First 20 | FT Count, Name -AutoSize | Out-String

Nejčastější příjemci

Složitější je situace u příjemců, kterých může být více (a zda u distribučních skupin chceme sledovat email skupiny nebo jednotlivé členy). Ukládají se jako pole a podle něj nejde groupovat. Ale můžeme využít parametr ExpandProperty, pak se každá položka pole vloží na samostatný řádek. Přijdeme o ostatní atributy, ale ty v tomto případě nepotřebujeme. Seskupením tedy dostaneme počty mailů pro jednotlivé příjemce (celkový součet pak může být větší než počet unikátních zpráv).

$log | Where-Object { $_.Recipients } | Sort-Object MessageID -Unique | Select-Object -ExpandProperty Recipients |
 Group-Object | Sort-Object Count -Descending | Select -First 20 | FT Count, Values -AutoSize | Out-String

Výsledek, ale nebude přesný. Musíme si uvědomit, že zpráva pro více příjemců má v některých zalogovaných událostech všechny příjemce, ale ve většině jich je méně. Třeba událost o doručení je pro každou mailbox DB jedna a obsahuje příjemce v dané DB. Potřebujeme tedy pro každé MessageId vybrat určitou událost, kde jsou všichni příjemci. Napadl mne způsob níže, kde seskupíme podle MessageId a zpracujeme jednotlivé položky (pro každé MessageId), vybereme vždy tu s největším počtem příjemců. Z ní vezmeme příjemce, které expandujeme a seskupíme.

$log | Where-Object { $_.Recipients } | Group-Object MessageID | ForEach-Object { $_.Group |
 Sort-Object RecipientCount -Descending | Select-Object -First 1 | Select-Object -ExpandProperty Recipients } |
 Group-Object | Sort-Object Count -Descending | Select-Object -First 20 | FT Count, Values -AutoSize | Out-String 

Nástin komplexního skriptu pro Exchange 2016

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn

$Start = (Get-Date -Hour 00 -Minute 00 -Second 00).AddDays(-1)
$End = (Get-Date -Hour 23 -Minute 59 -Second 59).AddDays(-1)

$servers = Get-TransportService

$log = $servers | Get-MessageTrackingLog -Start $Start -End $End -ResultSize Unlimited | Where-Object { $_.EventId -eq "RECEIVE" -or $_.EventId -eq "SEND" -or $_.EventId -eq "DELIVER" -or $_.EventId -eq "SENDEXTERNAL" -or $_.EventId -eq "FAIL" } | Select-Object Timestamp, EventId, Source, Sender, Recipients, ClientIp, OriginalClientIp, ServerIp, TotalBytes, MessageId, Directionality, RecipientCount

$mail_all_stats = $log | Group-Object MessageID | ForEach-Object { $_.Group | Sort-Object TotalBytes -Descending | Select-Object -First 1 } | Measure-Object -Property TotalBytes -Sum -Maximum -Average

$mail_send_inet = ($log | Where-Object { $_.EventId -eq "SENDEXTERNAL" -and $_.Source -eq "SMTP" }).Count
$mail_send_local = ($log | Where-Object { $_.EventId -eq "DELIVER" -and $_.Source -eq "STOREDRIVER" }).Count
$mail_receive_local = ($log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.Source -eq "STOREDRIVER" }).Count
$mail_receive_inet = ($log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.Source -eq "SMTP" -and $_.Directionality -eq "Incoming" -and $_.OriginalClientIp -notlike "10.0.*" -and $_.OriginalClientIp -notlike "192.168.*" }).Count
$mail_receive_app_anon = ($log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.Source -eq "SMTP" -and $_.Directionality -eq "Incoming" -and ($_.OriginalClientIp -like "10.0.*" -or $_.OriginalClientIp -like "192.168.*") }).Count
$mail_receive_app_auth = ($log | Where-Object { $_.EventId -eq "RECEIVE" -and $_.Source -eq "SMTP" -and $_.Directionality -eq "Originating" -and $_.OriginalClientIp -notlike "10.0.0.100" -and $_.OriginalClientIp -notlike "10.0.0.110" -and ($_.OriginalClientIp -like "10.0.0.*" -or $_.OriginalClientIp -like "192.168.*") }).Count
$mail_fail = ($log | Where-Object { $_.EventId -eq "FAIL" }).Count

$mail_send = $mail_send_inet + $mail_send_local
$mail_receive = $mail_receive_inet + $mail_receive_local + $mail_receive_app_anon + $mail_receive_app_auth
$mail_receive_app = $mail_receive_app_anon + $mail_receive_app_auth

$top_senders = $log | Where-Object { $_.Sender } | Sort-Object MessageID -Unique | Group-Object Sender | Sort-Object Count -Descending | Select-Object -First 20 | FT Count, Name -AutoSize | Out-String
$all_recipients = $log | Where-Object { $_.Recipients } | Group-Object MessageID | ForEach-Object { $_.Group | Sort-Object RecipientCount -Descending | Select-Object -First 1 | Select-Object -ExpandProperty Recipients }
$top_recipients = $all_recipients | Group-Object | Sort-Object Count -Descending | Select-Object -First 20 | FT Count, Values -AutoSize | Out-String
$top_FAIL_recipients = $log | Where-Object { $_.EventId -eq "FAIL" -and $_.Recipients } | Sort-Object MessageID -Unique | Select-Object -ExpandProperty Recipients | Group-Object | Sort-Object Count -Descending | Select -First 20 | FT Count, Values -AutoSize | Out-String
$top_FAIL_senders = $log | Where-Object { $_.EventId -eq "FAIL" -and $_.Sender } | Sort-Object MessageID -Unique | Group-Object Sender | Sort-Object Count -Descending | Select -First 20 | FT Count, Values -AutoSize | Out-String

$str = "Mail servers statistics for date " + $Start.ToShortDateString() +"`r`n`r`n"
$str += "Servers:`r`n" + $servers
$str += "`r`n`r`nTotal emails:`r`n"
$str += "  count: " + "{0:N0}" -f $mail_all_stats.Count + "`r`n"
$str += "  size: " + "{0:N2}" -f ($mail_all_stats.Sum / (1024 * 1024)) + " MB `r`n"
$str += "  biggest mail: " + "{0:N2}" -f ($mail_all_stats.Maximum / (1024 * 1024)) + " MB `r`n"
$str += "  average size: " + "{0:N2}" -f ($mail_all_stats.Average / 1024) + " kB `r`n"
$str += "`r`nReceive emails:`r`n"
$str += "  count: " + "{0:N0}" -f $mail_receive + "`r`n"
$str += "  from local mailbox: " + "{0:N0}" -f $mail_receive_local + "`r`n"
$str += "  from internet sender: " + "{0:N0}" -f $mail_receive_inet + "`r`n"
$str += "  from application servers: " + "{0:N0}" -f $mail_receive_app + "`r`n"
$str += "`r`nSent emails:`r`n"
$str += "  count: " + "{0:N0}" -f $mail_send + "`r`n"
$str += "  to local mailbox: " + "{0:N0}" -f $mail_send_local + "`r`n"
$str += "  to internet recipient: " + "{0:N0}" -f $mail_send_inet + "`r`n"
$str += "  recipients count: " + "{0:N0}" -f $all_recipients.Count + "`r`n"
$str += "`r`nFAIL emails: " + "{0:N0}" -f $mail_fail + "`r`n"
$str += "`r`nTop senders:"
$str += $top_senders
$str += "Top recipients:"
$str += $top_recipients
$str += "Top FAIL recipients:"
$str += $top_FAIL_recipients
$str += "Top FAIL senders:"
$str += $top_FAIL_senders
$str | Out-File -FilePath "c:\Scripts\Mail-statistics.txt" -Width 400

Send-MailMessage -From "admin@firma.cz" -To "prijemce@firma.cz" -Subject "Statistiky z poštovních serverů" -SmtpServer "10.0.0.100" -Attachments "c:\Scripts\Mail-statistics.txt" -Encoding ([System.Text.Encoding]::Unicode) -Body "Ahojda,`n`nStatistiky z posílání pošty za včerejší den.`n`nVáš administrátor ;-)`n`nPS: Vše naleznete v příloze`n"

#date;total;size[MB];receive;receive-inet;receive-app;receive-local;sent;sent-inet;sent-local
$out = $Start.ToShortDateString() + ";" + $mail_all_stats.Count + ";" + ($mail_all_stats.Sum / (1024 * 1024)) + ";" + $mail_receive + ";" + $mail_receive_inet + ";" + $mail_receive_app + ";" + $mail_receive_local + ";" + $mail_send + ";" + $mail_send_inet + ";" + $mail_send_local
$out | Out-File c:\Scripts\mail-statistics.csv -Append -Encoding default

Příklad výsledku skriptu

Mail servers statistics for date 24.04.2019

Servers:
MAIL1 MAIL2

Total emails:
  count: 13 763
  size: 750,04 MB 
  biggest mail: 18,32 MB 
  average size: 55,80 kB 

Receive emails:
  count: 13 627
  from local mailbox: 2 586
  from internet sender: 3 343
  from application servers: 7 698

Sent emails:
  count: 16 229
  to local mailbox: 13 910
  to internet recipient: 2 319
  recipients count: 22 235

FAIL emails: 101

Top senders:
Count Name                            
----- ----                            
 3927 xxxxx@firma.cz       
 1259 xxxxx@firma.cz
  565 xxxxx@firma.cz      
  467 xxxxx@firma.cz      

Top recipients:
Count Values                       
----- ------                       
  804 {xxxxx@firma.cz}          
  777 {xxxxx@firma.cz}          
  758 {xxxxx@firma.cz}           
  748 {xxxxx@firma.cz}   
  
Top FAIL recipients:
Count Values                                                                                      
----- ------                                                                                      
   26 {xxxxx@firma.cz}                                                                        
   10 {xxxxx@gmail.com}                                                    
    7 {xxxxx@seznam.cz}

Top FAIL senders:
Count Values                                                         
----- ------                                                         
   16 {xxxxx@firma.cz}                             
   16 {xxxxx@firma.cz}
   12 {xxxxx@firma.cz}
zobrazeno: 20511krát | Komentáře [5]

Autor:

Související články:

Microsoft Exchange

Jednou částí mé práce je administrace poštovního serveru od firmy Microsoft, tedy Exchange Serveru. Články začínají u verze 2003 a jak jde čas, tak pokračují dále.

Pokud se chcete vyjádřit k tomuto článku, využijte komentáře níže.

Komentáře

  1. [1] Jan

    Ahoj, velice povedený článek :)

    Nicméně měl bych dotaz, řešil jsi někdy nastavení správného času v logu? Ukazuje se mi tam o 2 hodiny méně, zřejmě je log nastaven dle GMT. Dá se to nějak změnit?

    Úterý, 01.04.2014 10:21 | odpovědět
  2. [2] Samuraj

    odpověď na [1]Jan: Neřešil, časy mám OK. Čekal bych, že záleží na nastavení serveru.

    Úterý, 01.04.2014 10:26 | odpovědět
  3. [3] Martin

    Zdravím, chci složit poklonu za vynikající článek. A rád bych položil jeden dotaz. Lze v rámci logování získávat informaci o IP adrese, na které se uživatel přihlásil do svého OWA účtu?

    Děkuji

    Pátek, 24.04.2015 13:48 | odpovědět
  4. [4] Samuraj

    odpověď na [3]Martin: Díky :-). To je trochu jiná oblast, než řešil tento článek. Nevím, jestli je na to nějaká jednoduchá možnost, ale připojení na OWA je klasicky služba IIS. To se loguje do W3SVC1 logů a z nich by to mohlo jít vytáhnout, i když je potřeba vymyslet nějaké inteligentní filtrování (je tam i ActiveSync a vůbec spousta informací).

    Pátek, 24.04.2015 14:06 | odpovědět
  5. [5] Marek

    odpověď na [3]Martin:

    Ahoj,

    musíš použít audit pro daný účet. Než můžeš hledat v audit logu, musíš jej povolit a potom si nastavit práva, aby jsi v něm mohl hledat.

    Pondělí, 21.01.2019 14:01 | odpovědět
Přidat komentář

Vložit tag: strong em link

Vložit smajlík: :-) ;-) :-( :-O

Nápověda:
  • maximální délka komentáře je 2000 znaků
  • HTML tagy nejsou povoleny (budou odstraněny), použít se mohou pouze speciální tagy (jsou uvedeny nad vstupním polem)
  • nový řádek (ENTER) ukončí odstavec a začne nový
  • pokud odpovídáte na jiný komentář, vložte na začátek odstavce (řádku) číslo komentáře v hranatých závorkách