- вывод сделан объектами
- добавлены поля
- исправлен баг когда первая запись выводилась неправильно
Получение количества отправленных и полученных писем по дням с exchange сервера.
#### Variables #####
# период за который будем смотреть статистику, считается от сегодня
$PeriodIndays = 7
# дата по которую смотрим, должна быть меньше чем стартовая
$EndPeriod = Get-date -hour 0 -minute 0 -second 0
# если пишешь вручную помни что дата задается наоброт ММ/ДД/ГГГГ тоесть "09/5/2016"
$StartPeriod = ($EndPeriod).AddDays( -$PeriodIndays )
####################################################################################
$From = $StartPeriod
$To = $EndPeriod
[Int64] $intSent = 0
[Int64] $intRec = 0
[Int64] $intSentSize = 0
[Int64] $intRecSize = 0
$Total = 0
$TotalSent = 0
$TotalRec = 0
$MailPerDay = @()
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
Do {
$From = $From.AddDays(1)
$To = $From.AddDays(1)
$intSent = $intRec = $intSentSize = $intRecSize = 0
(Get-TransportServer) | Get-MessageTrackingLog -ResultSize Unlimited -Start $From -End $To | ForEach {
# Sent E-mails
If ($_.EventId -eq "RECEIVE" -and $_.Source -eq "STOREDRIVER")
{
$intSent++
$intSentSize += $_.TotalBytes
}
# Received E-mails
If ($_.EventId -eq "DELIVER")
{
$intRec++
$intRecSize += $_.TotalBytes
}
}
$props = [ordered]@{ Date=$From
Sent=$intSent
SentSizeMB=[Math]::Round($intSentSize/1MB, 0)
Recived=$intRec
RecivedSizeMB=[Math]::Round($intRecSize/1MB, 0)
TotalPerDayInMB=[Math]::Round(($intRecSize+$intSentSize)/1MB, 2)
TotalPerDayInGB=[Math]::Round(($intRecSize+$intSentSize)/1GB, 2)
}
$obj = New-Object -TypeName PSObject -Property $props
$MailPerDay += $obj
$TotalSent += $intSentSize
$TotalRec += $intRecSize
} While ($To -lt (Get-Date))
$MailPerDay | ft
Write-Host "всего отправлено за отчетный период $([Math]::Round( $TotalSent/1GB, 2)) гигабайт"
Write-Host "всего получено за отчетный период $([Math]::Round( $TotalRec/1GB, 2)) гигайбайт"
Write-Host "всего получено и отправлено за период $([Math]::Round( ($TotalSent + $TotalRec)/1GB, 2)) гигабайт"
Чтобы получить красивый html отчет, например чтобы отправить по почте ниже дополненный скрипт:
#### Variables #####
# период за который будем смотреть статистику, считается от сегодня
$PeriodIndays = 7
# дата по которую смотрим, должна быть меньше чем стартовая
$EndPeriod = Get-date -hour 0 -minute 0 -second 0
# если пишешь вручную помни что дата задается наоброт ММ/ДД/ГГГГ тоесть "09/5/2016"
$StartPeriod = ($EndPeriod).AddDays( -$PeriodIndays )
# путь до html файла
$PathFile = 'c:\EmailSendAndreceived.html'
####################################################################################
$From = $StartPeriod
$To = $EndPeriod
[Int64] $intSent = 0
[Int64] $intRec = 0
[Int64] $intSentSize = 0
[Int64] $intRecSize = 0
$Total = 0
$TotalSent = 0
$TotalRec = 0
$MailPerDay = @()
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
Do {
$From = $From.AddDays(1)
$To = $From.AddDays(1)
$intSent = $intRec = $intSentSize = $intRecSize = 0
(Get-TransportServer) | Get-MessageTrackingLog -ResultSize Unlimited -Start $From -End $To | ForEach {
# Sent E-mails
If ($_.EventId -eq "RECEIVE" -and $_.Source -eq "STOREDRIVER")
{
$intSent++
$intSentSize += $_.TotalBytes
}
# Received E-mails
If ($_.EventId -eq "DELIVER")
{
$intRec++
$intRecSize += $_.TotalBytes
}
}
$props = [ordered]@{ Date=$From
Sent=$intSent
SentSizeMB=[Math]::Round($intSentSize/1MB, 0)
Recived=$intRec
RecivedSizeMB=[Math]::Round($intRecSize/1MB, 0)
TotalPerDayInMB=[Math]::Round(($intRecSize+$intSentSize)/1MB, 2)
TotalPerDayInGB=[Math]::Round(($intRecSize+$intSentSize)/1GB, 2)
}
$obj = New-Object -TypeName PSObject -Property $props
$MailPerDay += $obj
$TotalSent += $intSentSize
$TotalRec += $intRecSize
} While ($To -lt (Get-Date))
$MailPerDay | ft
Write-Host "всего отправлено за отчетный период $([Math]::Round( $TotalSent/1GB, 2)) гигабайт"
Write-Host "всего получено за отчетный период $([Math]::Round( $TotalRec/1GB, 2)) гигайбайт"
Write-Host "всего получено и отправлено за период $([Math]::Round( ($TotalSent + $TotalRec)/1GB, 2)) гигабайт"
############# HTML generating #############
$frag1 = $MailPerDay | sort -Property Date -Descending | ConvertTo-Html -As table -Fragment -PreContent "<h2>всего получено за период $([Math]::Round( $TotalSent/1GB, 2)) <br> всего отправлено за период $([Math]::Round( $TotalRec/1GB, 2))<br>всего отправлено и получено за период $([Math]::Round( ($TotalSent + $TotalRec)/1GB, 2))</h2>" | Out-String
Write-Verbose 'definiting CSS'
$head = @'
<style>
body { background-color:#ffffff; font-family:Tahoma; font-size:12pt; }
td, th { border:1px solid black; border-collapse:collapse; }
th { color:white; background-color:black; }
table, tr, td, th { padding: 2px; margin: 0px }
table { font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif; font-size: 14px; border-radius: 10px; border-spacing: 0; text-align: center; }
th { background: #BCEBDD; color: white; text-shadow: 0 1px 1px #2D2020; padding: 10px 20px; }
th, td { border-style: solid; border-width: 0 1px 1px 0; border-color: white; }
th:first-child, td:first-child { text-align: left; }
th:first-child { border-top-left-radius: 10px; }
th:last-child { border-top-right-radius: 10px; border-right: none; }
td { padding: 10px 20px; background: #F8E391; }
tr:last-child td:first-child { border-radius: 0 0 0 10px; }
tr:last-child td:last-child { border-radius: 0 0 10px 0; }
tr td:last-child { border-right: none; }
</style>
'@
$Date = Get-Date
$rep = ConvertTo-HTML -head $head -PostContent $frag1 -PreContent "<h1>Email Sent received $Date</h1>" | Out-String
$rep | Out-File $PathFile
Последний сгенерирует html-файл и положит по дефолту в каталог С.
Комментарии (29)
LoadRunner
19.09.2016 16:18Делал похожий велосипед, с авторизацией, выбором периода и пользователей. Только на C#.
Я правильно понимаю, что скрипт корректно отработает только из-под учётной записи с необходимыми правами?
krasaval
19.09.2016 17:25EndPeriod можно выставить и на начало завтрашнего дня, что бы получить статистику с начала дня, до текущего периода. Удобнее когда базовая точка отсчета — 0:00:00, а не время запуска скрипта.
kerberos464
19.09.2016 19:49не подскажете, как сделать так, чтобы можно было запускать этот скрипт дистанционно, а не только с того сервера, на котором установлен Exchange?
проблема в том, что часть коммандлетов, например, Get-Mailbox, подгружается, а часть нет, в т.ч. Get-TransportServer.
пробовал и через RemoteExchange.ps1, и через Import-PSSession:
$ExchangeAddress = «mail.domain.ru»
$ExchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri «http://$ExchangeAddress/PowerShell»
Import-PSSession $ExchangeSessionpak-nikolai
19.09.2016 19:56он и не запустится локально т.к. модули есть только на машине с эксчейнджем. сделайте лучше invoke-command
насчет сессии странно, по идее должно работать правильно. Сегодня не могу проверить
pak-nikolai
20.09.2016 07:20действительно есть такая проблема. командлет постоянно выдает ошибку при запуске из удаленной сессии или через invoke-command. я не нашел способа кроме как копировать на нужную машину и исполнять оттуда, или использовать сторонние решения типа psexec
получается нужно создавать на удаленной машине файл, его исполнять и результаты работы сгружать обратно
n01d
20.09.2016 08:23Через Enter-PSSession и дописать импорт соответствующих модулей перед вызовом командлетов. Без явного импорта командлеты могут не подхватываться.
n01d
20.09.2016 08:30Простите, не увидел сразу в коде подключения PSSnapin`ов… В интернетах пишут, что таки да — часть командлетов не работает по удалёнке. На всякий случай: https://technet.microsoft.com/en-us/library/dd297932%28v=exchg.141%29.aspx
pak-nikolai
20.09.2016 09:53мне кажется это связано както с ограничением WMI эксчейнджа, либо c непольной реализацией обертки PoSH, по идее если реализовать этот же трэкинг лог низкоуровнево должно заработать хотя бы через invok-command и pssession
LoadRunner
20.09.2016 08:37+2Установите соответствующую роль администрирования из установочного образа, без установки остальных ролей exchange.
CucTemaTexHuk
20.09.2016 08:53+1Спасибо за статью.
Делал что то подобное на PowerShell и прикручивал к система мониторинга PRTG для визуализации.
pak-nikolai
20.09.2016 08:54к prtg как прикручивал? у меня такая же стоит
CucTemaTexHuk
20.09.2016 11:57+1Скрипт работает на сервере PRTG. Скрипт подключается к Exchange через командлеты
$session=New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://exchange/powershell
Import-PSSession $session
Скрипт делает расчет только за указанную дельту времени (я установил 1 час), и рассчитывает только две переменные. Сколько получено байт "$ReceivedTOTAL" и сколько отправлено байт "$SentTOTAL"
Вывод результата нужно делать через «write-host» но при этом в формате XML.
#Выводим результат в XML формате для PRTG. write-host '<?xml version="1.0" encoding="Windows-1252" ?>' write-host '<prtg>' write-host '<result>' write-host '<channel>Exchange received traffic</channel>' write-host '<customUnit>Bytes</customUnit>' write-host '<value>'$ReceivedTOTAL'</value>' write-host '</result>' write-host '<result>' write-host '<channel>Exchange send traffic</channel>' write-host '<customUnit>Bytes</customUnit>' write-host '<value>'$SentTOTAL'</value>' write-host '</result>' write-host '</prtg>'
В PRTG создаешь группу которая прослушивает любой действующий IP, т.к. сенсор в этой группе будет запускать PowerShell скрипт, а скрипт сам подключается к Exchange. Т.е. нам не важен какой IP будет прослушивать данная группа. Я использовал IP 127.0.0.1
Далее в группе создаешь сенсор «XML Custom EXE/Script Sensor». В поле «EXE/Script» указываешь скрипт PowerShell, предварительно выложив его на сервере PRTG по пути «c:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML». В поле «Scanning Interval» выставляешь с какой периодичностью будет запускаться скрипт. Периодичность равна дельте времени в скрипте.
И Все. Ждешь когда накопится статистика.
Вроде мы ничего не забыл. С удовольствием отвечу на Ваши вопросы если, что то не понятно.krasaval
21.09.2016 15:17А как рассчитывается дельта? Где хранится предыдущее значение?
CucTemaTexHuk
21.09.2016 18:08+1Дельта не рассчитывается. Она устанавливается в ручную. Например, нужно знать сколько писем пришло за 1 час. 1 час это и будет дельта. Ее мы задаем в скрипте, и в настройке сенсора в PRTG, поле «Scanning Interval». Предыдущее значение скрипт не хранит. Он все время рассчитывает за дельту времени. В моем случае за один час назад (дельта). Как только скрипт рассчитал значение, он их передает в PRTG через «write-host» в формате XML. Смотрите код выше. PRTG строит графики, и хранит последние полученные значения. Смотрите мой скриншот. Период хранения полученной информации, задается настройками PRTG.
Если есть интерес, могу завтра выложить полный код скрипта.krasaval
21.09.2016 18:15было бы интересно взглянуть на полный текст скрипта
CucTemaTexHuk
22.09.2016 06:51+1Скрипт для сбора статистики почтового трафика (отправлено / получено) в байтах на Exchange за дельту времени и отправка в PRTG################################################################################### # Скрипт для сбора статистики почтового трафика (отправлено / получено) в байтах # на Exchange за дельту времени. ################################################################################### # #Сохраняем ошибки в файл "TrafficExchange2XML-Error.xml" и продолжаем выполнение скрипта "continue" trap {$_ | Export-Clixml TrafficExchange2XML-Error.xml; continue} #Отключаем вывод Warning, предварительно запомним текущее значение, для того что бы вернуть его обратно. $CurrentWarningPreference = $WarningPreference $WarningPreference = "SilentlyContinue" #Подключаемся к Exchange #Если консоль Exchange Management Shell установлена #add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010 #Если консоль Exchange Management Shell НЕ установлена. $session=New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://exchange/powershell Import-PSSession $session #Получаем все CAS сервера #Если работает авто определение #$CASs = (Get-ClientAccessServer).Name #Если НЕ работает авто определение $CASs = "CAS01", "CAS02", "CAS03" #Дельта времени подсчета. $DeltaTime = New-TimeSpan -Hours 1 #Переменные для подсчета почтового трафика [int]$ReceivedTOTAL = 0 [int]$SentTOTAL = 0 #Для каждого CAS сервера расчитываем трафик за период времени $DeltaTime ForEach ($CAS in $CASs) { $Received = Get-MessageTrackingLog -Server $CAS -ResultSize unlimited -Start ((Get-Date) - $DeltaTime) -End (Get-Date) -EventId RECEIVE | Measure-Object TotalBytes -sum $Send = Get-MessageTrackingLog -Server $CAS -ResultSize unlimited -Start ((Get-Date) - $DeltaTime) -End (Get-Date) -EventId SEND | Measure-Object TotalBytes -sum $ReceivedTOTAL = $ReceivedTOTAL + $Received.Sum $SentTOTAL = $SentTOTAL + $Send.Sum } #Выводим результат в XML формате для PRTG. write-host '<?xml version="1.0" encoding="Windows-1252" ?>' write-host '<prtg>' write-host '<result>' write-host '<channel>Exchange received traffic</channel>' write-host '<customUnit>Bytes</customUnit>' write-host '<value>'$ReceivedTOTAL'</value>' write-host '</result>' write-host '<result>' write-host '<channel>Exchange send traffic</channel>' write-host '<customUnit>Bytes</customUnit>' write-host '<value>'$SentTOTAL'</value>' write-host '</result>' write-host '</prtg>' #Разрываем сессию с CAS сервером Exchange. Remove-PSSession $session #Возвращаем вывод Warning $WarningPreference = $CurrentWarningPreference
pak-nikolai
22.09.2016 11:30слушай оформи это в статью, у меня тоже стоит 15я PRTG и я туда сгребаю все что можно.
оформи плиз способ как прикручивать туда все что хочешь, все что можно посчитать. Бывает необходимость а нормальной статьи на русском не видел.
Нужна пошаговая инструкция как добавлять в ПРТГ кастомные счетчики.
я на эту статью ссылку просто буду давать, а не писать как что делать
krasaval
Get-TransportServer лучше заменить на Get-TransportService, т.к. он скоро будет исключен
Так же неплохо было бы исключить из общей статистики письма HealthMailbox и inboundproxy
pak-nikolai
может стать несовместимым с exchange 2010
krasaval
хм, действительно, только начиная с 2013.
Еще наверное удобнее время считать с начала дня, что-то вроде этого:
$EndPeriod = (Get-date -hour 0 -minute 0 -second 0)
$StartPeriod = ($EndPeriod).AddDays( -$PeriodIndays )
LoadRunner
Что-то торкнуло меня в Вашем комментарии, только сейчас понял, что именно.
00:00:00 — это начало нового дня. Если выставить EndPeriod на начало дня, то мы не получим статистику писем этого дня, только если какому-то письму посчастливится прийти ровно в 00:00:00 (и то на сервере оно обрабатывается какое-то время и получает разные отметки от разных фильтров и соединителей отправки\получения).