Files
PowerShell-scripts/Misc/Test-ExchangeHealth.ps1
Martien de Kleijn 62134801aa Add 12 AI-generated PowerShell scripts with documentation
⚠️ IMPORTANT: These scripts are AI-GENERATED and UNTESTED

Exchange Scripts (5):
- Get-MailboxPermissions.ps1: Audit delegate access permissions
- Get-InactiveMailboxes.ps1: Identify stale mailboxes
- Compare-MailboxDatabases.ps1: Database health comparison
- Export-DistributionGroups.ps1: Distribution group inventory
- Get-MailflowStats.ps1: Transport log analysis

Active Directory Scripts (3):
- Get-ADUserLastLogon.ps1: True LastLogon across all DCs
- Export-OUStructure.ps1: OU hierarchy with GPO links
- Compare-ADGroupMemberships.ps1: Compare user group memberships

System Maintenance Scripts (4):
- Get-ServerInventory.ps1: Hardware/software inventory report
- Monitor-DiskSpace.ps1: Disk space monitoring with alerts
- Backup-ExchangeCertificates.ps1: Certificate backup to PFX
- Test-ExchangeHealth.ps1: Aggregated Exchange health checks

Documentation:
- Updated CLAUDE.md with AI-generated scripts section
- Added AI-GENERATED-SCRIPTS.md with warnings and testing guide

All scripts include prominent warnings and follow established patterns
from existing scripts. Require thorough testing before production use.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-15 10:52:44 +02:00

291 lines
10 KiB
PowerShell

<#
.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-<date>
.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
}