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:
226
Exchange/Get-MailflowStats.ps1
Normal file
226
Exchange/Get-MailflowStats.ps1
Normal file
@ -0,0 +1,226 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Analyze Exchange message flow statistics from transport logs
|
||||
|
||||
.DESCRIPTION
|
||||
Aggregates statistics from Exchange transport logs including top senders/receivers,
|
||||
message volume by time period, and potential anomalies. Builds on Get-SMTPTraffic.ps1
|
||||
pattern but provides comprehensive analysis.
|
||||
|
||||
.PARAMETER LogPath
|
||||
Path to transport logs (default: auto-detect from Exchange install)
|
||||
|
||||
.PARAMETER DaysBack
|
||||
Number of days of logs to analyze (default: 7)
|
||||
|
||||
.PARAMETER OutputFolder
|
||||
Destination folder for reports. Default: .\MailflowStats-<date>
|
||||
|
||||
.PARAMETER TopCount
|
||||
Number of top senders/receivers to include in report (default: 25)
|
||||
|
||||
.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
|
||||
- Can be slow with large log volumes
|
||||
- Analyzes SMTP Receive logs by default
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-MailflowStats.ps1
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-MailflowStats.ps1 -DaysBack 30 -TopCount 50
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$LogPath = "",
|
||||
[int]$DaysBack = 7,
|
||||
[string]$OutputFolder = (Join-Path -Path (Get-Location) -ChildPath ("MailflowStats-" + (Get-Date -Format "yyyyMMdd-HHmm"))),
|
||||
[int]$TopCount = 25
|
||||
)
|
||||
|
||||
function NowTag { (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") }
|
||||
|
||||
Write-Host "[$(NowTag)] ⚠️ AI-GENERATED SCRIPT - UNTESTED" -ForegroundColor Yellow
|
||||
Write-Host "[$(NowTag)] Starting mail flow analysis..." -ForegroundColor Green
|
||||
|
||||
# Auto-detect log path if not specified
|
||||
if (-not $LogPath) {
|
||||
$exchangePath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup" -ErrorAction SilentlyContinue).MsiInstallPath
|
||||
if ($exchangePath) {
|
||||
$LogPath = Join-Path $exchangePath "TransportRoles\Logs\FrontEnd\ProtocolLog\SmtpReceive"
|
||||
} else {
|
||||
Write-Host "[$(NowTag)] ERROR: Could not auto-detect Exchange log path. Please specify -LogPath parameter" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Test-Path $LogPath)) {
|
||||
Write-Host "[$(NowTag)] ERROR: Log path not found: $LogPath" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[$(NowTag)] Log path: $LogPath"
|
||||
|
||||
# Create output folder
|
||||
New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
|
||||
|
||||
# Get log files within date range
|
||||
$cutoffDate = (Get-Date).AddDays(-$DaysBack)
|
||||
Write-Host "[$(NowTag)] Analyzing logs from $($cutoffDate.ToString('yyyy-MM-dd')) to $(Get-Date -Format 'yyyy-MM-dd')"
|
||||
|
||||
$logFiles = Get-ChildItem -Path $LogPath -Filter "*.log" -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.LastWriteTime -ge $cutoffDate } |
|
||||
Sort-Object LastWriteTime -Descending
|
||||
|
||||
$fileCount = ($logFiles | Measure-Object).Count
|
||||
|
||||
if ($fileCount -eq 0) {
|
||||
Write-Host "[$(NowTag)] No log files found in specified date range" -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "[$(NowTag)] Found $fileCount log file(s) to analyze"
|
||||
|
||||
# Parse logs
|
||||
$allMessages = @()
|
||||
$fileIdx = 0
|
||||
|
||||
foreach ($logFile in $logFiles) {
|
||||
$fileIdx++
|
||||
Write-Progress -Activity "Parsing Transport Logs" -Status "Processing $($logFile.Name) ($fileIdx/$fileCount)" -PercentComplete ([int](($fileIdx / $fileCount) * 100))
|
||||
|
||||
# Get header from file
|
||||
$header = Get-Content $logFile.FullName -TotalCount 50 | Where-Object { $_ -like '#Fields:*' } | Select-Object -First 1
|
||||
if (-not $header) { continue }
|
||||
|
||||
$fields = $header -replace '^#Fields: ', ''
|
||||
$columns = $fields -split ','
|
||||
|
||||
# Parse log entries
|
||||
Get-Content $logFile.FullName | Where-Object { -not ($_ -like '#*') -and $_ -match ',' } | ForEach-Object {
|
||||
try {
|
||||
$row = $_ -split ',(?=(?:[^"]*"[^"]*")*[^"]*$)' # Handle quoted fields
|
||||
$entry = [PSCustomObject]@{}
|
||||
|
||||
for ($i = 0; $i -lt $columns.Count -and $i -lt $row.Count; $i++) {
|
||||
$entry | Add-Member -NotePropertyName $columns[$i].Trim() -NotePropertyValue ($row[$i] -replace '^"|"$', '') -Force
|
||||
}
|
||||
|
||||
# Filter for relevant events (RECEIVE events)
|
||||
if ($entry.event -eq 'RECEIVE' -or $entry.event -eq '+') {
|
||||
$allMessages += $entry
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Progress -Activity "Parsing Transport Logs" -Completed
|
||||
|
||||
$totalMessages = $allMessages.Count
|
||||
Write-Host "[$(NowTag)] Parsed $totalMessages message(s)"
|
||||
|
||||
if ($totalMessages -eq 0) {
|
||||
Write-Host "[$(NowTag)] No messages found to analyze" -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Analyze data
|
||||
Write-Host "[$(NowTag)] Analyzing message flow patterns..."
|
||||
|
||||
# Top senders (by remote-endpoint or client-ip)
|
||||
$topSenders = $allMessages | Where-Object { $_.'remote-endpoint' } |
|
||||
Group-Object -Property 'remote-endpoint' |
|
||||
Select-Object @{N = "IPAddress"; E = { $_.Name } }, Count |
|
||||
Sort-Object Count -Descending |
|
||||
Select-Object -First $TopCount
|
||||
|
||||
# Messages by hour
|
||||
$messagesByHour = $allMessages | Where-Object { $_.'date-time' } |
|
||||
ForEach-Object {
|
||||
try {
|
||||
$dt = [DateTime]::Parse($_.'date-time')
|
||||
[PSCustomObject]@{ Hour = $dt.Hour }
|
||||
} catch {}
|
||||
} |
|
||||
Group-Object Hour |
|
||||
Select-Object @{N = "Hour"; E = { $_.Name } }, Count |
|
||||
Sort-Object Hour
|
||||
|
||||
# Messages by day
|
||||
$messagesByDay = $allMessages | Where-Object { $_.'date-time' } |
|
||||
ForEach-Object {
|
||||
try {
|
||||
$dt = [DateTime]::Parse($_.'date-time')
|
||||
[PSCustomObject]@{ Date = $dt.ToString('yyyy-MM-dd') }
|
||||
} catch {}
|
||||
} |
|
||||
Group-Object Date |
|
||||
Select-Object @{N = "Date"; E = { $_.Name } }, Count |
|
||||
Sort-Object Date
|
||||
|
||||
# Connector usage
|
||||
$connectorStats = $allMessages | Where-Object { $_.'connector-id' } |
|
||||
Group-Object -Property 'connector-id' |
|
||||
Select-Object @{N = "Connector"; E = { $_.Name } }, Count |
|
||||
Sort-Object Count -Descending
|
||||
|
||||
# Export results
|
||||
Write-Host "[$(NowTag)] Exporting results..."
|
||||
|
||||
$summaryFile = Join-Path $OutputFolder "Mailflow-Summary.txt"
|
||||
$topSendersFile = Join-Path $OutputFolder "Top-Senders-By-IP.csv"
|
||||
$byHourFile = Join-Path $OutputFolder "Messages-By-Hour.csv"
|
||||
$byDayFile = Join-Path $OutputFolder "Messages-By-Day.csv"
|
||||
$connectorFile = Join-Path $OutputFolder "Messages-By-Connector.csv"
|
||||
|
||||
$topSenders | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $topSendersFile
|
||||
$messagesByHour | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $byHourFile
|
||||
$messagesByDay | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $byDayFile
|
||||
$connectorStats | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $connectorFile
|
||||
|
||||
Write-Host "[$(NowTag)] Top senders: $topSendersFile" -ForegroundColor Green
|
||||
Write-Host "[$(NowTag)] Hourly distribution: $byHourFile" -ForegroundColor Green
|
||||
Write-Host "[$(NowTag)] Daily distribution: $byDayFile" -ForegroundColor Green
|
||||
Write-Host "[$(NowTag)] Connector stats: $connectorFile" -ForegroundColor Green
|
||||
|
||||
# Summary report
|
||||
$summary = @"
|
||||
Mail Flow Statistics Report
|
||||
Generated: $(Get-Date)
|
||||
Analysis Period: $($cutoffDate.ToString('yyyy-MM-dd')) to $(Get-Date -Format 'yyyy-MM-dd')
|
||||
Log Path: $LogPath
|
||||
|
||||
SUMMARY:
|
||||
Total Messages Analyzed: $totalMessages
|
||||
Log Files Processed: $fileCount
|
||||
Average Messages Per Day: $([math]::Round($totalMessages / $DaysBack, 0))
|
||||
|
||||
TOP $TopCount SENDERS (by IP):
|
||||
$($topSenders | ForEach-Object { " $($_.IPAddress): $($_.Count) messages" } | Out-String)
|
||||
|
||||
BUSIEST HOURS (24-hour format):
|
||||
$($messagesByHour | Sort-Object Count -Descending | Select-Object -First 5 | ForEach-Object { " Hour $($_.Hour): $($_.Count) messages" } | Out-String)
|
||||
|
||||
DAILY VOLUME:
|
||||
$($messagesByDay | ForEach-Object { " $($_.Date): $($_.Count) messages" } | Out-String)
|
||||
|
||||
CONNECTOR USAGE:
|
||||
$($connectorStats | ForEach-Object { " $($_.Connector): $($_.Count) messages" } | Out-String)
|
||||
"@
|
||||
|
||||
$summary | Out-File -FilePath $summaryFile -Encoding UTF8
|
||||
Write-Host "[$(NowTag)] Summary report: $summaryFile" -ForegroundColor Green
|
||||
|
||||
# Console output
|
||||
Write-Host "`nMAIL FLOW SUMMARY:" -ForegroundColor Cyan
|
||||
Write-Host " Total Messages: $totalMessages"
|
||||
Write-Host " Average Per Day: $([math]::Round($totalMessages / $DaysBack, 0))"
|
||||
Write-Host " Peak Hour: $(($messagesByHour | Sort-Object Count -Descending | Select-Object -First 1).Hour):00"
|
||||
Write-Host " Busiest Day: $(($messagesByDay | Sort-Object Count -Descending | Select-Object -First 1).Date)"
|
||||
|
||||
Write-Host "`n[$(NowTag)] Analysis complete! Output folder: $OutputFolder"
|
||||
Reference in New Issue
Block a user