Exchange Server, Skype gibi ürünler firmalarımızda en önemli sunucular sınıfında yer almaktadır. Bu ürünlerin yedeklenme süreçleri kritik bir öneme sahiptir, kullandığımız yedekleme yazılımları düzenli kontrol edilmeli ve raporlar günlük incelenmelidir.
Exchange Server için circular log ve transaction log yapısını anlamak için aşağıdaki makalemi inceleyebilirsiniz.
Microsoft Exchange Server 2019 ortamlarında yedekleme durumu ve sistem sağlığı takibi, kurumsal süreklilik açısından kritik öneme sahiptir. Bu yazıda, daha önce yayımladığım Exchange Server Backup V1 ve Exchange Server Backup Report v2 sürümlerine ek olarak geliştirdiğim Exchange Server 2019 Backup & Health Report Script v3 sürümünü detaylı şekilde tanıtacağım..
Yeni sürümde, responsive (mobil uyumlu) HTML rapor, aktif/pasif sunucu ayrımı, disk alanı analizleri ve daha fazlası sizleri bekliyor.
Exchange Server Backup Report;
- https://cengizyilmaz.net/exchange-server-backup-report-powershell/
- https://cengizyilmaz.net/exchange-server-backup-report-v2-0/
İçindekiler
Exchange Server Backup ve DB Healthy Script V3.0
Exchange Server Backup Report v3.0 Yeni Özellikler
Exchange Server Backup Report Mobil Uyumlu HTML Raporu
- Her veritabanı kopyası için DiskTotalSpace, DiskFreeSpace ve DiskFreeSpacePercent bilgileri toplanır.
- Eğer serbest disk alanı oranı
%10
ve altına düşerse, ilgili satır kırmızı renkle vurgulanır.
- Minimum boş alan yüzdesi, “en riskli” kopya analizine olanak tanır.
Exchange Server Backup Report Disk Alanı ve Sağlık Analizi
- Her veritabanı kopyası için DiskTotalSpace, DiskFreeSpace ve DiskFreeSpacePercent bilgileri toplanır.
- Eğer serbest disk alanı oranı
%10
ve altına düşerse, ilgili satır kırmızı renkle vurgulanır. - Minimum boş alan yüzdesi, “en riskli” kopya analizine olanak tanır.
Exchange Server Backup Report Server-DAG Detayı (A/P Ayrımı)
- Aktif sunucular
A:
etiketiyle, pasiflerP:
etiketiyle net bir şekilde ayrılmıştır. - Bu sayede DAG içi durumlar çok daha anlaşılır hale gelmiştir.
- DAG adı da ayrı bir bölüm olarak eklenmiştir.
Exchange Server Backup Report Backup Durumu Sıralama
- Hiç yedek alınmamış, yedekleme süreci devam eden ve tamamlanmış yedeklemeler ayrı sıralarda gösterilir.
- Öncelik sırasına göre listelenme sayesinde, acil müdahale gerektiren veritabanları ön plana çıkar.
Exchange Server Backup Report Mail Gönderim ve Çoklu Alıcı Desteği
- SMTP kimlik doğrulaması ve TLS desteğiyle güvenli mail gönderimi.
To
alanında;
ile ayrılmış birden fazla mail adresine destek.
Exchange Server Backup Report Kurulum ve Kullanımı
Script dosyasını aşağıdaki bağlantıdan indirin:
- https://github.com/cengizyilmaz1/ExchangeServerBackupReport/blob/main/ExchangeServerBackupReport.ps1
C:\Backup Report
dizinine scripti yerleştirin ve ilk çalıştırmada gerekli SMTP bilgilerinizi girin.
Otomatik olarak bir HTML rapor oluşturulacak ve belirttiğiniz e-posta adreslerine gönderilecektir.
Not: Script içindeki credentials.backup
dosyası, SMTP kimlik bilgilerinizi şifreli olarak saklar.
Exchange Server Backup Report Kod Yapısı ve Açıklamaları
Exchange Server Backup Report Yapılandırma ve Değişkenler
$Config = @{
From = "[email protected]"
To = "[email protected];[email protected]"
...
FreeSpaceThreshold = 10
}
- SMTP, e-posta adresleri ve rapor yolu gibi ayarlar bu bölümde tanımlanır.
FreeSpaceThreshold
, disk alanı %10 altına düşerse alarm vermek için kullanılır.
Exchange Server Backup Report Gelişmiş ProgressBar Fonksiyonu
function Modern-WriteProgress {
...
Write-Progress -Activity $Activity -PercentComplete $PercentComplete -Status $Status
}
- Scriptin her aşamasında görsel ilerleme göstermek için kullanılır.
Exchange Server Backup Report Exchange Ortamına Erişim
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn
- Exchange komutlarının kullanılabilmesi için gerekli Snap-In yüklüyor.
- Eğer hali hazırda yüklü değilse sessizce devam eder.
Exchange Server Backup Report Veritabanı Bilgilerinin Toplanması
$mailboxDatabases = Get-MailboxDatabase -Status
$dbCopies = Get-MailboxDatabaseCopyStatus -Identity "$dbName\*"
- Tüm veritabanları ve bunlara ait aktif/pasif kopyalar çekilir.
CopyStatus
sayesinde disk bilgilerine de ulaşılır.
Exchange Server Backup Report Aktif ve Pasif Sunucu Etiketlemesi (A/P)
$activeLabel = "A: $activeServer"
$passiveLabel = "P: server1, server2"
- Her veritabanı için hangi sunucunun aktif (A) hangisinin pasif (P) olduğunu ayırır.
- DAG ismi de eklenir:
| DAG: DAG01
Exchange Server Backup Report Sağlık Durumu Analizi
switch ($status) {
"Failed" { ... }
"Suspended" { ... }
}
- Her kopyanın durumu analiz edilir.
CopyQueueLength
yüksekse ayrıca “Warning” etiketi verilir.
Exchange Server Backup Report Yedekleme Durumu Değerlendirmesi
if ($db.BackupInProgress) { ... }
elseif ($db.LastFullBackup -gt $Config.BackupThreshold) { ... }
Full
,Incremental
veyaNone
durumları tespit edilir.- Yedekleme yapılmamış olanlar
None
olarak listelenir.
Exchange Server Backup Report Disk Alanı Bilgisi ve Alarm
$copy.DiskTotalSpace, $copy.DiskFreeSpace, $copy.DiskFreeSpacePercent
- Aktif/pasif tüm disklerin boş alanı hesaplanır.
- Eğer boş alan azsa, HTML içinde kırmızı olarak işaretlenir (
lowDisk
CSS sınıfı).
Exchange Server Backup Report HTML Raporun Oluşturulması
$HTMLReport = @"
<html>
<head>...</head>
<body>
<table>...</table>
</body>
</html>
"@
- Rapor dinamik olarak PowerShell ile HTML biçiminde hazırlanır.
- CSS sınıfları ile her hücre duruma göre renklendirilir (örneğin
.fail
,.success
).
Exchange Server Backup Report Mail Gönderimi
Send-MailMessage @MessageParameters
Hazırlanan rapor, SMTP sunucusu üzerinden tanımlı adreslere gönderilir.
Çoklu e-posta desteği To
alanında ;
ayracıyla yapılır.
Exchange Server Backup Report Kod
<#
Exchange Server 2019 Backup & Health Report Script (Final Revised)
-------------------------------------------------------------
Description:
This script collects Exchange Server mailbox database backup statuses,
evaluates key health details for each database, and builds a modern, responsive
HTML report. The report includes backup status/time information, detailed "DB Status",
and a Server-DAG section that explicitly separates the Active and Passive server names.
In the Server-DAG section, active servers are shown with an "A:" label and passive
servers with a "P:" label. Disk details (total, used, free in GB and free percentage)
are obtained from Get-MailboxDatabaseCopyStatus properties: DiskTotalSpace, DiskFreeSpace,
DiskFreeSpacePercent, and DatabaseVolumeMountPoint. If the disk free percentage is less than
or equal to the defined threshold, the disk info is highlighted.
The final table is sorted as follows:
1. Databases with no backup ("None") first,
2. then "In Progress",
3. then backed up databases.
Within each group, the results are sorted by ActiveServer then by database Name.
The HTML report is responsive (includes viewport meta tag) for mobile devices.
The TO email field supports multiple addresses separated by semicolons.
Service status checks have been removed.
Author: Cengiz YILMAZ
Date: 4/15/2025
Title: Microsoft MVP - MCT
WebSite: https://cengizyilmaz.net
#>
###############################################
# Function: Modern-WriteProgress
# A wrapper for Write-Progress to display progress updates.
###############################################
function Modern-WriteProgress {
param(
[Parameter(Mandatory = $true)]
[string]$Activity,
[Parameter(Mandatory = $true)]
[int]$PercentComplete,
[string]$Status = ""
)
Write-Progress -Activity $Activity -PercentComplete $PercentComplete -Status $Status
}
###############################################
# Commit: Configuration and Central Variables
###############################################
$Config = @{
# Email Settings
From = "[email protected]"
To = "[email protected];[email protected]"
SMTPServer = "mail.fixcloud.com.tr"
Port = 587
Priority = "High"
Subject = "Exchange Server Backup & Health Report"
CredentialFile = "C:\Backup Report\credentials.backup"
# Time Thresholds
BackupThreshold = (Get-Date).AddHours(-24)
CopyQueueLengthThreshold = 5
# Free disk space threshold (in percent)
FreeSpaceThreshold = 10
# Backup Report Directory
BackupReportDir = "C:\Backup Report"
# CSS Color Classes for HTML Report – used as table cell background classes.
CSSClasses = @{
InProgress = "inprogress"
Success = "success"
Fail = "fail"
Mounted = "mounted"
Mounting = "mounting"
Dismounted = "dismounted"
Dismounting = "dismounting"
Healthy = "healthy"
Failed = "failed"
Suspended = "suspended"
Seeding = "seeding"
Initializing = "initializing"
Resynchronizing = "resynchronizing"
LowDisk = "lowDisk"
Default = "default"
}
}
###############################################
# Commit: Load Exchange Snap-In and Setup Environment
###############################################
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn -ErrorAction SilentlyContinue
if (!(Test-Path $Config.BackupReportDir)) {
New-Item -ItemType Directory -Path $Config.BackupReportDir | Out-Null
}
###############################################
# Commit: Credential Check and Save
###############################################
if (!(Test-Path $Config.CredentialFile)) {
Get-Credential -Message "Please verify the credentials for account $($Config.From)" | Export-Clixml -Path $Config.CredentialFile
}
$Credential = Import-Clixml -Path $Config.CredentialFile
###############################################
# Commit: Fetch DAG, Mailbox Database and Health Information with Progress
###############################################
Modern-WriteProgress -Activity "Fetching Mailbox Databases" -PercentComplete 0 -Status "Initializing..."
$allDAGs = Get-DatabaseAvailabilityGroup
$mailboxDatabases = Get-MailboxDatabase -Status
$totalDBs = $mailboxDatabases.Count
$Databases = @()
$currentDBIndex = 0
foreach ($db in $mailboxDatabases) {
$currentDBIndex++
$percentComplete = [math]::Round(($currentDBIndex / $totalDBs * 100), 0)
Modern-WriteProgress -Activity "Processing Mailbox Databases" -PercentComplete $percentComplete -Status "Processing database: $($db.Name)"
$dbName = $db.Name
$activeServer = $db.Server
# Retrieve all copy statuses for the database (active and passive copies)
$dbCopies = Get-MailboxDatabaseCopyStatus -Identity "$dbName\*" -ErrorAction SilentlyContinue
###############################################
# Server-DAG:
# Build server list by splitting the Identity property (format: "DatabaseName\ServerName").
# Separate active and passive servers. Active servers are listed first.
###############################################
$allServers = ($dbCopies | ForEach-Object { ($_."Identity" -split '\\')[1] } | Sort-Object -Unique)
$activeServers = $allServers | Where-Object { $_ -eq $activeServer }
$passiveServers = $allServers | Where-Object { $_ -ne $activeServer } | Sort-Object
$activeLabel = if ($activeServers) { "A: " + ($activeServers -join ", ") } else { "A: $activeServer" }
$passiveLabel = if ($passiveServers) { "P: " + ($passiveServers -join ", ") } else { "" }
if ($passiveLabel) {
$serverDag = "$activeLabel | $passiveLabel"
}
else {
$serverDag = $activeLabel
}
if ($db.MasterServerOrAvailabilityGroup) {
$serverDag += " | DAG: $($db.MasterServerOrAvailabilityGroup)"
}
###############################################
# Health Details: Evaluate each copy's status and CopyQueueLength.
###############################################
$healthDetails = ($dbCopies | ForEach-Object {
$status = $_.Status
$healthClass = $Config.CSSClasses.Default
switch ($status) {
"Dismounted" { $healthClass = $Config.CSSClasses.Dismounted }
"Suspended" { $healthClass = $Config.CSSClasses.Suspended }
"Failed" { $healthClass = $Config.CSSClasses.Fail }
"Resync" { $healthClass = $Config.CSSClasses.Resynchronizing }
"Resynchronizing" { $healthClass = $Config.CSSClasses.Resynchronizing }
default {
if ($_.CopyQueueLength -gt $Config.CopyQueueLengthThreshold) {
$healthClass = $Config.CSSClasses.Fail
}
}
}
"<span class='$healthClass'>$($status): CQ=$($_.CopyQueueLength)</span>"
}) -join "; "
###############################################
# Backup Status: Determine backup type.
###############################################
$backupTime = if ($db.LastFullBackup) { $db.LastFullBackup.ToString("yyyy-MM-dd HH:mm:ss") } else { "N/A" }
if ($db.BackupInProgress) {
$backupStatusText = "In Progress"
$backupStatusClass = $Config.CSSClasses.InProgress
}
elseif ($db.LastFullBackup -and ($db.LastFullBackup -gt $Config.BackupThreshold)) {
$backupStatusText = "Full Backup"
$backupStatusClass = $Config.CSSClasses.Success
}
elseif (($db.PSObject.Properties.Name -contains "LastIncrementalBackup") -and $db.LastIncrementalBackup -and ($db.LastIncrementalBackup -gt $Config.BackupThreshold)) {
$backupStatusText = "Incremental Backup"
$backupStatusClass = $Config.CSSClasses.Success
}
elseif ($dbCopies | Where-Object { $_.CopyQueueLength -gt $Config.CopyQueueLengthThreshold }) {
$backupStatusText = "Warning: CopyQueue Exceeded"
$backupStatusClass = $Config.CSSClasses.Fail
}
else {
$backupStatusText = "None"
$backupStatusClass = $Config.CSSClasses.Fail
}
###############################################
# DB Status: Determine database status based on active copy.
# Use the server portion of the Identity property to match the active server.
###############################################
$activeCopy = $dbCopies | Where-Object { (($_."Identity" -split '\\')[1]) -eq $activeServer } | Select-Object -First 1
if (-not $activeCopy -and $dbCopies.Count -gt 0) {
$activeCopy = $dbCopies[0]
}
if ($activeCopy) {
$statusValue = $activeCopy.Status
}
else {
$statusValue = "Unknown"
}
switch ($statusValue) {
"Mounted" { $dbStatusClass = $Config.CSSClasses.Mounted; $dbStatusText = "Mounted" }
"Mounting" { $dbStatusClass = $Config.CSSClasses.Mounting; $dbStatusText = "Mounting" }
"Dismounted" { $dbStatusClass = $Config.CSSClasses.Dismounted; $dbStatusText = "Dismounted" }
"Dismounting" { $dbStatusClass = $Config.CSSClasses.Dismounting; $dbStatusText = "Dismounting" }
"Healthy" { $dbStatusClass = $Config.CSSClasses.Healthy; $dbStatusText = "Healthy" }
"Failed" { $dbStatusClass = $Config.CSSClasses.Fail; $dbStatusText = "Failed" }
"Suspended" { $dbStatusClass = $Config.CSSClasses.Suspended; $dbStatusText = "Suspended" }
"Seeding" { $dbStatusClass = $Config.CSSClasses.Seeding; $dbStatusText = "Seeding" }
"Initializing" { $dbStatusClass = $Config.CSSClasses.Initializing; $dbStatusText = "Initializing" }
"Resynchronizing" { $dbStatusClass = $Config.CSSClasses.Resynchronizing; $dbStatusText = "Resynchronizing" }
default { $dbStatusClass = $Config.CSSClasses.Default; $dbStatusText = $statusValue }
}
###############################################
# WhiteSpace/Mailboxes: Merge free space info and mailbox count.
###############################################
$freeSpaceText = if ($db.AvailableNewMailboxSpace -gt 1GB) {
"{0:N2} GB" -f ($db.AvailableNewMailboxSpace.ToGB())
}
else {
"{0:N2} MB" -f ($db.AvailableNewMailboxSpace.ToMB())
}
$mailboxCount = 0
try {
$mailboxCount = (Get-Mailbox -Database $dbName -ErrorAction SilentlyContinue).Count
}
catch {
$mailboxCount = 0
}
$whiteSpaceMailboxes = "WhiteSpace: $freeSpaceText / Mailboxes: $mailboxCount"
###############################################
# Disk Info: For each copy, use disk properties to build disk info.
# Properties: DiskTotalSpace, DiskFreeSpace, DiskFreeSpacePercent, DatabaseVolumeMountPoint.
# If DiskFreeSpacePercent is below or equal to threshold, wrap info in a CSS "lowDisk" div.
###############################################
$diskInfoLines = @()
$freePctValues = @()
foreach ($copy in $dbCopies) {
if ($copy.PSObject.Properties.Name -contains "DiskTotalSpace" -and $copy.DiskTotalSpace) {
# Extract server name from Identity.
$serverNameFromCopy = ($copy.Identity -split '\\')[1]
$role = if ($serverNameFromCopy -eq $activeServer) { "Active" } else { "Passive" }
$totalSpaceGB = [math]::Round($copy.DiskTotalSpace / 1GB, 2)
$freeSpaceGB = [math]::Round($copy.DiskFreeSpace / 1GB, 2)
$freePercent = $copy.DiskFreeSpacePercent # expected numeric value
$mountPoint = $copy.DatabaseVolumeMountPoint
$diskDetails = "Drive: $mountPoint | Total: ${totalSpaceGB} GB, Free: ${freeSpaceGB} GB ($freePercent`%)"
if ($freePercent -le $Config.FreeSpaceThreshold) {
$diskDetails = "<div class='$($Config.CSSClasses.LowDisk)'>$diskDetails</div>"
}
$diskInfoLines += "${role}: $diskDetails"
$freePctValues += $freePercent
}
}
if ($diskInfoLines.Count -gt 0) {
$diskInfoText = $diskInfoLines -join "<br/>"
}
else {
$diskInfoText = "N/A"
}
# Determine minimum free percentage among copies (worst-case scenario)
if ($freePctValues.Count -gt 0) {
$minFreePercent = [math]::Round(($freePctValues | Measure-Object -Minimum).Minimum, 2)
}
else {
$minFreePercent = 100
}
###############################################
# Create Custom Object for the Database
###############################################
$Databases += [PSCustomObject]@{
Name = $dbName
ServerDAG = $serverDag
DBStatusText = $dbStatusText
DBStatusClass = $dbStatusClass
Health = $healthDetails
BackupStatusText = $backupStatusText
BackupStatusClass = $backupStatusClass
BackupTime = $backupTime
DatabaseSize = if ($db.DatabaseSize) { $db.DatabaseSize.ToString() } else { "N/A" }
WhiteSpaceMailboxes = $whiteSpaceMailboxes
DiskInfo = $diskInfoText
DiskFreePercentage = $minFreePercent
ActiveServer = $activeServer
}
}
Modern-WriteProgress -Activity "Processing Completed" -PercentComplete 100 -Status "Finished processing databases"
###############################################
# Commit: Sort Databases into groups and by server and DB name.
# Sort order:
# 1. BackupStatusText "None" (no backup) first,
# 2. then "In Progress",
# 3. then others (backed up).
# Within each group, sort by ActiveServer then by database Name.
###############################################
$sortedDatabases = $Databases | Sort-Object `
@{ Expression = { if ($_.BackupStatusText -eq "None") { 1 } elseif ($_.BackupStatusText -eq "In Progress") { 2 } else { 3 } } }, `
@{ Expression = { $_.ActiveServer } }, `
@{ Expression = { $_.Name } }
###############################################
# Commit: Dynamic Alarm Messages for Email Body
###############################################
$dbAlarm = ""
# Alarm: Dismounted databases
$dismountedDatabases = $sortedDatabases | Where-Object { $_.Health -match "Dismounted" }
if ($dismountedDatabases.Count -gt 0) {
$dbAlarm += "<p style='font-size:14px;color:red;'><strong>Alarm: Dismounted databases detected!</strong></p><ul style='font-size:13px;color:#555;'>"
foreach ($dDB in $dismountedDatabases) {
$dbAlarm += "<li>$($dDB.Name) on $($dDB.ServerDAG) - Health: $($dDB.Health)</li>"
}
$dbAlarm += "</ul>"
}
# Alarm: Failed databases – list each failed copy
$failedDatabases = $sortedDatabases | Where-Object { $_.Health -match "Failed" }
if ($failedDatabases.Count -gt 0) {
$dbAlarm += "<p style='font-size:14px;color:red;'><strong>Alarm: Failed databases detected!</strong></p><ul style='font-size:13px;color:#555;'>"
foreach ($fDB in $failedDatabases) {
$dbAlarm += "<li>$($fDB.Name) - Health: $($fDB.Health)</li>"
}
$dbAlarm += "</ul>"
}
# Alarm: Low Disk Space detected (using DiskFreePercentage from our custom object)
$lowDiskDatabases = $sortedDatabases | Where-Object { $_.DiskFreePercentage -lt $Config.FreeSpaceThreshold }
if ($lowDiskDatabases.Count -gt 0) {
$dbAlarm += "<p style='font-size:14px;color:red;'><strong>Alarm: Low Disk Space detected on the following databases!</strong></p><ul style='font-size:13px;color:#555;'>"
foreach ($ldDB in $lowDiskDatabases) {
$dbAlarm += "<li>$($ldDB.Name) on $($ldDB.ServerDAG) - Disk Free: $($ldDB.DiskFreePercentage)%</li>"
}
$dbAlarm += "</ul>"
}
###############################################
# Commit: Generate Modern HTML Report
###############################################
$backedUpCount = ($sortedDatabases | Where-Object { $_.BackupStatusText -eq "Full Backup" -or $_.BackupStatusText -eq "Incremental Backup" }).Count
$inProgressCount = ($sortedDatabases | Where-Object { $_.BackupStatusText -eq "In Progress" }).Count
$notBackedUpCount = $sortedDatabases.Count - $backedUpCount - $inProgressCount
$HTMLReport = @"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Exchange Server Backup & Health Report</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 20px;
background-color: #f4f4f4;
color: #333;
}
h2, h3 {
color: #333;
}
p {
font-size: 14px;
line-height: 1.6;
}
.table-responsive {
width: 100%;
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
th, td {
padding: 12px 15px;
border: 1px solid #ddd;
text-align: left;
white-space: nowrap;
}
th {
background-color: #4CAF50;
color: #ffffff;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.05em;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
/* CSS classes for cell background coloring */
.inprogress { background-color: blue; color: white; }
.success { background-color: green; color: white; }
.fail { background-color: red; color: white; }
.mounted { background-color: green; color: white; }
.mounting { background-color: lightgreen; color: black; }
.dismounted { background-color: purple; color: white; }
.dismounting { background-color: mediumpurple; color: white; }
.healthy { background-color: limegreen; color: white; }
.failed { background-color: maroon; color: white; }
.suspended { background-color: darkorange; color: white; }
.seeding { background-color: blueviolet; color: white; }
.initializing { background-color: orange; color: white; }
.resynchronizing { background-color: teal; color: white; }
.lowDisk { background-color: red; color: white; }
.default { background-color: lightgray; color: black; }
</style>
</head>
<body>
<h2>Exchange Server Backup & Health Report</h2>
<p>Total Databases: $($sortedDatabases.Count). In the last 24 hours,
<strong>$backedUpCount</strong> databases were fully backed up,
<strong>$notBackedUpCount</strong> were not backed up, and
<strong>$inProgressCount</strong> are in progress.</p>
$dbAlarm
<h3>Database Details</h3>
<div class="table-responsive">
<table>
<tr>
<th>Name</th>
<th>Server - DAG</th>
<th>DB Status</th>
<th>Health</th>
<th>Backup Status</th>
<th>Database Size</th>
<th>WhiteSpace/Mailboxes</th>
<th>Disk Info</th>
</tr>
"@
foreach ($db in $sortedDatabases) {
$HTMLReport += @"
<tr>
<td>$($db.Name)</td>
<td>$($db.ServerDAG)</td>
<td class='$($db.DBStatusClass)'>$($db.DBStatusText)</td>
<td>$($db.Health)</td>
<td class='$($db.BackupStatusClass)'>$($db.BackupStatusText)<br/><small>$($db.BackupTime)</small></td>
<td>$($db.DatabaseSize)</td>
<td>$($db.WhiteSpaceMailboxes)</td>
<td>$($db.DiskInfo)</td>
</tr>
"@
}
$HTMLReport += @"
</table>
</div>
</body>
</html>
"@
###############################################
# Commit: Send Email Report with Progress Update
###############################################
Modern-WriteProgress -Activity "Sending Email" -PercentComplete 0 -Status "Initializing email sending process"
$MessageParameters = @{
From = $Config.From
# TO addresses are split by semicolon to allow multiple recipients.
To = $Config.To -split ';'
Subject = $Config.Subject
Priority = $Config.Priority
Body = $HTMLReport
BodyAsHtml = $true
SmtpServer = $Config.SMTPServer
Port = $Config.Port
Credential = $Credential
}
Send-MailMessage @MessageParameters
Modern-WriteProgress -Activity "Email Sent" -PercentComplete 100 -Status "Email report successfully sent"
Exchange Server 2019 altyapılarında otomatik yedekleme ve sağlık denetimi yapmak isteyen IT yöneticileri için bu PowerShell scripti bir yardımcı olacağını düşünüyorum.