<# .SYNOPSIS Quick Exchange server health check with aggregated results .DESCRIPTION Runs multiple Exchange health cmdlets and aggregates results into a single report. Includes service health, replication health, MAPI connectivity, and database mount status. .PARAMETER OutputFolder Destination folder for reports. Default: .\ExchangeHealth- .PARAMETER IncludeMailflow Test mail flow using Test-Mailflow cmdlet (default: $false, can be slow) .PARAMETER ServerName Specific server to test (default: local server) .NOTES ⚠️ AI-GENERATED SCRIPT - UNTESTED This script was generated by Claude AI and has not been tested in production. Review and test thoroughly in a non-production environment before use. - Run in Exchange Management Shell - Some tests require specific server roles - Tests are non-intrusive (read-only) .EXAMPLE .\Test-ExchangeHealth.ps1 .EXAMPLE .\Test-ExchangeHealth.ps1 -ServerName "EXCH01" -IncludeMailflow $true #> [CmdletBinding()] param( [string]$OutputFolder = (Join-Path -Path (Get-Location) -ChildPath ("ExchangeHealth-" + (Get-Date -Format "yyyyMMdd-HHmm"))), [bool]$IncludeMailflow = $false, [string]$ServerName = $env:COMPUTERNAME ) function NowTag { (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") } Write-Host "[$(NowTag)] ⚠️ AI-GENERATED SCRIPT - UNTESTED" -ForegroundColor Yellow Write-Host "[$(NowTag)] Starting Exchange health check on $ServerName..." -ForegroundColor Green # Create output folder New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null $allResults = @() $criticalIssues = @() $warnings = @() # Test 1: Service Health Write-Host "[$(NowTag)] Testing service health..." try { $serviceHealth = Test-ServiceHealth -Server $ServerName -ErrorAction SilentlyContinue if ($serviceHealth) { foreach ($svc in $serviceHealth) { $result = [PSCustomObject]@{ TestCategory = "ServiceHealth" TestName = $svc.Role Server = $ServerName Status = if ($svc.RequiredServicesRunning) { "PASS" } else { "FAIL" } Details = "Required services: $($svc.RequiredServicesRunning)" } $allResults += $result if (-not $svc.RequiredServicesRunning) { $criticalIssues += "Service Health FAILED for role: $($svc.Role)" } } Write-Host " Service Health: COMPLETED" -ForegroundColor Green } else { Write-Host " Service Health: No results (cmdlet may not be available)" -ForegroundColor Yellow } } catch { Write-Host " Service Health: ERROR - $($_.Exception.Message)" -ForegroundColor Red $allResults += [PSCustomObject]@{ TestCategory = "ServiceHealth" TestName = "Test-ServiceHealth" Server = $ServerName Status = "ERROR" Details = $_.Exception.Message } } # Test 2: Replication Health (DAG servers only) Write-Host "[$(NowTag)] Testing replication health..." try { $replHealth = Test-ReplicationHealth -Server $ServerName -ErrorAction SilentlyContinue if ($replHealth) { foreach ($test in $replHealth) { $status = if ($test.Result -eq "Passed") { "PASS" } elseif ($test.Result -eq "Failed") { "FAIL" } else { "WARNING" } $result = [PSCustomObject]@{ TestCategory = "ReplicationHealth" TestName = $test.Check Server = $ServerName Status = $status Details = $test.Error } $allResults += $result if ($status -eq "FAIL") { $criticalIssues += "Replication Health FAILED: $($test.Check) - $($test.Error)" } elseif ($status -eq "WARNING") { $warnings += "Replication Health WARNING: $($test.Check) - $($test.Error)" } } Write-Host " Replication Health: COMPLETED" -ForegroundColor Green } else { Write-Host " Replication Health: Not applicable (not a DAG member)" -ForegroundColor Yellow } } catch { Write-Host " Replication Health: ERROR or not applicable - $($_.Exception.Message)" -ForegroundColor Yellow $allResults += [PSCustomObject]@{ TestCategory = "ReplicationHealth" TestName = "Test-ReplicationHealth" Server = $ServerName Status = "N/A" Details = "Not applicable or error: $($_.Exception.Message)" } } # Test 3: MAPI Connectivity Write-Host "[$(NowTag)] Testing MAPI connectivity..." try { $databases = Get-MailboxDatabase -Server $ServerName -Status -ErrorAction SilentlyContinue foreach ($db in $databases) { if ($db.Mounted) { try { $mapiTest = Test-MapiConnectivity -Database $db.Name -ErrorAction Stop $status = if ($mapiTest.Result -eq "Success") { "PASS" } else { "FAIL" } $result = [PSCustomObject]@{ TestCategory = "MapiConnectivity" TestName = "Database: $($db.Name)" Server = $ServerName Status = $status Details = "Latency: $($mapiTest.Latency.TotalMilliseconds) ms" } $allResults += $result if ($status -eq "FAIL") { $criticalIssues += "MAPI Connectivity FAILED for database: $($db.Name)" } } catch { $result = [PSCustomObject]@{ TestCategory = "MapiConnectivity" TestName = "Database: $($db.Name)" Server = $ServerName Status = "ERROR" Details = $_.Exception.Message } $allResults += $result $warnings += "MAPI test error for $($db.Name): $($_.Exception.Message)" } } } Write-Host " MAPI Connectivity: COMPLETED" -ForegroundColor Green } catch { Write-Host " MAPI Connectivity: ERROR - $($_.Exception.Message)" -ForegroundColor Red } # Test 4: Database Mount Status Write-Host "[$(NowTag)] Checking database mount status..." try { $databases = Get-MailboxDatabase -Server $ServerName -Status -ErrorAction SilentlyContinue foreach ($db in $databases) { $status = if ($db.Mounted) { "PASS" } else { "FAIL" } $result = [PSCustomObject]@{ TestCategory = "DatabaseMount" TestName = "Database: $($db.Name)" Server = $ServerName Status = $status Details = "Mounted: $($db.Mounted)" } $allResults += $result if (-not $db.Mounted) { $criticalIssues += "Database DISMOUNTED: $($db.Name)" } } Write-Host " Database Mount Status: COMPLETED" -ForegroundColor Green } catch { Write-Host " Database Mount Status: ERROR - $($_.Exception.Message)" -ForegroundColor Red } # Test 5: Mail Flow (optional) if ($IncludeMailflow) { Write-Host "[$(NowTag)] Testing mail flow (this may take a minute)..." try { $mailflowTest = Test-Mailflow -TargetMailboxServer $ServerName -ErrorAction Stop $status = if ($mailflowTest.TestMailflowResult -eq "Success") { "PASS" } else { "FAIL" } $result = [PSCustomObject]@{ TestCategory = "Mailflow" TestName = "Test-Mailflow" Server = $ServerName Status = $status Details = "Result: $($mailflowTest.TestMailflowResult), Latency: $($mailflowTest.MessageLatencyTime.TotalMilliseconds) ms" } $allResults += $result if ($status -eq "FAIL") { $criticalIssues += "Mail Flow test FAILED" } Write-Host " Mail Flow: COMPLETED" -ForegroundColor Green } catch { Write-Host " Mail Flow: ERROR - $($_.Exception.Message)" -ForegroundColor Red $allResults += [PSCustomObject]@{ TestCategory = "Mailflow" TestName = "Test-Mailflow" Server = $ServerName Status = "ERROR" Details = $_.Exception.Message } } } # Export results Write-Host "[$(NowTag)] Exporting results..." $csvFile = Join-Path $OutputFolder "Health-Check-Results.csv" $allResults | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $csvFile Write-Host "[$(NowTag)] Results exported: $csvFile" -ForegroundColor Green # Summary $passCount = ($allResults | Where-Object Status -eq "PASS").Count $failCount = ($allResults | Where-Object Status -eq "FAIL").Count $errorCount = ($allResults | Where-Object Status -eq "ERROR").Count $totalTests = $allResults.Count $summaryFile = Join-Path $OutputFolder "Health-Check-Summary.txt" $summary = @" Exchange Health Check Summary Server: $ServerName Generated: $(Get-Date) TEST RESULTS: Total Tests: $totalTests Passed: $passCount Failed: $failCount Errors: $errorCount Overall Status: $(if ($failCount -eq 0 -and $errorCount -eq 0) { "HEALTHY" } else { "ISSUES DETECTED" }) $(if ($criticalIssues.Count -gt 0) { "CRITICAL ISSUES: $($criticalIssues | ForEach-Object { " - $_" } | Out-String) "} else { "" }) $(if ($warnings.Count -gt 0) { "WARNINGS: $($warnings | ForEach-Object { " - $_" } | Out-String) "} else { "" }) DETAILED RESULTS: $($allResults | ForEach-Object { " [$($_.Status)] $($_.TestCategory) - $($_.TestName): $($_.Details)" } | Out-String) "@ $summary | Out-File -FilePath $summaryFile -Encoding UTF8 Write-Host "[$(NowTag)] Summary: $summaryFile" -ForegroundColor Green # Console output Write-Host "`nHEALTH CHECK SUMMARY:" -ForegroundColor Cyan Write-Host " Total Tests: $totalTests" Write-Host " Passed: $passCount" -ForegroundColor Green Write-Host " Failed: $failCount" -ForegroundColor $(if ($failCount -gt 0) { "Red" } else { "Green" }) Write-Host " Errors: $errorCount" -ForegroundColor $(if ($errorCount -gt 0) { "Red" } else { "Green" }) if ($criticalIssues.Count -gt 0) { Write-Host "`nCRITICAL ISSUES DETECTED:" -ForegroundColor Red $criticalIssues | ForEach-Object { Write-Host " - $_" -ForegroundColor Red } } if ($warnings.Count -gt 0) { Write-Host "`nWARNINGS:" -ForegroundColor Yellow $warnings | ForEach-Object { Write-Host " - $_" -ForegroundColor Yellow } } Write-Host "`n[$(NowTag)] Health check complete! Output folder: $OutputFolder" # Exit code if ($failCount -gt 0 -or $errorCount -gt 0) { exit 1 } else { exit 0 }