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:
191
Exchange/Get-InactiveMailboxes.ps1
Normal file
191
Exchange/Get-InactiveMailboxes.ps1
Normal file
@ -0,0 +1,191 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Identify inactive mailboxes based on LastLogonTime
|
||||
|
||||
.DESCRIPTION
|
||||
Finds mailboxes with no logon activity within specified days.
|
||||
Useful for identifying stale accounts, cost optimization, and cleanup planning.
|
||||
|
||||
.PARAMETER InactiveDays
|
||||
Number of days without logon to consider mailbox inactive (default: 90)
|
||||
|
||||
.PARAMETER OutputFolder
|
||||
Destination folder for reports. Default: .\InactiveMailboxes-<date>
|
||||
|
||||
.PARAMETER IncludeShared
|
||||
Include shared mailboxes in the report (default: $false)
|
||||
|
||||
.PARAMETER IncludeSize
|
||||
Include mailbox size information (slower, 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
|
||||
- LastLogonTime may be null for never-accessed mailboxes
|
||||
- Size calculation can be slow with large mailbox counts
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-InactiveMailboxes.ps1
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-InactiveMailboxes.ps1 -InactiveDays 180 -IncludeShared $true
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[int]$InactiveDays = 90,
|
||||
[string]$OutputFolder = (Join-Path -Path (Get-Location) -ChildPath ("InactiveMailboxes-" + (Get-Date -Format "yyyyMMdd-HHmm"))),
|
||||
[bool]$IncludeShared = $false,
|
||||
[bool]$IncludeSize = $true
|
||||
)
|
||||
|
||||
function NowTag { (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") }
|
||||
|
||||
Write-Host "[$(NowTag)] ⚠️ AI-GENERATED SCRIPT - UNTESTED" -ForegroundColor Yellow
|
||||
Write-Host "[$(NowTag)] Searching for mailboxes inactive for $InactiveDays+ days..." -ForegroundColor Green
|
||||
|
||||
# Create output folder
|
||||
New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
|
||||
|
||||
$cutoffDate = (Get-Date).AddDays(-$InactiveDays)
|
||||
Write-Host "[$(NowTag)] Cutoff date: $($cutoffDate.ToString('yyyy-MM-dd'))"
|
||||
|
||||
# Get mailboxes
|
||||
Write-Host "[$(NowTag)] Retrieving mailboxes..."
|
||||
$filter = if ($IncludeShared) {
|
||||
{ RecipientTypeDetails -notmatch "^Remote" -and Database }
|
||||
} else {
|
||||
{ RecipientTypeDetails -eq "UserMailbox" -and Database }
|
||||
}
|
||||
|
||||
$mailboxes = Get-Mailbox -ResultSize Unlimited -ErrorAction SilentlyContinue |
|
||||
Where-Object $filter
|
||||
|
||||
$mbCount = ($mailboxes | Measure-Object).Count
|
||||
Write-Host "[$(NowTag)] Found $mbCount mailboxes to check"
|
||||
|
||||
# Get statistics per database to avoid prompts
|
||||
Write-Host "[$(NowTag)] Retrieving mailbox statistics..."
|
||||
$statsByDb = @{}
|
||||
$databases = ($mailboxes.Database | Sort-Object -Unique)
|
||||
|
||||
$dbIdx = 0
|
||||
foreach ($db in $databases) {
|
||||
$dbIdx++
|
||||
Write-Progress -Activity "Collecting Mailbox Statistics" -Status "Database $db ($dbIdx/$($databases.Count))" -PercentComplete ([int](($dbIdx / $databases.Count) * 100))
|
||||
|
||||
try {
|
||||
$stats = Get-MailboxStatistics -Database $db -ErrorAction SilentlyContinue
|
||||
foreach ($stat in $stats) {
|
||||
$statsByDb[$stat.DisplayName] = $stat
|
||||
}
|
||||
} catch {
|
||||
Write-Host "[$(NowTag)] WARNING: Could not get statistics for database $db" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
Write-Progress -Activity "Collecting Mailbox Statistics" -Completed
|
||||
|
||||
# Analyze for inactive mailboxes
|
||||
Write-Host "[$(NowTag)] Analyzing mailbox activity..."
|
||||
$inactiveMailboxes = @()
|
||||
|
||||
$current = 0
|
||||
foreach ($mb in $mailboxes) {
|
||||
$current++
|
||||
$pct = [int](($current / $mbCount) * 100)
|
||||
Write-Progress -Activity "Analyzing Mailboxes" -Status "Processing $($mb.DisplayName) ($current/$mbCount)" -PercentComplete $pct
|
||||
|
||||
$stat = $statsByDb[$mb.DisplayName]
|
||||
|
||||
$lastLogon = if ($stat) { $stat.LastLogonTime } else { $null }
|
||||
$isInactive = $false
|
||||
$reason = ""
|
||||
|
||||
if ($null -eq $lastLogon) {
|
||||
$isInactive = $true
|
||||
$reason = "Never logged on"
|
||||
} elseif ($lastLogon -lt $cutoffDate) {
|
||||
$isInactive = $true
|
||||
$reason = "Last logon: $($lastLogon.ToString('yyyy-MM-dd'))"
|
||||
}
|
||||
|
||||
if ($isInactive) {
|
||||
$daysSinceLogon = if ($lastLogon) {
|
||||
[int]((Get-Date) - $lastLogon).TotalDays
|
||||
} else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$size = $null
|
||||
$itemCount = $null
|
||||
|
||||
if ($IncludeSize -and $stat) {
|
||||
$size = $stat.TotalItemSize
|
||||
$itemCount = $stat.ItemCount
|
||||
}
|
||||
|
||||
$inactiveMailboxes += [PSCustomObject]@{
|
||||
DisplayName = $mb.DisplayName
|
||||
PrimarySmtpAddress = $mb.PrimarySmtpAddress
|
||||
RecipientTypeDetails = $mb.RecipientTypeDetails
|
||||
Database = $mb.Database
|
||||
LastLogonTime = $lastLogon
|
||||
DaysSinceLogon = $daysSinceLogon
|
||||
WhenCreated = $mb.WhenCreated
|
||||
TotalItemSize = $size
|
||||
ItemCount = $itemCount
|
||||
Reason = $reason
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Progress -Activity "Analyzing Mailboxes" -Completed
|
||||
|
||||
# Export results
|
||||
Write-Host "[$(NowTag)] Found $($inactiveMailboxes.Count) inactive mailboxes"
|
||||
|
||||
if ($inactiveMailboxes.Count -gt 0) {
|
||||
$csvFile = Join-Path $OutputFolder "Inactive-Mailboxes.csv"
|
||||
$inactiveMailboxes | Sort-Object DaysSinceLogon -Descending |
|
||||
Export-Csv -NoTypeInformation -Encoding UTF8 -Path $csvFile
|
||||
Write-Host "[$(NowTag)] Report exported: $csvFile" -ForegroundColor Green
|
||||
|
||||
# Summary by type
|
||||
$byType = $inactiveMailboxes | Group-Object RecipientTypeDetails
|
||||
Write-Host "`nInactive Mailboxes by Type:"
|
||||
foreach ($type in $byType) {
|
||||
Write-Host " $($type.Name): $($type.Count)"
|
||||
}
|
||||
|
||||
# Calculate potential storage savings
|
||||
if ($IncludeSize) {
|
||||
$totalBytes = 0
|
||||
foreach ($mb in $inactiveMailboxes) {
|
||||
if ($mb.TotalItemSize) {
|
||||
try {
|
||||
$sizeStr = [string]$mb.TotalItemSize
|
||||
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 }
|
||||
}
|
||||
$totalBytes += $bytes
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
$totalGB = [math]::Round($totalBytes / 1GB, 2)
|
||||
Write-Host "`nPotential storage savings: $totalGB GB" -ForegroundColor Cyan
|
||||
}
|
||||
} else {
|
||||
Write-Host "[$(NowTag)] No inactive mailboxes found!" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host "`n[$(NowTag)] Analysis complete! Output folder: $OutputFolder"
|
||||
Reference in New Issue
Block a user