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:
178
Misc/Backup-ExchangeCertificates.ps1
Normal file
178
Misc/Backup-ExchangeCertificates.ps1
Normal file
@ -0,0 +1,178 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Backup Exchange certificates to PFX files
|
||||
|
||||
.DESCRIPTION
|
||||
Exports all Exchange certificates to password-protected PFX files.
|
||||
Alerts on certificates expiring within specified days.
|
||||
|
||||
.PARAMETER OutputFolder
|
||||
Destination folder for PFX exports. Default: .\CertBackup-<date>
|
||||
|
||||
.PARAMETER Password
|
||||
Password for PFX files (required)
|
||||
|
||||
.PARAMETER ExpiryWarningDays
|
||||
Alert on certificates expiring within this many days (default: 90)
|
||||
|
||||
.PARAMETER IncludePrivateKey
|
||||
Export with private key (required for restoration, default: $true)
|
||||
|
||||
.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 password for PFX protection
|
||||
- Store PFX files securely - they contain private keys
|
||||
- Tested compatibility: Exchange 2013/2016/2019 (not validated)
|
||||
|
||||
.EXAMPLE
|
||||
$pwd = Read-Host "Enter PFX password" -AsSecureString
|
||||
.\Backup-ExchangeCertificates.ps1 -Password $pwd
|
||||
|
||||
.EXAMPLE
|
||||
$pwd = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force
|
||||
.\Backup-ExchangeCertificates.ps1 -Password $pwd -ExpiryWarningDays 60
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$OutputFolder = (Join-Path -Path (Get-Location) -ChildPath ("CertBackup-" + (Get-Date -Format "yyyyMMdd-HHmm"))),
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.Security.SecureString]$Password,
|
||||
|
||||
[int]$ExpiryWarningDays = 90,
|
||||
|
||||
[bool]$IncludePrivateKey = $true
|
||||
)
|
||||
|
||||
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 certificate backup..." -ForegroundColor Green
|
||||
|
||||
# Create output folder
|
||||
New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
|
||||
Write-Host "[$(NowTag)] Output folder: $OutputFolder"
|
||||
|
||||
# Get all Exchange certificates
|
||||
Write-Host "[$(NowTag)] Retrieving Exchange certificates..."
|
||||
$certs = Get-ExchangeCertificate -ErrorAction SilentlyContinue
|
||||
|
||||
if (-not $certs) {
|
||||
Write-Host "[$(NowTag)] No Exchange certificates found" -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
|
||||
$certCount = ($certs | Measure-Object).Count
|
||||
Write-Host "[$(NowTag)] Found $certCount certificate(s)"
|
||||
|
||||
# Process each certificate
|
||||
$exported = @()
|
||||
$warnings = @()
|
||||
|
||||
foreach ($cert in $certs) {
|
||||
$thumbprint = $cert.Thumbprint
|
||||
$subject = $cert.Subject
|
||||
$notAfter = $cert.NotAfter
|
||||
$daysUntilExpiry = [int](($notAfter - (Get-Date)).TotalDays)
|
||||
|
||||
Write-Host "[$(NowTag)] Processing: $subject (Thumbprint: $thumbprint)"
|
||||
|
||||
# Check expiry
|
||||
$status = "OK"
|
||||
if ($daysUntilExpiry -lt 0) {
|
||||
$status = "EXPIRED"
|
||||
$warnings += [PSCustomObject]@{
|
||||
Thumbprint = $thumbprint
|
||||
Subject = $subject
|
||||
NotAfter = $notAfter
|
||||
DaysRemaining = $daysUntilExpiry
|
||||
Status = $status
|
||||
}
|
||||
Write-Host " WARNING: Certificate EXPIRED on $($notAfter.ToString('yyyy-MM-dd'))" -ForegroundColor Red
|
||||
} elseif ($daysUntilExpiry -lt $ExpiryWarningDays) {
|
||||
$status = "EXPIRING SOON"
|
||||
$warnings += [PSCustomObject]@{
|
||||
Thumbprint = $thumbprint
|
||||
Subject = $subject
|
||||
NotAfter = $notAfter
|
||||
DaysRemaining = $daysUntilExpiry
|
||||
Status = $status
|
||||
}
|
||||
Write-Host " WARNING: Certificate expires in $daysUntilExpiry days ($($notAfter.ToString('yyyy-MM-dd')))" -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host " Status: OK - Expires in $daysUntilExpiry days"
|
||||
}
|
||||
|
||||
# Export to PFX
|
||||
$fileName = "$($thumbprint).pfx"
|
||||
$filePath = Join-Path $OutputFolder $fileName
|
||||
|
||||
try {
|
||||
if ($IncludePrivateKey) {
|
||||
# Export with private key
|
||||
Export-ExchangeCertificate -Thumbprint $thumbprint -FileName $filePath -Password $Password -ErrorAction Stop | Out-Null
|
||||
Write-Host " Exported: $fileName (with private key)" -ForegroundColor Green
|
||||
} else {
|
||||
# Export public key only (using .NET method)
|
||||
$certObj = Get-Item -Path "Cert:\LocalMachine\My\$thumbprint" -ErrorAction SilentlyContinue
|
||||
if ($certObj) {
|
||||
$certBytes = $certObj.Export('Cert')
|
||||
[System.IO.File]::WriteAllBytes($filePath, $certBytes)
|
||||
Write-Host " Exported: $fileName (public key only)" -ForegroundColor Green
|
||||
} else {
|
||||
throw "Certificate not found in LocalMachine\My"
|
||||
}
|
||||
}
|
||||
|
||||
$exported += [PSCustomObject]@{
|
||||
Thumbprint = $thumbprint
|
||||
Subject = $subject
|
||||
Services = ($cert.Services -join ", ")
|
||||
NotBefore = $cert.NotBefore
|
||||
NotAfter = $notAfter
|
||||
DaysRemaining = $daysUntilExpiry
|
||||
Status = $status
|
||||
FileName = $fileName
|
||||
FilePath = $filePath
|
||||
FileSize = (Get-Item $filePath).Length
|
||||
}
|
||||
} catch {
|
||||
Write-Host " ERROR exporting certificate: $($_.Exception.Message)" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
# Export inventory
|
||||
$inventoryFile = Join-Path $OutputFolder "Certificate-Inventory.csv"
|
||||
$exported | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $inventoryFile
|
||||
Write-Host "`n[$(NowTag)] Inventory exported: $inventoryFile" -ForegroundColor Green
|
||||
|
||||
# Export warnings if any
|
||||
if ($warnings.Count -gt 0) {
|
||||
$warningsFile = Join-Path $OutputFolder "Certificate-Warnings.csv"
|
||||
$warnings | Sort-Object DaysRemaining | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $warningsFile
|
||||
Write-Host "[$(NowTag)] Warnings exported: $warningsFile" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Summary
|
||||
Write-Host "`nBACKUP SUMMARY:" -ForegroundColor Cyan
|
||||
Write-Host " Total Certificates: $certCount"
|
||||
Write-Host " Successfully Exported: $($exported.Count)" -ForegroundColor Green
|
||||
Write-Host " Failed: $($certCount - $exported.Count)" -ForegroundColor $(if ($certCount - $exported.Count -gt 0) { "Red" } else { "Green" })
|
||||
Write-Host " Expired: $(($warnings | Where-Object Status -eq 'EXPIRED').Count)" -ForegroundColor Red
|
||||
Write-Host " Expiring Soon: $(($warnings | Where-Object Status -eq 'EXPIRING SOON').Count)" -ForegroundColor Yellow
|
||||
|
||||
if ($warnings.Count -gt 0) {
|
||||
Write-Host "`nCERTIFICATE WARNINGS:" -ForegroundColor Yellow
|
||||
$warnings | Sort-Object DaysRemaining | ForEach-Object {
|
||||
$color = if ($_.Status -eq "EXPIRED") { "Red" } else { "Yellow" }
|
||||
Write-Host " $($_.Status): $($_.Subject) - $($_.DaysRemaining) days" -ForegroundColor $color
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`n[$(NowTag)] Backup complete! Output folder: $OutputFolder"
|
||||
Write-Host "`nIMPORTANT: Store PFX files securely - they contain private keys!" -ForegroundColor Cyan
|
||||
Reference in New Issue
Block a user