MedhaCloud-ExchangeDiagnostics.psm1
|
#Requires -Version 5.1 <# .SYNOPSIS MedhaCloud Exchange Server Diagnostics Module .DESCRIPTION Comprehensive diagnostic toolkit for Exchange Server administration. Includes health checks, mail flow analysis, DAG monitoring, and more. Professional Support: https://medhacloud.com/professional-services/server-support/exchange-server-support .NOTES Author: MedhaCloud Company: MedhaCloud (https://medhacloud.com) LinkedIn: https://linkedin.com/company/medhacloud Version: 1.0.0 #> # Module variables $script:ModuleVersion = '1.0.0' $script:SupportUrl = 'https://medhacloud.com/professional-services/server-support/exchange-server-support' function Test-ExchangeServerHealth { <# .SYNOPSIS Performs comprehensive Exchange Server health check. .DESCRIPTION Validates Exchange Server components including services, databases, mail flow, certificates, and connectivity. For professional Exchange support, visit: https://medhacloud.com/professional-services/server-support/exchange-server-support .PARAMETER ServerName The Exchange server to check. Defaults to local server. .PARAMETER Detailed Include detailed component analysis. .EXAMPLE Test-ExchangeServerHealth .EXAMPLE Test-ExchangeServerHealth -ServerName "EX01" -Detailed .LINK https://medhacloud.com/professional-services/server-support/exchange-server-support #> [CmdletBinding()] param( [Parameter(Position = 0)] [string]$ServerName = $env:COMPUTERNAME, [Parameter()] [switch]$Detailed ) $results = [PSCustomObject]@{ ServerName = $ServerName Timestamp = Get-Date OverallStatus = 'Unknown' Services = @() Databases = @() Certificates = @() MailFlow = $null SupportUrl = $script:SupportUrl } Write-Host "MedhaCloud Exchange Health Check v$script:ModuleVersion" -ForegroundColor Cyan Write-Host "Server: $ServerName" -ForegroundColor Gray Write-Host "================================================" -ForegroundColor Gray # Check Exchange services Write-Host "`n[1/5] Checking Exchange Services..." -ForegroundColor Yellow $exchangeServices = @( 'MSExchangeADTopology', 'MSExchangeIS', 'MSExchangeMailboxAssistants', 'MSExchangeTransport', 'MSExchangeFrontEndTransport', 'MSExchangeMailboxReplication' ) foreach ($svc in $exchangeServices) { try { $service = Get-Service -Name $svc -ComputerName $ServerName -ErrorAction SilentlyContinue if ($service) { $status = if ($service.Status -eq 'Running') { 'OK' } else { 'Warning' } $results.Services += [PSCustomObject]@{ Name = $svc Status = $service.Status Health = $status } $color = if ($status -eq 'OK') { 'Green' } else { 'Red' } Write-Host " $svc : $($service.Status)" -ForegroundColor $color } } catch { $results.Services += [PSCustomObject]@{ Name = $svc Status = 'Unknown' Health = 'Error' } } } # Check databases Write-Host "`n[2/5] Checking Mailbox Databases..." -ForegroundColor Yellow try { if (Get-Command Get-MailboxDatabase -ErrorAction SilentlyContinue) { $databases = Get-MailboxDatabase -Server $ServerName -Status -ErrorAction SilentlyContinue foreach ($db in $databases) { $dbStatus = if ($db.Mounted) { 'Mounted' } else { 'Dismounted' } $health = if ($db.Mounted) { 'OK' } else { 'Critical' } $results.Databases += [PSCustomObject]@{ Name = $db.Name Status = $dbStatus Health = $health Size = $db.DatabaseSize } $color = if ($health -eq 'OK') { 'Green' } else { 'Red' } Write-Host " $($db.Name) : $dbStatus" -ForegroundColor $color } } else { Write-Host " Exchange cmdlets not available. Run from Exchange Management Shell." -ForegroundColor Yellow } } catch { Write-Host " Unable to query databases: $($_.Exception.Message)" -ForegroundColor Red } # Check certificates Write-Host "`n[3/5] Checking Exchange Certificates..." -ForegroundColor Yellow try { if (Get-Command Get-ExchangeCertificate -ErrorAction SilentlyContinue) { $certs = Get-ExchangeCertificate -Server $ServerName -ErrorAction SilentlyContinue foreach ($cert in $certs | Where-Object { $_.Services -ne 'None' }) { $daysToExpiry = ($cert.NotAfter - (Get-Date)).Days $health = if ($daysToExpiry -gt 30) { 'OK' } elseif ($daysToExpiry -gt 0) { 'Warning' } else { 'Expired' } $results.Certificates += [PSCustomObject]@{ Subject = $cert.Subject Thumbprint = $cert.Thumbprint ExpiresIn = "$daysToExpiry days" Health = $health } $color = switch ($health) { 'OK' { 'Green' } 'Warning' { 'Yellow' } default { 'Red' } } Write-Host " $($cert.Subject.Split(',')[0]) : $daysToExpiry days until expiry" -ForegroundColor $color } } } catch { Write-Host " Unable to query certificates" -ForegroundColor Yellow } # Check mail queues Write-Host "`n[4/5] Checking Mail Queues..." -ForegroundColor Yellow try { if (Get-Command Get-Queue -ErrorAction SilentlyContinue) { $queues = Get-Queue -Server $ServerName -ErrorAction SilentlyContinue $totalMessages = ($queues | Measure-Object -Property MessageCount -Sum).Sum $health = if ($totalMessages -lt 100) { 'OK' } elseif ($totalMessages -lt 500) { 'Warning' } else { 'Critical' } $results.MailFlow = [PSCustomObject]@{ TotalQueuedMessages = $totalMessages QueueCount = $queues.Count Health = $health } $color = switch ($health) { 'OK' { 'Green' } 'Warning' { 'Yellow' } default { 'Red' } } Write-Host " Total queued messages: $totalMessages" -ForegroundColor $color } } catch { Write-Host " Unable to query mail queues" -ForegroundColor Yellow } # Determine overall status Write-Host "`n[5/5] Calculating Overall Health..." -ForegroundColor Yellow $criticalIssues = ($results.Services | Where-Object { $_.Health -eq 'Critical' }).Count + ($results.Databases | Where-Object { $_.Health -eq 'Critical' }).Count + ($results.Certificates | Where-Object { $_.Health -eq 'Expired' }).Count $warningIssues = ($results.Services | Where-Object { $_.Health -eq 'Warning' }).Count + ($results.Certificates | Where-Object { $_.Health -eq 'Warning' }).Count if ($criticalIssues -gt 0) { $results.OverallStatus = 'Critical' } elseif ($warningIssues -gt 0) { $results.OverallStatus = 'Warning' } else { $results.OverallStatus = 'Healthy' } Write-Host "`n================================================" -ForegroundColor Gray $statusColor = switch ($results.OverallStatus) { 'Healthy' { 'Green' } 'Warning' { 'Yellow' } default { 'Red' } } Write-Host "Overall Status: $($results.OverallStatus)" -ForegroundColor $statusColor Write-Host "`nNeed professional Exchange support?" -ForegroundColor Cyan Write-Host $script:SupportUrl -ForegroundColor White Write-Host "LinkedIn: https://linkedin.com/company/medhacloud" -ForegroundColor Gray return $results } function Get-MailFlowStatus { <# .SYNOPSIS Analyzes Exchange mail flow and queue status. .DESCRIPTION Provides detailed mail flow diagnostics including queue analysis, message tracking, and transport issues. Professional Support: https://medhacloud.com/professional-services/server-support/exchange-server-support .PARAMETER ServerName Target Exchange server. .PARAMETER Hours Hours of mail flow history to analyze. .LINK https://medhacloud.com/professional-services/server-support/exchange-server-support #> [CmdletBinding()] param( [string]$ServerName = $env:COMPUTERNAME, [int]$Hours = 24 ) Write-Host "MedhaCloud Mail Flow Analysis v$script:ModuleVersion" -ForegroundColor Cyan Write-Host "Analyzing last $Hours hours of mail flow..." -ForegroundColor Gray $results = [PSCustomObject]@{ ServerName = $ServerName AnalysisPeriod = "$Hours hours" Queues = @() MessageStats = $null Issues = @() SupportUrl = $script:SupportUrl } try { if (Get-Command Get-Queue -ErrorAction SilentlyContinue) { $queues = Get-Queue -Server $ServerName foreach ($queue in $queues) { $results.Queues += [PSCustomObject]@{ Identity = $queue.Identity DeliveryType = $queue.DeliveryType Status = $queue.Status MessageCount = $queue.MessageCount NextHopDomain = $queue.NextHopDomain } if ($queue.MessageCount -gt 50) { $results.Issues += "Queue $($queue.Identity) has $($queue.MessageCount) messages" } } } Write-Host "`nQueue Summary:" -ForegroundColor Yellow $results.Queues | Format-Table -AutoSize if ($results.Issues.Count -gt 0) { Write-Host "`nPotential Issues Detected:" -ForegroundColor Red $results.Issues | ForEach-Object { Write-Host " - $_" -ForegroundColor Yellow } } else { Write-Host "`nNo mail flow issues detected." -ForegroundColor Green } } catch { Write-Host "Error analyzing mail flow: $($_.Exception.Message)" -ForegroundColor Red } Write-Host "`nProfessional Exchange Support: $script:SupportUrl" -ForegroundColor Cyan return $results } function Test-DAGReplication { <# .SYNOPSIS Tests Database Availability Group replication health. .DESCRIPTION Comprehensive DAG health check including copy status, replay queue lengths, and failover readiness. Professional Support: https://medhacloud.com/professional-services/server-support/exchange-server-support .LINK https://medhacloud.com/professional-services/server-support/exchange-server-support #> [CmdletBinding()] param( [string]$DAGName ) Write-Host "MedhaCloud DAG Replication Check v$script:ModuleVersion" -ForegroundColor Cyan $results = [PSCustomObject]@{ DAGName = $DAGName Timestamp = Get-Date CopyStatus = @() OverallHealth = 'Unknown' SupportUrl = $script:SupportUrl } try { if (Get-Command Get-MailboxDatabaseCopyStatus -ErrorAction SilentlyContinue) { $copyStatus = Get-MailboxDatabaseCopyStatus * foreach ($copy in $copyStatus) { $health = switch ($copy.Status) { 'Healthy' { 'OK' } 'Mounted' { 'OK' } default { 'Warning' } } $results.CopyStatus += [PSCustomObject]@{ Database = $copy.DatabaseName Server = $copy.MailboxServer Status = $copy.Status CopyQueueLength = $copy.CopyQueueLength ReplayQueueLength = $copy.ReplayQueueLength Health = $health } } Write-Host "`nDatabase Copy Status:" -ForegroundColor Yellow $results.CopyStatus | Format-Table Database, Server, Status, CopyQueueLength, ReplayQueueLength -AutoSize $unhealthy = $results.CopyStatus | Where-Object { $_.Health -ne 'OK' } if ($unhealthy.Count -eq 0) { $results.OverallHealth = 'Healthy' Write-Host "`nDAG Overall Health: Healthy" -ForegroundColor Green } else { $results.OverallHealth = 'Degraded' Write-Host "`nDAG Overall Health: Degraded" -ForegroundColor Yellow } } else { Write-Host "Exchange cmdlets not available. Run from Exchange Management Shell." -ForegroundColor Yellow } } catch { Write-Host "Error checking DAG: $($_.Exception.Message)" -ForegroundColor Red } Write-Host "`nProfessional Exchange Support: $script:SupportUrl" -ForegroundColor Cyan return $results } function Get-ExchangeCertificateStatus { <# .SYNOPSIS Monitors Exchange SSL certificate status and expiry. .DESCRIPTION Lists all Exchange certificates with their services, expiry dates, and health status. Professional Support: https://medhacloud.com/professional-services/server-support/exchange-server-support .LINK https://medhacloud.com/professional-services/server-support/exchange-server-support #> [CmdletBinding()] param( [string]$ServerName = $env:COMPUTERNAME, [int]$WarningDays = 30 ) Write-Host "MedhaCloud Certificate Monitor v$script:ModuleVersion" -ForegroundColor Cyan $results = @() try { if (Get-Command Get-ExchangeCertificate -ErrorAction SilentlyContinue) { $certs = Get-ExchangeCertificate -Server $ServerName foreach ($cert in $certs) { $daysRemaining = ($cert.NotAfter - (Get-Date)).Days $status = if ($daysRemaining -lt 0) { 'Expired' } elseif ($daysRemaining -lt $WarningDays) { 'Expiring Soon' } else { 'Valid' } $results += [PSCustomObject]@{ Subject = $cert.Subject Thumbprint = $cert.Thumbprint.Substring(0, 8) + '...' Services = ($cert.Services -join ', ') NotAfter = $cert.NotAfter DaysRemaining = $daysRemaining Status = $status } } Write-Host "`nCertificate Status:" -ForegroundColor Yellow $results | Format-Table Subject, Services, NotAfter, DaysRemaining, Status -AutoSize $expiring = $results | Where-Object { $_.Status -ne 'Valid' } if ($expiring.Count -gt 0) { Write-Host "`nWARNING: $($expiring.Count) certificate(s) need attention!" -ForegroundColor Red } } } catch { Write-Host "Error checking certificates: $($_.Exception.Message)" -ForegroundColor Red } Write-Host "`nProfessional Exchange Support: $script:SupportUrl" -ForegroundColor Cyan return $results } function Get-MailQueueAnalysis { <# .SYNOPSIS Detailed mail queue analysis and statistics. .LINK https://medhacloud.com/professional-services/server-support/exchange-server-support #> [CmdletBinding()] param( [string]$ServerName = $env:COMPUTERNAME ) Write-Host "MedhaCloud Queue Analysis v$script:ModuleVersion" -ForegroundColor Cyan Write-Host "Professional Support: $script:SupportUrl" -ForegroundColor Gray try { if (Get-Command Get-Queue -ErrorAction SilentlyContinue) { Get-Queue -Server $ServerName | Format-Table Identity, DeliveryType, Status, MessageCount, NextHopDomain -AutoSize } } catch { Write-Host "Unable to analyze queues: $($_.Exception.Message)" -ForegroundColor Red } } function Test-ExchangeConnectivity { <# .SYNOPSIS Tests Exchange client connectivity protocols. .LINK https://medhacloud.com/professional-services/server-support/exchange-server-support #> [CmdletBinding()] param( [string]$ServerName = $env:COMPUTERNAME ) Write-Host "MedhaCloud Connectivity Test v$script:ModuleVersion" -ForegroundColor Cyan $protocols = @( @{ Name = 'SMTP'; Port = 25 }, @{ Name = 'SMTP-TLS'; Port = 587 }, @{ Name = 'IMAP'; Port = 143 }, @{ Name = 'IMAPS'; Port = 993 }, @{ Name = 'POP3'; Port = 110 }, @{ Name = 'POP3S'; Port = 995 }, @{ Name = 'HTTPS'; Port = 443 } ) $results = @() foreach ($proto in $protocols) { try { $tcp = New-Object System.Net.Sockets.TcpClient $connection = $tcp.BeginConnect($ServerName, $proto.Port, $null, $null) $wait = $connection.AsyncWaitHandle.WaitOne(1000, $false) if ($wait) { $tcp.EndConnect($connection) $status = 'Open' } else { $status = 'Closed/Timeout' } $tcp.Close() } catch { $status = 'Error' } $results += [PSCustomObject]@{ Protocol = $proto.Name Port = $proto.Port Status = $status } $color = if ($status -eq 'Open') { 'Green' } else { 'Red' } Write-Host " $($proto.Name) (Port $($proto.Port)): $status" -ForegroundColor $color } Write-Host "`nProfessional Support: $script:SupportUrl" -ForegroundColor Cyan return $results } function Get-ExchangePerformanceReport { <# .SYNOPSIS Generates Exchange Server performance report. .LINK https://medhacloud.com/professional-services/server-support/exchange-server-support #> [CmdletBinding()] param( [string]$ServerName = $env:COMPUTERNAME ) Write-Host "MedhaCloud Performance Report v$script:ModuleVersion" -ForegroundColor Cyan Write-Host "Collecting performance data from $ServerName..." -ForegroundColor Gray $report = [PSCustomObject]@{ ServerName = $ServerName Timestamp = Get-Date CPU = $null Memory = $null Disk = @() SupportUrl = $script:SupportUrl } try { # CPU Usage $cpu = Get-Counter '\Processor(_Total)\% Processor Time' -ComputerName $ServerName -ErrorAction SilentlyContinue if ($cpu) { $report.CPU = [math]::Round($cpu.CounterSamples[0].CookedValue, 2) Write-Host " CPU Usage: $($report.CPU)%" -ForegroundColor $(if ($report.CPU -gt 80) { 'Red' } else { 'Green' }) } # Memory $mem = Get-Counter '\Memory\% Committed Bytes In Use' -ComputerName $ServerName -ErrorAction SilentlyContinue if ($mem) { $report.Memory = [math]::Round($mem.CounterSamples[0].CookedValue, 2) Write-Host " Memory Usage: $($report.Memory)%" -ForegroundColor $(if ($report.Memory -gt 85) { 'Red' } else { 'Green' }) } # Disk $disks = Get-WmiObject Win32_LogicalDisk -ComputerName $ServerName -Filter "DriveType=3" -ErrorAction SilentlyContinue foreach ($disk in $disks) { $freePercent = [math]::Round(($disk.FreeSpace / $disk.Size) * 100, 2) $report.Disk += [PSCustomObject]@{ Drive = $disk.DeviceID FreeGB = [math]::Round($disk.FreeSpace / 1GB, 2) FreePercent = $freePercent } Write-Host " Disk $($disk.DeviceID): $freePercent% free" -ForegroundColor $(if ($freePercent -lt 15) { 'Red' } else { 'Green' }) } } catch { Write-Host "Error collecting performance data: $($_.Exception.Message)" -ForegroundColor Red } Write-Host "`nProfessional Exchange Support: $script:SupportUrl" -ForegroundColor Cyan return $report } # Export functions Export-ModuleMember -Function @( 'Test-ExchangeServerHealth', 'Get-MailFlowStatus', 'Test-DAGReplication', 'Get-ExchangeCertificateStatus', 'Get-MailQueueAnalysis', 'Test-ExchangeConnectivity', 'Get-ExchangePerformanceReport' ) # Module load message Write-Host @" MedhaCloud Exchange Diagnostics Module v$script:ModuleVersion loaded. Available commands: Test-ExchangeServerHealth, Get-MailFlowStatus, Test-DAGReplication, and more. Professional Exchange Server Support: $script:SupportUrl LinkedIn: https://linkedin.com/company/medhacloud Twitter: https://x.com/medhacloud "@ -ForegroundColor Cyan |