Загрузка данных
# =====================================================================
# Diagnostic collector for Andrey Terekhin
# Exchange Server 2019
#
# READ ONLY:
# - ничего не меняет
# - не запускает Managed Folder Assistant
# - не назначает Retention Policy
# - Search-Mailbox используется только с -EstimateResultOnly
# =====================================================================
$ErrorActionPreference = "Continue"
# ---------------------------------------------------------------------
# SETTINGS
# ---------------------------------------------------------------------
$Identity = "Andrey.Terekhin@fmc-ag.ru"
# Та же дата, которая использовалась исходным collector:
$CutoffDate = [datetime]"2025-07-23"
$TimeStamp = Get-Date -Format "yyyyMMdd_HHmmss"
$OutDir = Join-Path $PWD "Terekhin_Diagnostics_$TimeStamp"
New-Item -Path $OutDir -ItemType Directory -Force | Out-Null
$MainLog = Join-Path $OutDir "00_Summary.txt"
function Write-Log {
param(
[string]$Text
)
$Text | Tee-Object -FilePath $MainLog -Append
}
Write-Log "============================================================"
Write-Log "Exchange Archive Diagnostic Collector"
Write-Log "Mailbox: $Identity"
Write-Log "Collected: $(Get-Date)"
Write-Log "CutoffDate: $($CutoffDate.ToString('yyyy-MM-dd'))"
Write-Log "Server: $env:COMPUTERNAME"
Write-Log "============================================================"
Write-Log ""
# =====================================================================
# 1. MAILBOX CONFIGURATION
# =====================================================================
Write-Host "[1/9] Mailbox configuration..." -ForegroundColor Yellow
try {
$Mailbox = Get-Mailbox -Identity $Identity -ErrorAction Stop
$Mailbox |
Format-List `
DisplayName,
Identity,
DistinguishedName,
PrimarySmtpAddress,
Alias,
Database,
ExchangeGuid,
ArchiveStatus,
ArchiveState,
ArchiveDatabase,
ArchiveGuid,
ArchiveName,
RetentionPolicy,
RetentionHoldEnabled,
RetentionComment,
RetentionUrl,
LitigationHoldEnabled,
InPlaceHolds,
ElcProcessingDisabled,
SingleItemRecoveryEnabled,
RecoverableItemsQuota,
RecoverableItemsWarningQuota |
Out-File `
-FilePath (Join-Path $OutDir "01_Mailbox_Config.txt") `
-Encoding UTF8
Write-Log "Mailbox found."
Write-Log "Database : $($Mailbox.Database)"
Write-Log "ArchiveStatus : $($Mailbox.ArchiveStatus)"
Write-Log "ArchiveDatabase : $($Mailbox.ArchiveDatabase)"
Write-Log "RetentionPolicy : $($Mailbox.RetentionPolicy)"
}
catch {
Write-Log "ERROR Get-Mailbox: $($_.Exception.Message)"
}
# =====================================================================
# 2. PRIMARY MAILBOX STATISTICS
# =====================================================================
Write-Host "[2/9] Primary mailbox statistics..." -ForegroundColor Yellow
try {
$PrimaryStats = Get-MailboxStatistics `
-Identity $Identity `
-ErrorAction Stop
$PrimaryStats |
Format-List `
DisplayName,
Database,
MailboxGuid,
ItemCount,
TotalItemSize,
TotalDeletedItemSize,
DeletedItemCount,
LastLogonTime,
LastLoggedOnUserAccount,
DisconnectReason,
IsArchiveMailbox |
Out-File `
-FilePath (Join-Path $OutDir "02_Primary_Statistics.txt") `
-Encoding UTF8
Write-Log ""
Write-Log "PRIMARY:"
Write-Log "ItemCount : $($PrimaryStats.ItemCount)"
Write-Log "TotalItemSize : $($PrimaryStats.TotalItemSize)"
}
catch {
Write-Log "ERROR Primary statistics: $($_.Exception.Message)"
}
# =====================================================================
# 3. ARCHIVE MAILBOX STATISTICS
# =====================================================================
Write-Host "[3/9] Archive mailbox statistics..." -ForegroundColor Yellow
try {
$ArchiveStats = Get-MailboxStatistics `
-Identity $Identity `
-Archive `
-ErrorAction Stop
$ArchiveStats |
Format-List `
DisplayName,
Database,
MailboxGuid,
ItemCount,
TotalItemSize,
TotalDeletedItemSize,
DeletedItemCount,
LastLogonTime,
DisconnectReason,
IsArchiveMailbox |
Out-File `
-FilePath (Join-Path $OutDir "03_Archive_Statistics.txt") `
-Encoding UTF8
Write-Log ""
Write-Log "ARCHIVE:"
Write-Log "ItemCount : $($ArchiveStats.ItemCount)"
Write-Log "TotalItemSize : $($ArchiveStats.TotalItemSize)"
}
catch {
Write-Log "ERROR Archive statistics: $($_.Exception.Message)"
}
# =====================================================================
# 4. PRIMARY MAILBOX FOLDER STATISTICS
# =====================================================================
Write-Host "[4/9] Primary mailbox folder statistics..." -ForegroundColor Yellow
try {
Get-MailboxFolderStatistics `
-Identity $Identity `
-ErrorAction Stop |
Select-Object `
Name,
FolderPath,
FolderType,
ItemsInFolder,
ItemsInFolderAndSubfolders,
FolderSize,
FolderAndSubfolderSize,
OldestItemReceivedDate,
NewestItemReceivedDate |
Export-Csv `
-Path (Join-Path $OutDir "04_Primary_Folders.csv") `
-NoTypeInformation `
-Encoding UTF8
}
catch {
Write-Log "ERROR Primary folder statistics: $($_.Exception.Message)"
}
# =====================================================================
# 5. ARCHIVE MAILBOX FOLDER STATISTICS
# =====================================================================
Write-Host "[5/9] Archive mailbox folder statistics..." -ForegroundColor Yellow
try {
Get-MailboxFolderStatistics `
-Identity $Identity `
-Archive `
-ErrorAction Stop |
Select-Object `
Name,
FolderPath,
FolderType,
ItemsInFolder,
ItemsInFolderAndSubfolders,
FolderSize,
FolderAndSubfolderSize,
OldestItemReceivedDate,
NewestItemReceivedDate |
Export-Csv `
-Path (Join-Path $OutDir "05_Archive_Folders.csv") `
-NoTypeInformation `
-Encoding UTF8
}
catch {
Write-Log "ERROR Archive folder statistics: $($_.Exception.Message)"
}
# =====================================================================
# 6. RETENTION POLICY + TAGS
# =====================================================================
Write-Host "[6/9] Retention policy..." -ForegroundColor Yellow
try {
$Mailbox = Get-Mailbox -Identity $Identity -ErrorAction Stop
if ($Mailbox.RetentionPolicy) {
$Policy = Get-RetentionPolicy `
-Identity $Mailbox.RetentionPolicy `
-ErrorAction Stop
$Policy |
Format-List * |
Out-File `
-FilePath (Join-Path $OutDir "06_RetentionPolicy.txt") `
-Encoding UTF8
$Tags = foreach ($TagName in $Policy.RetentionPolicyTagLinks) {
try {
Get-RetentionPolicyTag `
-Identity $TagName `
-ErrorAction Stop |
Select-Object `
Name,
Type,
RetentionEnabled,
AgeLimitForRetention,
RetentionAction,
MessageClass,
TriggerForRetention,
SystemTag
}
catch {
[PSCustomObject]@{
Name = $TagName
Type = $null
RetentionEnabled = $null
AgeLimitForRetention = $null
RetentionAction = $null
MessageClass = $null
TriggerForRetention = $null
SystemTag = $null
}
}
}
$Tags |
Export-Csv `
-Path (Join-Path $OutDir "07_RetentionPolicyTags.csv") `
-NoTypeInformation `
-Encoding UTF8
}
else {
Write-Log "WARNING: RetentionPolicy is empty."
}
}
catch {
Write-Log "ERROR Retention Policy: $($_.Exception.Message)"
}
# =====================================================================
# 7. MANAGED FOLDER ASSISTANT / ELC DIAGNOSTICS
# =====================================================================
Write-Host "[7/9] Managed Folder Assistant diagnostics..." -ForegroundColor Yellow
try {
$Diagnostic = Export-MailboxDiagnosticLogs `
-Identity $Identity `
-ExtendedProperties `
-ErrorAction Stop
$Diagnostic.MailboxLog |
Out-File `
-FilePath (Join-Path $OutDir "08_MailboxDiagnosticLogs_RAW.xml") `
-Encoding UTF8
try {
[xml]$Xml = $Diagnostic.MailboxLog
$ELCProperties = @(
$Xml.Properties.MailboxTable.Property |
Where-Object {
$_.Name -like "ELC*" -or
$_.Name -like "*Retention*" -or
$_.Name -like "*Archive*"
} |
Select-Object Name,Value
)
$ELCProperties |
Export-Csv `
-Path (Join-Path $OutDir "09_ELC_Properties.csv") `
-NoTypeInformation `
-Encoding UTF8
Write-Log ""
Write-Log "ELC/MFA properties:"
foreach ($Property in $ELCProperties) {
Write-Log "$($Property.Name) = $($Property.Value)"
}
}
catch {
Write-Log "ERROR parsing MailboxDiagnosticLogs XML: $($_.Exception.Message)"
}
}
catch {
Write-Log "ERROR Export-MailboxDiagnosticLogs: $($_.Exception.Message)"
}
# =====================================================================
# 8. SEARCH-MAILBOX ESTIMATES
#
# ВАЖНО:
# запросы выполняются ПОСЛЕ включения архива.
#
# -DoNotIncludeArchive означает, что мы сейчас проверяем,
# сколько подходящих писем осталось В PRIMARY.
#
# Ничего не копируется и не удаляется.
# =====================================================================
Write-Host "[8/9] Search-Mailbox estimates..." -ForegroundColor Yellow
$SearchResults = New-Object System.Collections.Generic.List[object]
function Invoke-DiagnosticSearch {
param(
[string]$Name,
[string]$Query
)
Write-Host " $Name" -ForegroundColor DarkGray
try {
$Result = Search-Mailbox `
-Identity $Identity `
-SearchQuery $Query `
-EstimateResultOnly `
-DoNotIncludeArchive `
-SearchDumpster:$false `
-WarningAction SilentlyContinue `
-ErrorAction Stop |
Select-Object -First 1
$SearchResults.Add(
[PSCustomObject]@{
Name = $Name
SearchQuery = $Query
ResultItemsCount = $Result.ResultItemsCount
ResultItemsSize = [string]$Result.ResultItemsSize
Error = $null
}
)
}
catch {
$SearchResults.Add(
[PSCustomObject]@{
Name = $Name
SearchQuery = $Query
ResultItemsCount = $null
ResultItemsSize = $null
Error = $_.Exception.Message
}
)
}
}
# ---------------------------------------------------------------------
# Исходный запрос из collector.
# ---------------------------------------------------------------------
Invoke-DiagnosticSearch `
-Name "Original_BroadQuery" `
-Query "Kind:email AND Received<07/23/2025"
# ---------------------------------------------------------------------
# Несколько независимых диапазонов.
#
# Нам они нужны для диагностики того, как Search-Mailbox
# интерпретирует даты.
#
# Эти результаты НЕ суммировать как новый migration estimate.
# ---------------------------------------------------------------------
Invoke-DiagnosticSearch `
-Name "Before_2020" `
-Query 'Kind:email AND Received<01/01/2020'
Invoke-DiagnosticSearch `
-Name "2020" `
-Query 'Kind:email AND Received>=01/01/2020 AND Received<01/01/2021'
Invoke-DiagnosticSearch `
-Name "2021" `
-Query 'Kind:email AND Received>=01/01/2021 AND Received<01/01/2022'
Invoke-DiagnosticSearch `
-Name "2022" `
-Query 'Kind:email AND Received>=01/01/2022 AND Received<01/01/2023'
Invoke-DiagnosticSearch `
-Name "2023" `
-Query 'Kind:email AND Received>=01/01/2023 AND Received<01/01/2024'
Invoke-DiagnosticSearch `
-Name "2024" `
-Query 'Kind:email AND Received>=01/01/2024 AND Received<01/01/2025'
Invoke-DiagnosticSearch `
-Name "2025_to_cutoff" `
-Query 'Kind:email AND Received>=01/01/2025 AND Received<07/23/2025'
$SearchResults |
Export-Csv `
-Path (Join-Path $OutDir "10_SearchMailbox_CurrentPrimary.csv") `
-NoTypeInformation `
-Encoding UTF8
Write-Log ""
Write-Log "CURRENT SEARCH-MAILBOX RESULTS:"
foreach ($Result in $SearchResults) {
Write-Log ""
Write-Log "[$($Result.Name)]"
Write-Log "Query : $($Result.SearchQuery)"
Write-Log "Count : $($Result.ResultItemsCount)"
Write-Log "Size : $($Result.ResultItemsSize)"
if ($Result.Error) {
Write-Log "ERROR : $($Result.Error)"
}
}
# =====================================================================
# 9. DATABASE COPY / ARCHIVE DATABASE INFO
# =====================================================================
Write-Host "[9/9] Database information..." -ForegroundColor Yellow
try {
$Mailbox = Get-Mailbox -Identity $Identity
$DatabaseNames = @(
[string]$Mailbox.Database
[string]$Mailbox.ArchiveDatabase
) |
Where-Object {
-not [string]::IsNullOrWhiteSpace($_)
} |
Select-Object -Unique
foreach ($DatabaseName in $DatabaseNames) {
$SafeName = $DatabaseName -replace '[\\/:*?"<>|]', '_'
try {
Get-MailboxDatabase `
-Identity $DatabaseName `
-Status |
Format-List `
Name,
Server,
Mounted,
DatabaseSize,
AvailableNewMailboxSpace,
EdbFilePath,
LogFolderPath |
Out-File `
-FilePath (
Join-Path $OutDir "11_Database_$SafeName.txt"
) `
-Encoding UTF8
}
catch {
Write-Log "ERROR database $DatabaseName : $($_.Exception.Message)"
}
}
}
catch {
Write-Log "ERROR database collection: $($_.Exception.Message)"
}
# =====================================================================
# FINISH
# =====================================================================
Write-Log ""
Write-Log "============================================================"
Write-Log "Collection completed: $(Get-Date)"
Write-Log "Output directory: $OutDir"
Write-Log "============================================================"
$ZipPath = "$OutDir.zip"
try {
Compress-Archive `
-Path (Join-Path $OutDir "*") `
-DestinationPath $ZipPath `
-Force
Write-Host ""
Write-Host "DONE" -ForegroundColor Green
Write-Host "ZIP: $ZipPath" -ForegroundColor Green
}
catch {
Write-Host ""
Write-Host "Collection completed, but ZIP creation failed:" -ForegroundColor Yellow
Write-Host $_.Exception.Message -ForegroundColor Yellow
Write-Host "Folder: $OutDir" -ForegroundColor Green
}