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>
This commit is contained in:
190
Exchange/Compare-MailboxDatabases.ps1
Normal file
190
Exchange/Compare-MailboxDatabases.ps1
Normal file
@ -0,0 +1,190 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Compare health metrics across all Exchange mailbox databases
|
||||
|
||||
.DESCRIPTION
|
||||
Generates a comparison report of database sizes, whitespace, mount status,
|
||||
backup age, and circular logging settings. Alerts on databases exceeding
|
||||
thresholds or with configuration issues.
|
||||
|
||||
.PARAMETER WhitespaceThresholdGB
|
||||
Alert if available whitespace exceeds this value (default: 50)
|
||||
|
||||
.PARAMETER BackupAgeThresholdDays
|
||||
Alert if last backup is older than this many days (default: 2)
|
||||
|
||||
.PARAMETER OutputFolder
|
||||
Destination folder for reports. Default: .\DatabaseComparison-<date>
|
||||
|
||||
.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 with appropriate RBAC permissions
|
||||
- Requires -Status parameter support (Get-MailboxDatabase -Status)
|
||||
- Tested compatibility: Exchange 2013/2016/2019 (not validated)
|
||||
|
||||
.EXAMPLE
|
||||
.\Compare-MailboxDatabases.ps1
|
||||
|
||||
.EXAMPLE
|
||||
.\Compare-MailboxDatabases.ps1 -WhitespaceThresholdGB 100 -BackupAgeThresholdDays 1
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[int]$WhitespaceThresholdGB = 50,
|
||||
[int]$BackupAgeThresholdDays = 2,
|
||||
[string]$OutputFolder = (Join-Path -Path (Get-Location) -ChildPath ("DatabaseComparison-" + (Get-Date -Format "yyyyMMdd-HHmm")))
|
||||
)
|
||||
|
||||
function NowTag { (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") }
|
||||
|
||||
function Convert-BytesToGB([string]$sizeStr) {
|
||||
if (-not $sizeStr) { return 0 }
|
||||
try {
|
||||
if ($sizeStr -match "([\d\.,]+)\s*(KB|MB|GB|TB)") {
|
||||
$num = [double]($matches[1] -replace ',', '.')
|
||||
$bytes = switch ($matches[2].ToUpper()) {
|
||||
"KB" { $num * 1KB }
|
||||
"MB" { $num * 1MB }
|
||||
"GB" { $num * 1GB }
|
||||
"TB" { $num * 1TB }
|
||||
}
|
||||
return [math]::Round($bytes / 1GB, 2)
|
||||
}
|
||||
} catch {}
|
||||
return 0
|
||||
}
|
||||
|
||||
Write-Host "[$(NowTag)] ⚠️ AI-GENERATED SCRIPT - UNTESTED" -ForegroundColor Yellow
|
||||
Write-Host "[$(NowTag)] Starting database comparison analysis..." -ForegroundColor Green
|
||||
|
||||
# Create output folder
|
||||
New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
|
||||
|
||||
# Get all databases with status
|
||||
Write-Host "[$(NowTag)] Retrieving mailbox databases..."
|
||||
$databases = Get-MailboxDatabase -Status -ErrorAction SilentlyContinue | Sort-Object Name
|
||||
|
||||
$dbCount = ($databases | Measure-Object).Count
|
||||
Write-Host "[$(NowTag)] Found $dbCount databases"
|
||||
|
||||
# Analyze each database
|
||||
$dbAnalysis = @()
|
||||
$alerts = @()
|
||||
|
||||
foreach ($db in $databases) {
|
||||
Write-Host "[$(NowTag)] Analyzing $($db.Name)..."
|
||||
|
||||
$dbSizeGB = Convert-BytesToGB ([string]$db.DatabaseSize)
|
||||
$whitespaceGB = Convert-BytesToGB ([string]$db.AvailableNewMailboxSpace)
|
||||
|
||||
$backupAge = $null
|
||||
$backupStatus = "Unknown"
|
||||
if ($db.LastFullBackup) {
|
||||
$backupAge = [int]((Get-Date) - $db.LastFullBackup).TotalDays
|
||||
$backupStatus = if ($backupAge -le $BackupAgeThresholdDays) { "OK" } else { "OLD" }
|
||||
} else {
|
||||
$backupStatus = "NEVER"
|
||||
}
|
||||
|
||||
# Generate alerts
|
||||
$dbAlerts = @()
|
||||
|
||||
if (-not $db.Mounted) {
|
||||
$dbAlerts += "Database is DISMOUNTED"
|
||||
$alerts += [PSCustomObject]@{
|
||||
Database = $db.Name
|
||||
Severity = "CRITICAL"
|
||||
Alert = "Database is dismounted"
|
||||
}
|
||||
}
|
||||
|
||||
if ($whitespaceGB -gt $WhitespaceThresholdGB) {
|
||||
$dbAlerts += "Excessive whitespace: $whitespaceGB GB"
|
||||
$alerts += [PSCustomObject]@{
|
||||
Database = $db.Name
|
||||
Severity = "WARNING"
|
||||
Alert = "Excessive whitespace: $whitespaceGB GB (threshold: $WhitespaceThresholdGB GB)"
|
||||
}
|
||||
}
|
||||
|
||||
if ($backupStatus -eq "NEVER") {
|
||||
$dbAlerts += "Never backed up"
|
||||
$alerts += [PSCustomObject]@{
|
||||
Database = $db.Name
|
||||
Severity = "CRITICAL"
|
||||
Alert = "Database has never been backed up"
|
||||
}
|
||||
} elseif ($backupStatus -eq "OLD") {
|
||||
$dbAlerts += "Backup is $backupAge days old"
|
||||
$alerts += [PSCustomObject]@{
|
||||
Database = $db.Name
|
||||
Severity = "WARNING"
|
||||
Alert = "Last backup is $backupAge days old (threshold: $BackupAgeThresholdDays days)"
|
||||
}
|
||||
}
|
||||
|
||||
if ($db.CircularLoggingEnabled) {
|
||||
$dbAlerts += "Circular logging enabled"
|
||||
$alerts += [PSCustomObject]@{
|
||||
Database = $db.Name
|
||||
Severity = "INFO"
|
||||
Alert = "Circular logging is enabled"
|
||||
}
|
||||
}
|
||||
|
||||
$dbAnalysis += [PSCustomObject]@{
|
||||
Database = $db.Name
|
||||
Server = $db.Server
|
||||
Mounted = $db.Mounted
|
||||
DatabaseSizeGB = $dbSizeGB
|
||||
WhitespaceGB = $whitespaceGB
|
||||
WhitespacePercent = if ($dbSizeGB -gt 0) { [math]::Round(($whitespaceGB / $dbSizeGB) * 100, 2) } else { 0 }
|
||||
CircularLogging = $db.CircularLoggingEnabled
|
||||
LastFullBackup = $db.LastFullBackup
|
||||
BackupAgeDays = $backupAge
|
||||
BackupStatus = $backupStatus
|
||||
EdbFilePath = $db.EdbFilePath
|
||||
LogFolderPath = $db.LogFolderPath
|
||||
Alerts = ($dbAlerts -join "; ")
|
||||
}
|
||||
}
|
||||
|
||||
# Export full analysis
|
||||
$csvFile = Join-Path $OutputFolder "Database-Comparison.csv"
|
||||
$dbAnalysis | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $csvFile
|
||||
Write-Host "[$(NowTag)] Database analysis exported: $csvFile" -ForegroundColor Green
|
||||
|
||||
# Export alerts
|
||||
if ($alerts.Count -gt 0) {
|
||||
$alertsFile = Join-Path $OutputFolder "Database-Alerts.csv"
|
||||
$alerts | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $alertsFile
|
||||
Write-Host "[$(NowTag)] Alerts exported: $alertsFile" -ForegroundColor Yellow
|
||||
|
||||
Write-Host "`nALERTS FOUND:" -ForegroundColor Yellow
|
||||
$alerts | Group-Object Severity | ForEach-Object {
|
||||
Write-Host " $($_.Name): $($_.Count) alert(s)" -ForegroundColor $(
|
||||
switch ($_.Name) {
|
||||
"CRITICAL" { "Red" }
|
||||
"WARNING" { "Yellow" }
|
||||
default { "Cyan" }
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Write-Host "`n[$(NowTag)] No alerts found - all databases healthy!" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Summary statistics
|
||||
Write-Host "`nDATABASE SUMMARY:" -ForegroundColor Cyan
|
||||
Write-Host " Total Databases: $dbCount"
|
||||
Write-Host " Mounted: $(($dbAnalysis | Where-Object Mounted).Count)"
|
||||
Write-Host " Dismounted: $(($dbAnalysis | Where-Object { -not $_.Mounted }).Count)"
|
||||
Write-Host " Total Size: $([math]::Round(($dbAnalysis | Measure-Object DatabaseSizeGB -Sum).Sum, 2)) GB"
|
||||
Write-Host " Total Whitespace: $([math]::Round(($dbAnalysis | Measure-Object WhitespaceGB -Sum).Sum, 2)) GB"
|
||||
Write-Host " Circular Logging Enabled: $(($dbAnalysis | Where-Object CircularLogging).Count)"
|
||||
|
||||
Write-Host "`n[$(NowTag)] Analysis complete! Output folder: $OutputFolder"
|
||||
Reference in New Issue
Block a user