# Set Error Action Preference for the script $ErrorActionPreference = 'Stop' # Stop on terminating errors try { # Import admin credentials Write-Host "Loading configuration..." -ForegroundColor Gray $serverAddress = Get-Content -Path ".\DefaultServer.txt" -ErrorAction SilentlyContinue if (-not $serverAddress) { throw "Could not read server address from .\DefaultServer.txt" } $credential = Import-Clixml -Path .\AdminCredential.xml -ErrorAction SilentlyContinue if (-not $credential) { throw "Could not import credentials from .\AdminCredential.xml" } # Establish session with Exchange Server Write-Host "Connecting to Exchange server $serverAddress..." -ForegroundColor Yellow $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$serverAddress/PowerShell/" -Authentication Kerberos -Credential $credential # ErrorAction Stop is implied by preference Import-PSSession $session -DisableNameChecking -WarningAction SilentlyContinue # ErrorAction Stop is implied by preference Write-Host "Successfully connected." -ForegroundColor Green # Define output file path in the user's Downloads folder $outputFile = Join-Path -Path $env:USERPROFILE -ChildPath "Downloads\ExchangeDatabaseMailboxListReport_$(Get-Date -Format 'yyyyMMdd_HHmm').html" Write-Host "Report will be saved to: $outputFile" -ForegroundColor Gray # --- Data Collection Variables --- $totalUserMailboxes = 0 $totalSharedMailboxes = 0 $databaseStats = @() # Array to hold stats for the column chart # --- HTML Report Setup --- Write-Host "Setting up HTML structure and styles..." -ForegroundColor Gray $head = @" "@ # Start building the HTML body content $scriptStartTime = Get-Date $bodyContent = "
Generated on: $($scriptStartTime.ToString('yyyy-MM-dd HH:mm:ss')) (AEST - Bexley, NSW)
" $bodyContent += "Note: System mailboxes such as 'Discovery Search Mailbox' have been excluded. Size and Last Logon data retrieval can take significant time.
" # Get database size and mailboxes Write-Host "Retrieving database information..." -ForegroundColor Yellow $databases = Get-MailboxDatabase -Status | Select-Object Name, DatabaseSize Write-Host "Found $($databases.Count) databases." -ForegroundColor Green # --- Process Each Database --- foreach ($db in $databases) { $dbStartTime = Get-Date Write-Host "Processing database: $($db.Name)" -ForegroundColor Yellow $dbName = $db.Name $dbSize = $db.DatabaseSize -replace '\s*\(.*\)', '' # Clean up size string # Add database details to the HTML body $bodyContent += "Total Size: $dbSize
" # Retrieve base mailboxes first Write-Host " Retrieving base mailbox list for $dbName..." -ForegroundColor Gray $baseMailboxes = Get-Mailbox -Database $dbName -ResultSize Unlimited | Where-Object {$_.DisplayName -ne "Discovery Search Mailbox"} | Select-Object Identity, DisplayName, PrimarySmtpAddress, RecipientTypeDetails Write-Host " Found $($baseMailboxes.Count) mailboxes to query for statistics." -ForegroundColor Gray # --- Get Detailed Stats (Slow Part) --- $detailedMailboxData = @() # Array to hold combined data for this DB Write-Host " Retrieving statistics for $($baseMailboxes.Count) mailboxes (this may take considerable time)..." -ForegroundColor Cyan $progressCount = 0 foreach ($mb in $baseMailboxes) { $progressCount++ Write-Progress -Activity "Getting Mailbox Stats for $($db.Name)" -Status "Processing mailbox $progressCount of $($baseMailboxes.Count): $($mb.DisplayName)" -PercentComplete (($progressCount / $baseMailboxes.Count) * 100) $mbSize = "N/A" $mbLastLogon = $null try { $stats = Get-MailboxStatistics -Identity $mb.Identity -ErrorAction Stop | Select-Object TotalItemSize, LastLogonTime if ($stats.TotalItemSize -ne $null) { $mbSize = "{0:N2}" -f $stats.TotalItemSize.ToMB() } $mbLastLogon = $stats.LastLogonTime } catch { Write-Warning "Could not retrieve statistics for mailbox $($mb.DisplayName) ($($mb.Identity)). Error: $($_.Exception.Message)" $mbSize = "Error" $mbLastLogon = $null } $detailedMailboxData += [PSCustomObject]@{ DisplayName = $mb.DisplayName PrimarySmtpAddress = $mb.PrimarySmtpAddress RecipientTypeDetails = $mb.RecipientTypeDetails MailboxSizeMB = $mbSize LastLogonTime = $mbLastLogon } } # End foreach mailbox statistics Write-Progress -Activity "Getting Mailbox Stats for $($db.Name)" -Completed Write-Host " Finished retrieving statistics for $dbName." -ForegroundColor Green # Filter and Sort the detailed data Write-Host " Filtering and sorting mailbox data..." -ForegroundColor Gray $userMailboxes = $detailedMailboxData | Where-Object {$_.RecipientTypeDetails -eq "UserMailbox"} | Sort-Object DisplayName $sharedMailboxes = $detailedMailboxData | Where-Object {$_.RecipientTypeDetails -eq "SharedMailbox"} | Sort-Object DisplayName # Accumulate total counts for charts $currentUserCount = $userMailboxes.Count $currentSharedCount = $sharedMailboxes.Count $totalUserMailboxes += $currentUserCount $totalSharedMailboxes += $currentSharedCount $databaseStats += [PSCustomObject]@{ DatabaseName = $dbName UserCount = $currentUserCount SharedCount = $currentSharedCount } # --- Add User Mailboxes Table (Manual HTML Generation) --- # START BLOCK TO REPLACE ConvertTo-Html Write-Host " Generating User Mailbox table (Manual Method)..." -ForegroundColor Gray $bodyContent += "Count: $currentUserCount
" # Add alignment styling directly to TH elements $tableHtml += "| DisplayName | PrimarySmtpAddress | Size (MB) | Last Logon |
|---|---|---|---|
| $displayNameEsc | " $tableHtml += "$smtpAddressEsc | " # Add alignment styling directly to TD elements $tableHtml += "$sizeEsc | " $tableHtml += "$logonEsc | " $tableHtml += "
No user mailboxes found in this database.
" } # END BLOCK TO REPLACE ConvertTo-Html # --- Add Shared Mailboxes Table (Manual HTML Generation) --- # START BLOCK TO REPLACE ConvertTo-Html Write-Host " Generating Shared Mailbox table (Manual Method)..." -ForegroundColor Gray $bodyContent += "Count: $currentSharedCount
" # Add alignment styling directly to TH elements $tableHtml += "| DisplayName | PrimarySmtpAddress | Size (MB) | Last Logon |
|---|---|---|---|
| $displayNameEsc | " $tableHtml += "$smtpAddressEsc | " # Add alignment styling directly to TD elements $tableHtml += "$sizeEsc | " $tableHtml += "$logonEsc | " $tableHtml += "
No shared mailboxes found in this database.
" } # END BLOCK TO REPLACE ConvertTo-Html $dbEndTime = Get-Date Write-Host " Finished processing $dbName in $(($dbEndTime - $dbStartTime).ToString('g'))." -ForegroundColor Green } # End foreach database # --- Add Chart Placeholders and Script --- Write-Host "Generating summary charts..." -ForegroundColor Yellow $bodyContent += "Report generation took: $(($scriptEndTime - $scriptStartTime).ToString('g'))
" # Add duration Write-Host "Generating final HTML report file..." -ForegroundColor Yellow ConvertTo-Html -Head $head -Body $bodyContent -Title "Exchange Database Mailbox Report" | Out-File -FilePath $outputFile -Encoding UTF8 -Force Write-Host "Report saved to $outputFile" -ForegroundColor Green # --- Open the file --- Write-Host "Attempting to open the report..." -ForegroundColor Cyan Invoke-Item -Path $outputFile # Clean up session Write-Host "Removing PSSession..." -ForegroundColor Gray Remove-PSSession $session Write-Host "Script finished successfully in $(($scriptEndTime - $scriptStartTime).ToString('g'))." -ForegroundColor Green } catch { # Log the error details Write-Host "An error occurred:" -ForegroundColor Red Write-Host "Error Message: $($_.Exception.Message)" -ForegroundColor Red # Display Line number if available if ($_.InvocationInfo) { Write-Host "Line Number: $($_.InvocationInfo.ScriptLineNumber)" -ForegroundColor Red # Write-Host "Line Content: $($_.InvocationInfo.Line)" -ForegroundColor Red # Uncomment to see the line content } # Write-Host "Stack Trace: $($_.ScriptStackTrace)" -ForegroundColor DarkGray # Uncomment for full stack trace if needed Write-Host "Script failed." -ForegroundColor Red # Attempt to remove session even if error occurred mid-script if ($PSBoundParameters.ContainsKey('session') -and $session -ne $null -and (Get-PSSession | Where-Object {$_.ID -eq $session.ID})) { Write-Host "Attempting to remove PSSession after error..." -ForegroundColor Yellow Remove-PSSession $session -ErrorAction SilentlyContinue } # Pause script window if running in console host before exit if ($Host.Name -eq 'ConsoleHost') { Read-Host -Prompt "Press Enter to exit" } # Exit with a non-zero code to indicate failure exit 1 } finally { # Any final cleanup that should always run (even after errors, if possible) Write-Progress -Activity "Cleanup" -Completed -ErrorAction SilentlyContinue } ```