Загрузка данных


Что тебе нужно выгрузить
1. Создай папку для выгрузок

В Exchange Management Shell:

$Out = "C:\Temp\MailArchivePlan_$(Get-Date -Format yyyyMMdd_HHmm)"
New-Item -ItemType Directory -Path $Out -Force
$Out
2. Текущее состояние БД Exchange
Get-MailboxDatabase -Status |
Select Name,
       Server,
       Mounted,
       DatabaseSize,
       AvailableNewMailboxSpace,
       EdbFilePath,
       LogFolderPath,
       CircularLoggingEnabled,
       LastFullBackup |
Export-Csv "$Out\01_MailboxDatabases.csv" -NoTypeInformation -Encoding UTF8
3. Состояние копий БД, если используется DAG

Выполни даже если не уверен, есть DAG или нет:

Get-MailboxDatabaseCopyStatus * |
Select Name,
       MailboxServer,
       Status,
       ContentIndexState,
       CopyQueueLength,
       ReplayQueueLength,
       ActivationPreference |
Export-Csv "$Out\02_DatabaseCopyStatus.csv" -NoTypeInformation -Encoding UTF8
4. Текущее место на дисках Exchange-серверов

Если PowerShell Remoting работает:

$Servers = Get-MailboxDatabase -Status | Select -ExpandProperty Server -Unique

Invoke-Command -ComputerName $Servers -ScriptBlock {
    Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" |
    Select @{n="Server";e={$env:COMPUTERNAME}},
           DeviceID,
           VolumeName,
           @{n="SizeGB";e={[math]::Round($_.Size/1GB,3)}},
           @{n="FreeGB";e={[math]::Round($_.FreeSpace/1GB,3)}},
           @{n="UsedGB";e={[math]::Round(($_.Size-$_.FreeSpace)/1GB,3)}},
           @{n="FreePercent";e={[math]::Round(($_.FreeSpace/$_.Size)*100,2)}}
} |
Export-Csv "$Out\03_Disks.csv" -NoTypeInformation -Encoding UTF8

Если Remoting не работает — выполни на каждом Exchange-сервере:

Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" |
Select @{n="Server";e={$env:COMPUTERNAME}},
       DeviceID,
       VolumeName,
       @{n="SizeGB";e={[math]::Round($_.Size/1GB,3)}},
       @{n="FreeGB";e={[math]::Round($_.FreeSpace/1GB,3)}},
       @{n="UsedGB";e={[math]::Round(($_.Size-$_.FreeSpace)/1GB,3)}},
       @{n="FreePercent";e={[math]::Round(($_.FreeSpace/$_.Size)*100,2)}} |
Export-Csv "C:\Temp\03_Disks_$env:COMPUTERNAME.csv" -NoTypeInformation -Encoding UTF8
5. Список ящиков и где они сейчас находятся
Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited |
Select DisplayName,
       Alias,
       PrimarySmtpAddress,
       Database,
       ArchiveStatus,
       ArchiveDatabase,
       RetentionPolicy,
       LitigationHoldEnabled,
       InPlaceHolds,
       WhenMailboxCreated |
Export-Csv "$Out\04_Mailboxes.csv" -NoTypeInformation -Encoding UTF8
6. Текущие размеры основных ящиков
Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited |
Get-MailboxStatistics |
Select DisplayName,
       MailboxGuid,
       Database,
       ItemCount,
       TotalItemSize,
       TotalDeletedItemSize,
       LastLogonTime |
Export-Csv "$Out\05_MailboxStatistics.csv" -NoTypeInformation -Encoding UTF8
7. Текущие размеры архивных ящиков, если они уже есть
Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited |
Where-Object {$_.ArchiveStatus -eq "Active"} |
Get-MailboxStatistics -Archive |
Select DisplayName,
       MailboxGuid,
       Database,
       ItemCount,
       TotalItemSize,
       TotalDeletedItemSize,
       LastLogonTime |
