Как собрать статистику с MS Exchange 2019
Статистика по наполнению системы
Статистику нужно собирать на пассивном сервере (Passive Node):
-
Скопируйте скрипт в файл с именем Get-ExchangeStats.ps1 и сохраните его на диске. Например:
C:\Scripts\.Get-ExchangeStats.ps1
#Requires -Version 5.1 <# .SYNOPSIS Сбор статистики Exchange 2019 .DESCRIPTION Собирает метрики по почте и календарям с поддержкой случайной выборки .PARAMETER ResultPath Путь для сохранения отчёта (по умолчанию текущая папка) .PARAMETER SamplePercent Процент пользователей для выборки (0-100). По умолчанию 100% (все пользователи) .PARAMETER SampleSize Точное количество пользователей для выборки (переопределяет SamplePercent) .PARAMETER RandomSeed Фиксированное зерно для генератора случайных чисел (для воспроизводимости результатов) .EXAMPLE .\Get-ExchangeStats.ps1 .\Get-ExchangeStats.ps1 -ResultPath "C:\Reports" .\Get-ExchangeStats.ps1 -SamplePercent 10 .\Get-ExchangeStats.ps1 -SampleSize 500 -RandomSeed 42 #> param( [string]$ResultPath = $PSScriptRoot, [ValidateRange(1,100)] [int]$SamplePercent = 100, [ValidateRange(1,1000000)] [int]$SampleSize = 0, [int]$RandomSeed = $null ) $ErrorActionPreference = "Stop" if (-not (Get-Command Get-Mailbox -ErrorAction SilentlyContinue)) { Write-Error "Запустите скрипт из Exchange Management Shell" exit 1 } Write-Host "`n════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " СБОР СТАТИСТИКИ EXCHANGE 2019" -ForegroundColor Cyan Write-Host "════════════════════════════════════════════════════════════`n" -ForegroundColor Cyan if (-not (Test-Path $ResultPath)) { New-Item -ItemType Directory -Path $ResultPath -Force | Out-Null } Write-Host "[1/5] Получение списка пользователей..." -ForegroundColor Yellow $allMailboxes = Get-Mailbox -ResultSize Unlimited -Filter "RecipientTypeDetails -eq 'UserMailbox'" $totalUsersAll = $allMailboxes.Count Write-Host " Найдено пользователей (всего): $totalUsersAll" -ForegroundColor Green # Формирование выборки $mailboxes = $allMailboxes if ($SampleSize -gt 0) { if ($SampleSize -ge $totalUsersAll) { Write-Host " SampleSize >= общему количеству, берём всех пользователей" -ForegroundColor Yellow } else { if ($RandomSeed -ne $null) { Get-Random -SetSeed $RandomSeed | Out-Null } $mailboxes = $allMailboxes | Get-Random -Count $SampleSize Write-Host " Взята выборка $SampleSize пользователей из $totalUsersAll" -ForegroundColor Green } } elseif ($SamplePercent -lt 100) { $sampleCount = [math]::Max(1, [int]($totalUsersAll * $SamplePercent / 100)) if ($RandomSeed -ne $null) { Get-Random -SetSeed $RandomSeed | Out-Null } $mailboxes = $allMailboxes | Get-Random -Count $sampleCount Write-Host " Взята выборка $SamplePercent% пользователей ($sampleCount из $totalUsersAll)" -ForegroundColor Green } else { Write-Host " Берём всех пользователей (100%)" -ForegroundColor Green } $totalUsers = $mailboxes.Count Write-Host " Обрабатывается пользователей: $totalUsers" -ForegroundColor Yellow Write-Host "`n─── РЕЗУЛЬТАТ БЛОКА 1 ───" -ForegroundColor Cyan Write-Host "Всего пользователей в системе: $totalUsersAll" -ForegroundColor White if ($totalUsers -lt $totalUsersAll) { Write-Host "Размер выборки: $totalUsers пользователей ($([math]::Round($totalUsers / $totalUsersAll * 100, 1))%)" -ForegroundColor White Write-Host "Коэффициент экстраполяции: $([math]::Round($totalUsersAll / $totalUsers, 2))x" -ForegroundColor White } else { Write-Host "Обрабатываются все пользователи (100%)" -ForegroundColor White } Write-Host "───────────────────────`n" -ForegroundColor Cyan Write-Host "[2/5] Сбор статистики почты..." -ForegroundColor Yellow $mailStats = @() $totalMessages = 0 $processedCount = 0 foreach ($mbx in $mailboxes) { $processedCount++ if ($totalUsers -gt 100) { Write-Progress -Activity "Обработка почтовых ящиков ($processedCount из $totalUsers)" ` -Status "$($mbx.DisplayName)" ` -PercentComplete (($processedCount / $totalUsers) * 100) } try { $stats = Get-MailboxFolderStatistics -Identity $mbx.Alias -FolderScope Inbox -ErrorAction SilentlyContinue $itemsCount = ($stats | Measure-Object -Property ItemsInFolder -Sum).Sum $totalMessages += $itemsCount $mailStats += [PSCustomObject]@{ DisplayName = $mbx.DisplayName EmailAddress = $mbx.PrimarySmtpAddress TotalMessages = $itemsCount } } catch { Write-Warning "Ошибка: $($mbx.DisplayName) - $($_.Exception.Message)" } } if ($totalUsers -gt 100) { Write-Progress -Activity "Обработка почтовых ящиков" -Completed } $maxMessagesUser = $mailStats | Sort-Object TotalMessages -Descending | Select-Object -First 1 $avgMessages = if ($totalUsers -gt 0) { [math]::Round($totalMessages / $totalUsers, 0) } else { 0 } Write-Host "`n─── РЕЗУЛЬТАТ БЛОКА 2 ───" -ForegroundColor Cyan Write-Host "Всего писем (в выборке): $totalMessages" -ForegroundColor White Write-Host "Среднее писем на пользователя: $avgMessages" -ForegroundColor White if ($maxMessagesUser) { Write-Host "Максимум писем у пользователя: $($maxMessagesUser.TotalMessages)" -ForegroundColor White } Write-Host "───────────────────────`n" -ForegroundColor Cyan Write-Host "[3/5] Сбор статистики календарей..." -ForegroundColor Yellow $calendarStats = @() $calendarFolders = @() $usersWithCalendar = 0 $processedCount = 0 foreach ($mbx in $mailboxes) { $processedCount++ if ($totalUsers -gt 100) { Write-Progress -Activity "Обработка календарей ($processedCount из $totalUsers)" ` -Status "$($mbx.DisplayName)" ` -PercentComplete (($processedCount / $totalUsers) * 100) } try { $calendars = Get-MailboxFolderStatistics -Identity $mbx.Alias -FolderScope Calendar -ErrorAction SilentlyContinue if ($calendars.Count -gt 0) { $usersWithCalendar++ $calendarCount = $calendars.Count $totalEvents = ($calendars | Measure-Object -Property ItemsInFolder -Sum).Sum $calendarStats += [PSCustomObject]@{ DisplayName = $mbx.DisplayName EmailAddress = $mbx.PrimarySmtpAddress CalendarCount = $calendarCount TotalEvents = $totalEvents } foreach ($cal in $calendars) { $calendarFolders += [PSCustomObject]@{ DisplayName = $mbx.DisplayName CalendarName = $cal.Name EventsCount = $cal.ItemsInFolder } } } } catch { } } if ($totalUsers -gt 100) { Write-Progress -Activity "Обработка календарей" -Completed } $totalCalendarEvents = ($calendarFolders | Measure-Object -Property EventsCount -Sum).Sum $maxCalendarsUser = $calendarStats | Sort-Object CalendarCount -Descending | Select-Object -First 1 $maxEventsCalendar = $calendarFolders | Sort-Object EventsCount -Descending | Select-Object -First 1 $calendarPercent = if ($totalUsers -gt 0) { [math]::Round(($usersWithCalendar / $totalUsers) * 100, 1) } else { 0 } Write-Host "`n─── РЕЗУЛЬТАТ БЛОКА 3 ───" -ForegroundColor Cyan Write-Host "Пользователей с календарём (в выборке): $usersWithCalendar из $totalUsers ($calendarPercent%)" -ForegroundColor White Write-Host "Всего событий календаря (в выборке): $totalCalendarEvents" -ForegroundColor White Write-Host "Среднее событий на пользователя с календарём: $([math]::Round($totalCalendarEvents / ($usersWithCalendar + 1), 0))" -ForegroundColor White if ($maxCalendarsUser) { Write-Host "Максимум календарей у пользователя: $($maxCalendarsUser.CalendarCount)" -ForegroundColor White } if ($maxEventsCalendar) { Write-Host "Максимум событий в одном календаре: $($maxEventsCalendar.EventsCount)" -ForegroundColor White } Write-Host "───────────────────────`n" -ForegroundColor Cyan Write-Host "[4/5] Сбор статистики писем за период..." -ForegroundColor Yellow $endDate = Get-Date $startDate1Day = $endDate.AddDays(-1) $startDate7Days = $endDate.AddDays(-7) $messages1Day = 0 $messages7Days = 0 try { $tracking1Day = Get-MessageTrackingLog -Start $startDate1Day -End $endDate -EventId "DELIVER" -ResultSize Unlimited -ErrorAction SilentlyContinue $messages1Day = $tracking1Day.Count $tracking7Days = Get-MessageTrackingLog -Start $startDate7Days -End $endDate -EventId "DELIVER" -ResultSize Unlimited -ErrorAction SilentlyContinue $messages7Days = $tracking7Days.Count Write-Host " Данные за период собраны" -ForegroundColor Green } catch { Write-Warning "Не удалось собрать данные MessageTracking (требуются права администратора)" $messages1Day = "N/A" $messages7Days = "N/A" } Write-Host "`n─── РЕЗУЛЬТАТ БЛОКА 4 ───" -ForegroundColor Cyan if ($messages1Day -ne "N/A") { Write-Host "Писем за последние 24 часа: $messages1Day" -ForegroundColor White Write-Host "Писем за последние 7 дней: $messages7Days" -ForegroundColor White Write-Host "Средняя дневная активность: $([math]::Round($messages7Days / 7, 0)) писем/день" -ForegroundColor White } else { Write-Host "Статистика писем за период недоступна (недостаточно прав)" -ForegroundColor Yellow } Write-Host "───────────────────────`n" -ForegroundColor Cyan Write-Host "[5/5] Расчёт оценочных значений для всей системы..." -ForegroundColor Yellow $ratio = $totalUsersAll / $totalUsers if ($totalUsers -lt $totalUsersAll) { $estimatedTotalMessages = [bigint]($totalMessages * $ratio) $estimatedCalendarEvents = [bigint]($totalCalendarEvents * $ratio) $estimatedUsersWithCalendar = [int]($usersWithCalendar * $ratio) Write-Host " Выполнена экстраполяция на всех пользователей" -ForegroundColor Green } else { $estimatedTotalMessages = $totalMessages $estimatedCalendarEvents = $totalCalendarEvents $estimatedUsersWithCalendar = $usersWithCalendar } Write-Host "`n════════════════════════════════════════════════════════════" -ForegroundColor Green Write-Host " РЕЗУЛЬТАТЫ СТАТИСТИКИ" -ForegroundColor Green Write-Host "════════════════════════════════════════════════════════════`n" -ForegroundColor Green $results = @( [PSCustomObject]@{ Метрика = "Количество пользователей (всего)"; Значение = $totalUsersAll } [PSCustomObject]@{ Метрика = "Обработано пользователей в выборке"; Значение = "$totalUsers" } ) if ($totalUsers -lt $totalUsersAll) { $results += [PSCustomObject]@{ Метрика = "───────────────────────────────"; Значение = "────────────────" } $results += [PSCustomObject]@{ Метрика = "ДАННЫЕ ПО ВЫБОРКЕ:"; Значение = "" } } $results += @( [PSCustomObject]@{ Метрика = "Всего писем (в выборке)"; Значение = $totalMessages } [PSCustomObject]@{ Метрика = "Среднее писем на пользователя"; Значение = $avgMessages } [PSCustomObject]@{ Метрика = "Макс. писем у пользователя"; Значение = if ($maxMessagesUser) { "$($maxMessagesUser.TotalMessages)" } else { "—" } } [PSCustomObject]@{ Метрика = ""; Значение = "" } [PSCustomObject]@{ Метрика = "Пользователей с календарём (в выборке)"; Значение = $usersWithCalendar } [PSCustomObject]@{ Метрика = "Всего событий календаря (в выборке)"; Значение = $totalCalendarEvents } [PSCustomObject]@{ Метрика = "Макс. календарей у пользователя"; Значение = if ($maxCalendarsUser) { "$($maxCalendarsUser.CalendarCount)" } else { "—" } } [PSCustomObject]@{ Метрика = "Макс. событий в одном календаре"; Значение = if ($maxEventsCalendar) { "$($maxEventsCalendar.EventsCount)" } else { "—" } } ) if ($totalUsers -lt $totalUsersAll) { $results += [PSCustomObject]@{ Метрика = ""; Значение = "" } $results += [PSCustomObject]@{ Метрика = "ПРОГНОЗ НА ВСЕХ ПОЛЬЗОВАТЕЛЕЙ:"; Значение = "" } $results += @( [PSCustomObject]@{ Метрика = "Всего писем (прогноз)"; Значение = $estimatedTotalMessages } [PSCustomObject]@{ Метрика = "Всего событий календаря (прогноз)"; Значение = $estimatedCalendarEvents } [PSCustomObject]@{ Метрика = "Пользователей с календарём (прогноз)"; Значение = $estimatedUsersWithCalendar } ) } $results += @( [PSCustomObject]@{ Метрика = ""; Значение = "" } [PSCustomObject]@{ Метрика = "Писем созданных за 1 день"; Значение = $messages1Day } [PSCustomObject]@{ Метрика = "Писем созданных за 7 дней"; Значение = $messages7Days } [PSCustomObject]@{ Метрика = "Средняя дневная активность"; Значение = if ($messages7Days -ne "N/A") { "$([math]::Round($messages7Days / 7, 0)) писем/день" } else { "N/A" } } ) $results | Format-Table -AutoSize -Property Метрика, Значение $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $csvPath = Join-Path $ResultPath "ExchangeStats_$timestamp.csv" $results | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8 -Delimiter ";" Write-Host "`n════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " Отчёт сохранён: $csvPath" -ForegroundColor Green Write-Host "════════════════════════════════════════════════════════════`n" -ForegroundColor Cyan -
Запустите Exchange Management Shell от имени администратора.
-
Перейдите в папку с скриптом Get-ExchangeStats.ps:
-
Запустите скрипт, чтобы сохранить отчет в текущей папке:
Чтобы сохранить в конкретной папке:
Чтобы запустить скрипт по случайной выборке из 10% пользователей:
Чтобы запустить скрипт по случайной выборке из 1000 пользователей:
Как выглядит отчет после выполнения скрипта
════════════════════════════════════════════════════════════
РЕЗУЛЬТАТЫ СТАТИСТИКИ
════════════════════════════════════════════════════════════
Метрика Значение
------- --------
Количество пользователей 13
Всего писем 1234
Макс. количество писем у пользователя 1006
Количество пользователей с календарем 11
Всего событий календаря (items) 146
Макс. календарей у пользователя 6
Макс. событий в одном календаре 60
Писем созданных за 1 день 0
Писем созданных за 7 дней 0
════════════════════════════════════════════════════════════
Отчёт сохранён: c:\ExchangeReports\ExchangeStats_20260414_101421.csv
════════════════════════════════════════════════════════════
Чтобы получать данные о количестве созданных писем за 1 и 7 дней убедитесь, что включено отслеживание писем (Message Tracking):
Чтобы получать подробную информацию формируйте отчет ежедневно в течение недели. Для наиболее полного охвата статистических данных собирайте информацию за час до начала рабочего дня и заканчивайте через час после его окончания.
Статистика по активности пользователей
Статистику нужно собирать на серверах с ролью Client Access (CAS):
-
Скопируйте скрипт в файл с именем Get-OWAStats.ps1 и сохраните его на диске каждого сервера CAS. Например:
C:\Scripts\.Get-OWAStats.ps1
# Requires -Version 5.1 <# .SYNOPSIS Сбор метрик активности OWA с Exchange сервера .DESCRIPTION Скрипт собирает производительность OWA счетчиков и сохраняет в CSV файл. Счетчики соответствуют стандартному набору производительности Exchange. .PARAMETER ResultPath Путь для сохранения CSV файла (по умолчанию: C:\OWA_Metrics) .PARAMETER IntervalSeconds Интервал сбора данных в секундах (по умолчанию: 5) .EXAMPLE .\Get-OWAStats.ps1 .\Get-OWAStats.ps1 -ResultPath "D:\Reports" -IntervalSeconds 10 #> param( [string]$ResultPath = "C:\OWA_Metrics", [int]$IntervalSeconds = 5 ) $counters = @( "\MSExchange OWA\Attachments Uploaded Since OWA Start", "\MSExchange OWA\Average Search Time", "\MSExchange OWA\Calendar View Refreshed", "\MSExchange OWA\Calendar Views Loaded", "\MSExchange OWA\Current Unique Users", "\MSExchange OWA\Current Users", "\MSExchange OWA\Logons/sec", "\MSExchange OWA\Mail View Refreshes", "\MSExchange OWA\Mail Views Loaded", "\MSExchange OWA\Messages Sent", "\MSExchange OWA\Peak User Count", "\MSExchange OWA\Requests/sec", "\MSExchange OWA\Searches", "\MSExchange OWA\Total Unique Users" ) if (-not (Test-Path $ResultPath)) { New-Item -ItemType Directory -Path $ResultPath -Force | Out-Null } $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $outputFile = Join-Path $ResultPath "OWA_Metrics_$timestamp.csv" $header = "Timestamp," + ($counters -join ",") $header | Out-File -FilePath $outputFile -Encoding UTF8 Write-Host "`n════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " СБОР МЕТРИК OWA (Outlook Web Access)" -ForegroundColor Cyan Write-Host "════════════════════════════════════════════════════════════`n" -ForegroundColor Cyan Write-Host " Счётчиков: $($counters.Count)" -ForegroundColor Yellow Write-Host " Интервал: $IntervalSeconds секунд" -ForegroundColor Yellow Write-Host " Файл: $outputFile" -ForegroundColor Yellow Write-Host "`n Для остановки нажмите Ctrl+C...`n" -ForegroundColor Green $iteration = 0 while ($true) { $iteration++ try { $data = Get-Counter -ComputerName "." -Counter $counters -SampleInterval $IntervalSeconds -MaxSamples 1 -ErrorAction Stop if ($data -ne $null) { $timestamp = $data.Timestamp.ToString("yyyy-MM-dd HH:mm:ss") $values = @() foreach ($counter in $counters) { $sample = $data.CounterSamples | Where-Object { $_.Path -like "*$counter" } if ($sample -ne $null) { $rawValue = $sample.CookedValue if ($counter -like "*Average Search Time*") { $val = [math]::Round($rawValue, 2) } elseif ($rawValue -ge 0 -and $rawValue -lt 1000000) { $val = [math]::Round($rawValue, 0) } else { $val = [math]::Round($rawValue, 2) } $values += $val } else { $values += "N/A" } } $line = "$timestamp," + ($values -join ",") Add-Content -Path $outputFile -Value $line $currentUsers = if ($values[4] -ne "N/A") { $values[4] } else { $values[5] } $requestsPerSec = if ($values[11] -ne "N/A") { $values[11] } else { "N/A" } Write-Host "[$timestamp] Итерация $iteration | Текущие пользователи: $currentUsers | Requests/sec: $requestsPerSec" -ForegroundColor Green } } catch { Write-Warning "Ошибка при сборе данных: $($_.Exception.Message)" Write-Host "Повторная попытка через $IntervalSeconds секунд..." -ForegroundColor Yellow Start-Sleep -Seconds $IntervalSeconds continue } Start-Sleep -Milliseconds 100 } -
Убедитесь, что запущена служба PerfHost на каждом сервере CAS.
-
Запустите Exchange Management Shell от имени администратора на каждом сервере CAS.
-
Перейдите в папку с скриптом Get-ExchangeStats.ps:
-
Запустите скрипт, чтобы сохранить отчет в текущей папке:
Чтобы сохранить в конкретной папке:
Как выглядит отчет после выполнения скрипта
════════════════════════════════════════════════════════════
СБОР МЕТРИК OWA (Outlook Web Access)
════════════════════════════════════════════════════════════
Счётчиков: 14
Интервал: 5 секунд
Файл: c:\ExchangeReports\OWA_Metrics_20260414_103825.csv
Для остановки нажмите Ctrl+C...
[2026-04-14 10:38:30] Итерация 1 | Текущие пользователи: 0 | Requests/sec: 0
[2026-04-14 10:38:36] Итерация 2 | Текущие пользователи: 0 | Requests/sec: 0
[2026-04-14 10:38:41] Итерация 3 | Текущие пользователи: 1 | Requests/sec: 1
[2026-04-14 10:38:46] Итерация 4 | Текущие пользователи: 1 | Requests/sec: 0
[2026-04-14 10:38:51] Итерация 5 | Текущие пользователи: 1 | Requests/sec: 0
[2026-04-14 10:38:56] Итерация 6 | Текущие пользователи: 1 | Requests/sec: 0
[2026-04-14 10:39:01] Итерация 7 | Текущие пользователи: 1 | Requests/sec: 0
[2026-04-14 10:39:06] Итерация 8 | Текущие пользователи: 1 | Requests/sec: 0
Чтобы получать подробную информацию формируйте отчет ежедневно в течение недели на каждом сервере CAS. Для наиболее полного охвата статистических данных собирайте информацию за час до начала рабочего дня и заканчивайте через час после его окончания.