Public/Invoke-MigrationAssessment.ps1
|
function Invoke-MigrationAssessment { <# .SYNOPSIS Runs a complete Exchange-to-M365 migration pre-assessment. .DESCRIPTION Gathers all data needed to plan an Exchange migration: 1. Mailbox inventory with sizes and types 2. Distribution group audit 3. Mail flow (transport) rule export 4. Public folder analysis Generates an HTML report with migration readiness summary, estimated migration time, and potential blockers. .PARAMETER OutputPath Directory for the HTML report and CSV exports. Defaults to .\Reports. .PARAMETER ExportCsv Also export detailed data as CSV files alongside the HTML report. .PARAMETER SkipPublicFolders Skip the public folder analysis (useful if no public folders exist). .EXAMPLE Invoke-MigrationAssessment .EXAMPLE Invoke-MigrationAssessment -ExportCsv -OutputPath "\\server\migration-planning" .NOTES Run from the Exchange Management Shell or with Exchange Online Management module. #> [CmdletBinding()] param( [string]$OutputPath = '.\Reports', [switch]$ExportCsv, [switch]$SkipPublicFolders, [string]$LogPath = '.\Logs' ) begin { foreach ($dir in @($OutputPath, $LogPath)) { if (-not (Test-Path $dir)) { New-Item -Path $dir -ItemType Directory -Force | Out-Null } } $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss' Start-Transcript -Path (Join-Path $LogPath "MigrationAssessment-$timestamp.log") -Append $assessment = @{} } process { # 1. Mailbox Inventory Write-Verbose "Gathering mailbox inventory..." $assessment['Mailboxes'] = @(Get-MailboxInventory) # 2. Distribution Groups Write-Verbose "Auditing distribution groups..." $assessment['DistGroups'] = @(Get-DistributionGroupAudit) # 3. Mail Flow Rules Write-Verbose "Exporting mail flow rules..." $assessment['MailFlowRules'] = @(Get-MailFlowRuleExport) # 4. Public Folders if (-not $SkipPublicFolders) { Write-Verbose "Analyzing public folders..." $assessment['PublicFolders'] = @(Get-PublicFolderAnalysis) } # Export CSVs if requested if ($ExportCsv) { $assessment['Mailboxes'] | Export-Csv (Join-Path $OutputPath "Mailboxes-$timestamp.csv") -NoTypeInformation $assessment['DistGroups'] | Export-Csv (Join-Path $OutputPath "DistGroups-$timestamp.csv") -NoTypeInformation $assessment['MailFlowRules'] | Export-Csv (Join-Path $OutputPath "MailFlowRules-$timestamp.csv") -NoTypeInformation if ($assessment['PublicFolders']) { $assessment['PublicFolders'] | Export-Csv (Join-Path $OutputPath "PublicFolders-$timestamp.csv") -NoTypeInformation } Write-Verbose "CSV files exported to $OutputPath" } # Generate HTML $htmlFile = Join-Path $OutputPath "MigrationAssessment-$timestamp.html" $html = _New-MigrationAssessmentHtml -Assessment $assessment $html | Out-File -FilePath $htmlFile -Encoding UTF8 Write-Verbose "Report saved: $htmlFile" # Summary calculations $totalMailboxes = $assessment['Mailboxes'].Count $totalSizeGB = ($assessment['Mailboxes'] | Measure-Object -Property SizeGB -Sum).Sum $largeMailboxes = @($assessment['Mailboxes'] | Where-Object { $_.SizeGB -gt 50 }).Count [PSCustomObject]@{ AssessmentDate = Get-Date -Format 'yyyy-MM-dd HH:mm' TotalMailboxes = $totalMailboxes TotalSizeGB = [math]::Round($totalSizeGB, 1) LargeMailboxes = $largeMailboxes DistributionGroups = $assessment['DistGroups'].Count MailFlowRules = $assessment['MailFlowRules'].Count PublicFolders = if ($assessment['PublicFolders']) { $assessment['PublicFolders'].Count } else { 'Skipped' } ReportPath = $htmlFile } } end { Stop-Transcript } } |