Export-Csv "$Out\06_ArchiveStatistics.csv" -NoTypeInformation -Encoding UTF8
8. Главное: оценка писем старше 3 лет

Эта выгрузка нужна, чтобы заново получить аналоги листов MailOlderThan365d_*, только для 3 лет.

$Cutoff = (Get-Date).AddYears(-3).ToString("MM/dd/yyyy")
$Mailboxes = Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited

$Results = foreach ($mbx in $Mailboxes) {
    Write-Host "Estimate:" $mbx.PrimarySmtpAddress

    try {
        $estimate = Search-Mailbox -Identity $mbx.PrimarySmtpAddress `
            -SearchQuery "(received:<$Cutoff OR sent:<$Cutoff)" `
            -EstimateResultOnly `
            -ErrorAction Stop

        [PSCustomObject]@{
            DisplayName        = $mbx.DisplayName
            Alias              = $mbx.Alias
            PrimarySmtpAddress = $mbx.PrimarySmtpAddress
            Database           = $mbx.Database
            ArchiveStatus      = $mbx.ArchiveStatus
            ArchiveDatabase    = $mbx.ArchiveDatabase
            CutoffDate         = $Cutoff
            ResultItemsCount   = $estimate.ResultItemsCount
            ResultItemsSize    = $estimate.ResultItemsSize
            Error              = $null
        }
    }
    catch {
        [PSCustomObject]@{
            DisplayName        = $mbx.DisplayName
            Alias              = $mbx.Alias
            PrimarySmtpAddress = $mbx.PrimarySmtpAddress
            Database           = $mbx.Database
            ArchiveStatus      = $mbx.ArchiveStatus
            ArchiveDatabase    = $mbx.ArchiveDatabase
            CutoffDate         = $Cutoff
            ResultItemsCount   = $null
            ResultItemsSize    = $null
            Error              = $_.Exception.Message
        }
    }
}

$Results |
Export-Csv "$Out\07_MailOlderThan3Years_AllUsers.csv" -NoTypeInformation -Encoding UTF8

Если Search-Mailbox выдаст ошибку по правам, пришли текст ошибки. Чаще всего нужно добавить роль:

New-ManagementRoleAssignment -Role "Mailbox Import Export" -User "<твой_админский_аккаунт>"

После этого обычно нужно перелогиниться в Exchange Management Shell.

9. Суммарный объём старше 3 лет по БД

После выполнения пункта 8 выполни:

$Results |
Group-Object Database |
ForEach-Object {
    [PSCustomObject]@{
        Database = $_.Name
        Users    = $_.Count
        Items    = ($_.Group | Measure-Object ResultItemsCount -Sum).Sum
    }
} |
Export-Csv "$Out\08_ArchiveTotals_ByDB_Raw.csv" -NoTypeInformation -Encoding UTF8

Размеры в GB я потом сам посчитаю из ResultItemsSize, потому что Exchange часто отдаёт размер строкой вида 123.4 MB (129,394,000 bytes).

10. Политики архивации и retention
Get-RetentionPolicy |
Select Name, RetentionPolicyTagLinks |
Export-Csv "$Out\09_RetentionPolicies.csv" -NoTypeInformation -Encoding UTF8

Get-RetentionPolicyTag |
Select Name,
       Type,
       AgeLimitForRetention,
       RetentionAction,
       RetentionEnabled |
Export-Csv "$Out\10_RetentionPolicyTags.csv" -NoTypeInformation -Encoding UTF8
11. Ограничения, которые нужно написать вручную

Пришли отдельным текстом ответы:

1. Какой минимальный остаток свободного места должен быть на дисках?
   Например: не ниже 15%, 20%, 100 GB, 200 GB.

2. Какие диски можно использовать под новые архивные БД?

3. Какие диски можно использовать под новые рабочие БД?

4. Какие диски использовать нельзя?

5. Можно ли размещать архивную БД и новую рабочую БД на одном диске?

6. Нужно ли учитывать запас под логи?
   Рекомендую учитывать минимум 10–15%.

7. Миграция будет идти с DAG или без DAG?

8. Нужно ли учитывать место на всех копиях БД DAG или только на активной копии?

9. Есть ли ограничение по числу пользователей в одной волне миграции?

10. Нужно ли исключить Disabled-пользователей или наоборот архивировать их тоже?

11. Старше 3 лет — это только письма или все элементы: письма, календарь, задачи и т.д.?

12. Нужно ли сохранить формат старого Excel 1-в-1?
12. Собери всё в архив
Compress-Archive -Path "$Out\*" -DestinationPath "$Out.zip" -Force

Пришли мне:

$Out.zip с новыми выгрузками;
ответы на ограничения из пункта 11;
старый Excel уже есть, его буду использовать как шаблон.

После этого я смогу составить новый план в таком же стиле: лист All, лист Миграция, суммарные данные по БД и отдельные листы по пользователям/БД.

Оценка писем старше 365 дней
$Cutoff = (Get-Date).AddDays(-365).ToString("MM/dd/yyyy")
$Mailboxes = Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited

$Results = foreach ($mbx in $Mailboxes) {
    Write-Host "Estimate:" $mbx.PrimarySmtpAddress

    try {
        $estimate = Search-Mailbox -Identity $mbx.PrimarySmtpAddress `
            -SearchQuery "(received:<$Cutoff OR sent:<$Cutoff)" `
            -EstimateResultOnly `
            -ErrorAction Stop

        [PSCustomObject]@{
            DisplayName        = $mbx.DisplayName
            Alias              = $mbx.Alias
            PrimarySmtpAddress = $mbx.PrimarySmtpAddress
            Database           = $mbx.Database
            ArchiveStatus      = $mbx.ArchiveStatus
            ArchiveDatabase    = $mbx.ArchiveDatabase
            CutoffDate         = $Cutoff
            ResultItemsCount   = $estimate.ResultItemsCount
            ResultItemsSize    = $estimate.ResultItemsSize
            Error              = $null
        }
    }
    catch {
        [PSCustomObject]@{
            DisplayName        = $mbx.DisplayName
            Alias              = $mbx.Alias
            PrimarySmtpAddress = $mbx.PrimarySmtpAddress
            Database           = $mbx.Database
            ArchiveStatus      = $mbx.ArchiveStatus
            ArchiveDatabase    = $mbx.ArchiveDatabase
            CutoffDate         = $Cutoff
            ResultItemsCount   = $null
            ResultItemsSize    = $null
            Error              = $_.Exception.Message
        }
    }
}

