$server = Get-Content -Path ".\DefaultServer.txt" $credential = Import-Clixml -Path ".\AdminCredential.xml" # Create remote PowerShell session $session = $null # Initialize session variable try { Write-Host "Attempting to create remote PowerShell session to $server..." $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$server/PowerShell/" -Credential $credential -Authentication Kerberos -ErrorAction Stop Import-PSSession $session -DisableNameChecking -ErrorAction Stop Write-Host "Session created and imported successfully." } catch { Write-Error "Failed to create or import remote PowerShell session: $($_.Exception.Message)" return } # --- Helper Functions (Unchanged) --- # Function to display formatted size values without bytes function Get-FormattedSize { param ([string]$sizeString) if ([string]::IsNullOrWhiteSpace($sizeString)) { return "N/A" } # Match pattern like "1.23 GB (1320702443 bytes)" if ($sizeString -match "^(.*?) \(") { return $matches[1].Trim() } # Match pattern like "1.23 GB" if the bytes part is missing elseif ($sizeString -match "(\d+(\.\d+)? (GB|TB|MB|KB))$") { return $matches[1].Trim() } else { Write-Verbose "Could not parse size string: $sizeString"; return $sizeString } } # Helper function to convert size string (e.g., "1.5 GB") to GB (for calculation/charting) function ConvertTo-GB { param ( [Parameter(Mandatory=$true)] [string]$sizeStr ) $value = $null $unit = $null # Try parsing the 'Value (Bytes)' format first if ($sizeStr -match "^(.*?) \((\d+) bytes\)") { $readablePart = $matches[1].Trim() # Now parse the readable part if ($readablePart -match "(\d+(\.\d+)?)\s*(GB|TB|MB|KB)") { # Added \s* for flexibility $value = [double]$matches[1] $unit = $matches[3] # Fall through to switch } else { Write-Warning "Could not parse readable part '$readablePart' from '$sizeStr' for GB conversion." return $null } } elseif ($sizeStr -match "(\d+(\.\d+)?)\s*(GB|TB|MB|KB)") { # Added \s* for flexibility # Handle cases where the string might *only* be the size $value = [double]$matches[1] $unit = $matches[3] # Fall through to switch } else { Write-Warning "Could not parse size string '$sizeStr' for GB conversion." return $null # Indicate conversion failure } # Perform conversion based on unit try { switch ($unit) { "TB" { return $value * 1024 } "GB" { return $value } "MB" { return $value / 1024 } "KB" { return $value / (1024*1024) } Default { return $null } # Should not happen with regex, but good practice } } catch { Write-Warning "Error converting value '$value' ($unit) to GB from string '$sizeStr': $($_.Exception.Message)" return $null } } # Function to calculate whitespace percentage correctly function Calculate-WhitespacePercentage { param ( [Parameter(Mandatory=$true)] [string]$totalSizeString, # Expects format like "1.25 GB" [Parameter(Mandatory=$true)] [string]$whitespaceString # Expects format like "500 MB" ) $totalValueGB = ConvertTo-GB -sizeStr $totalSizeString $whitespaceValueGB = ConvertTo-GB -sizeStr $whitespaceString if ($null -ne $totalValueGB -and $null -ne $whitespaceValueGB -and $totalValueGB -gt 0) { # Ensure whitespace isn't negative or larger than total (can happen with calculation delays) $whitespaceValueGB = [System.Math]::Max(0, $whitespaceValueGB) $whitespaceValueGB = [System.Math]::Min($totalValueGB, $whitespaceValueGB) $percentage = ($whitespaceValueGB / $totalValueGB) * 100 return "{0:N2}" -f $percentage } elseif ($null -eq $totalValueGB) { return "N/A (Total Size Error)" } elseif ($null -eq $whitespaceValueGB) { return "N/A (Whitespace Error)" } elseif ($totalValueGB -le 0) { return "N/A (Zero Total Size)" } else { return "N/A (Calculation Error)" } } # --- End Helper Functions --- # Retrieve mailbox database details Write-Host "Retrieving mailbox database status..." $databases = Get-MailboxDatabase -Status -ErrorAction SilentlyContinue if (-not $databases) { Write-Warning "No mailbox databases found or error retrieving them." if ($session -ne $null) { Remove-PSSession $session } return } # Initialize arrays for chart data $chartDbNames = @() $chartDbSizesGB = @() $dbSizeDataForSorting = @() # Array of objects for sorting # Get Report Generation Date $reportGeneratedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" # --- Start building HTML report --- # Using the new CSS styles provided $html = @"
| Name | Server | Mounted | Total Size | Whitespace | Whitespace (%) | Mailbox Count | Last Full Backup | Circular Logging |
|---|---|---|---|---|---|---|---|---|
| $($dbName) | $($dbServer) | $($dbMounted) | $($totalSizeFormatted) | $($whitespaceFormatted) | $($whitespacePercent) % | $($mailboxCount) | $($lastBackup) | $($dbCircular) |
No valid database size data available to generate charts.
"@ } # --- End Chart Generation Logic --- # Complete the HTML report structure $html += @" "@ # Save the HTML report (NO CHANGES IN THIS SECTION) $outputDirectory = Join-Path -Path $env:USERPROFILE -ChildPath "Downloads" if (-not (Test-Path -Path $outputDirectory -PathType Container)) { Write-Warning "Downloads directory not found at '$outputDirectory'." try { Write-Host "Attempting to create directory: $outputDirectory" New-Item -Path $outputDirectory -ItemType Directory -Force -ErrorAction Stop | Out-Null Write-Host "Directory created successfully." } catch { Write-Error "Could not create output directory '$outputDirectory': $($_.Exception.Message)" $outputDirectory = $PSScriptRoot Write-Warning "Attempting to save report to script directory: $outputDirectory" if (-not (Test-Path -Path $outputDirectory -PathType Container)) { $outputDirectory = $PWD.Path Write-Warning "Script directory not found. Falling back to current directory: $outputDirectory" if (-not (Test-Path -Path $outputDirectory -PathType Container)) { Write-Error "Fallback directory $outputDirectory also not found. Cannot save report." if ($session -ne $null) { Remove-PSSession $session } exit 1 } } } } $reportFileName = "ExchangeDatabaseSizeReport(Navitas).html" $outputFile = Join-Path -Path $outputDirectory -ChildPath $reportFileName try { [System.IO.File]::WriteAllText($outputFile, $html, [System.Text.UTF8Encoding]::new($false)) # UTF8 without BOM Write-Host "Report successfully saved to $outputFile" # Invoke-Item $outputFile } catch { Write-Error "Failed to save HTML report to '$outputFile': $($_.Exception.Message)" } # Clean up the remote session (NO CHANGES IN THIS SECTION) if ($session -ne $null -and $session.State -eq 'Opened') { Write-Host "Removing remote PowerShell session..." Remove-PSSession $session } elseif ($session -ne $null) { Write-Warning "Session state is $($session.State). Attempting removal anyway." Remove-PSSession $session -ErrorAction SilentlyContinue } Write-Host "Script finished."