$Results |
Export-Csv "$Out\07_MailOlderThan365d_AllUsers.csv" -NoTypeInformation -Encoding UTF8
Суммарно по БД
$Results |
Group-Object Database |
ForEach-Object {
    [PSCustomObject]@{
        Database = $_.Name
        Users    = $_.Count
        Items    = ($_.Group | Measure-Object ResultItemsCount -Sum).Sum
    }
} |
Export-Csv "$Out\08_ArchiveTotals_ByDB_Raw.csv" -NoTypeInformation -Encoding UTF8

Итого мне нужны выгрузки:

01_MailboxDatabases.csv
02_DatabaseCopyStatus.csv
03_Disks.csv
04_Mailboxes.csv
05_MailboxStatistics.csv
06_ArchiveStatistics.csv
07_MailOlderThan365d_AllUsers.csv
08_ArchiveTotals_ByDB_Raw.csv
09_RetentionPolicies.csv
10_RetentionPolicyTags.csv

Плюс текстом:

1. Минимальный остаток свободного места на дисках: %, GB или оба условия.
2. Какие диски можно использовать под архивные БД.
3. Какие диски можно использовать под новые рабочие БД.
4. Какие диски использовать нельзя.
5. Нужно ли учитывать DAG-копии.
6. Есть ли лимит пользователей/БД в одной волне миграции.
7. Нужно ли исключать какие-то БД или пользователей.