Public/Get-O365MailboxUsage.ps1
function Get-O365MailboxUsage { <# .SYNOPSIS Retrieves Office 365 mailbox usage statistics showing storage utilization and percentage full. .DESCRIPTION This function connects to Exchange Online and retrieves mailbox statistics including current usage, total quota, and percentage full. Results are sorted by highest usage percentage by default. Can process specific users from pipeline input or return all mailboxes. .PARAMETER UserPrincipalName Specific user principal name (email address) to retrieve statistics for. Can accept pipeline input. .PARAMETER SortBy Property to sort results by. Valid values: PercentFull, UsedSpaceGB, TotalQuotaGB, DisplayName Default is PercentFull (descending). .PARAMETER IncludeArchive Include archive mailbox statistics if available. .EXAMPLE Get-O365MailboxUsage Returns all mailboxes sorted by percentage full (highest first). .EXAMPLE "user@domain.com" | Get-O365MailboxUsage Returns statistics for specific user from pipeline input. .EXAMPLE Get-O365MailboxUsage -SortBy UsedSpaceGB -IncludeArchive Returns all mailboxes sorted by used space including archive statistics. .NOTES Requires Exchange Online PowerShell module and appropriate permissions. Run Connect-ExchangeOnline before using this function. #> [CmdletBinding()] param( [Parameter( ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias("Identity", "PrimarySmtpAddress", "Email")] [string[]]$UserPrincipalName, [Parameter()] [ValidateSet("PercentFull", "UsedSpaceGB", "TotalQuotaGB", "DisplayName")] [string]$SortBy = "PercentFull", [Parameter()] [switch]$IncludeArchive ) begin { # Check if Exchange Online module is available and connected try { $connectionStatus = Get-ConnectionInformation -ErrorAction Stop if (-not $connectionStatus) { throw "Not connected to Exchange Online" } } catch { Write-Error "Exchange Online connection required. Please run Connect-ExchangeOnline first." return } Write-Verbose "Connected to Exchange Online: $($connectionStatus.Name)" # Initialize collection for results $results = @() # Function to convert bytes to GB with proper formatting function ConvertTo-GB { param([string]$SizeString) if ([string]::IsNullOrEmpty($SizeString) -or $SizeString -eq "Unlimited") { return 0 } # Extract numeric value and convert to GB if ($SizeString -match '([\d,]+\.?\d*)\s*([KMGT]?B)') { $value = [double]($matches[1] -replace ',', '') $unit = $matches[2] switch ($unit) { "TB" { return [math]::Round($value * 1024, 2) } "GB" { return [math]::Round($value, 2) } "MB" { return [math]::Round($value / 1024, 2) } "KB" { return [math]::Round($value / 1048576, 2) } "B" { return [math]::Round($value / 1073741824, 2) } default { return [math]::Round($value, 2) } } } return 0 } # Function to process mailbox statistics function ProcessMailboxStats { param( [object]$Mailbox, [object]$Stats, [object]$ArchiveStats = $null ) # Convert sizes to GB $usedSpaceGB = ConvertTo-GB -SizeString $Stats.TotalItemSize $totalQuotaGB = ConvertTo-GB -SizeString $Stats.ProhibitSendReceiveQuota # Calculate percentage full (avoid division by zero) $percentFull = if ($totalQuotaGB -gt 0) { [math]::Round(($usedSpaceGB / $totalQuotaGB) * 100, 1) } else { 0 } # Create result object $result = [PSCustomObject]@{ DisplayName = $Mailbox.DisplayName UserPrincipalName = $Mailbox.PrimarySmtpAddress UsedSpaceGB = $usedSpaceGB TotalQuotaGB = $totalQuotaGB PercentFull = $percentFull ItemCount = $Stats.ItemCount LastLogonTime = $Stats.LastLogonTime MailboxType = $Mailbox.RecipientTypeDetails } # Add archive information if requested and available if ($IncludeArchive -and $ArchiveStats) { $archiveUsedGB = ConvertTo-GB -SizeString $ArchiveStats.TotalItemSize $archiveTotalGB = ConvertTo-GB -SizeString $ArchiveStats.ProhibitSendReceiveQuota $archivePercentFull = if ($archiveTotalGB -gt 0) { [math]::Round(($archiveUsedGB / $archiveTotalGB) * 100, 1) } else { 0 } $result | Add-Member -NotePropertyName "ArchiveUsedSpaceGB" -NotePropertyValue $archiveUsedGB $result | Add-Member -NotePropertyName "ArchiveTotalQuotaGB" -NotePropertyValue $archiveTotalGB $result | Add-Member -NotePropertyName "ArchivePercentFull" -NotePropertyValue $archivePercentFull $result | Add-Member -NotePropertyName "ArchiveItemCount" -NotePropertyValue $ArchiveStats.ItemCount } return $result } } process { try { # Determine which mailboxes to process if ($UserPrincipalName) { # Process specific users from pipeline or parameter foreach ($upn in $UserPrincipalName) { Write-Verbose "Processing mailbox: $upn" # Get mailbox information $mailbox = Get-Mailbox -Identity $upn -ErrorAction Stop # Get mailbox statistics $stats = Get-MailboxStatistics -Identity $upn -ErrorAction Stop # Get archive statistics if requested $archiveStats = $null if ($IncludeArchive -and $mailbox.ArchiveStatus -eq "Active") { try { $archiveStats = Get-MailboxStatistics -Identity $upn -Archive -ErrorAction Stop } catch { Write-Warning "Could not retrieve archive statistics for $upn : $($_.Exception.Message)" } } # Process and add to results $result = ProcessMailboxStats -Mailbox $mailbox -Stats $stats -ArchiveStats $archiveStats $results += $result } } else { # Get all mailboxes Write-Verbose "Retrieving all mailboxes..." $mailboxes = Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox, SharedMailbox, RoomMailbox, EquipmentMailbox $totalCount = $mailboxes.Count $currentCount = 0 foreach ($mailbox in $mailboxes) { $currentCount++ $percentComplete = [math]::Round(($currentCount / $totalCount) * 100, 0) Write-Progress -Activity "Processing mailboxes" -Status "Processing $($mailbox.DisplayName) ($currentCount of $totalCount)" -PercentComplete $percentComplete Write-Verbose "Processing mailbox: $($mailbox.PrimarySmtpAddress)" try { # Get mailbox statistics $stats = Get-MailboxStatistics -Identity $mailbox.PrimarySmtpAddress -ErrorAction Stop # Get archive statistics if requested $archiveStats = $null if ($IncludeArchive -and $mailbox.ArchiveStatus -eq "Active") { try { $archiveStats = Get-MailboxStatistics -Identity $mailbox.PrimarySmtpAddress -Archive -ErrorAction Stop } catch { Write-Warning "Could not retrieve archive statistics for $($mailbox.PrimarySmtpAddress): $($_.Exception.Message)" } } # Process and add to results $result = ProcessMailboxStats -Mailbox $mailbox -Stats $stats -ArchiveStats $archiveStats $results += $result } catch { Write-Warning "Could not retrieve statistics for $($mailbox.PrimarySmtpAddress): $($_.Exception.Message)" } } Write-Progress -Activity "Processing mailboxes" -Completed } } catch { Write-Error "Error processing mailbox statistics: $($_.Exception.Message)" return } } end { if ($results.Count -eq 0) { Write-Warning "No mailbox statistics retrieved." return } Write-Verbose "Retrieved statistics for $($results.Count) mailboxes" # Sort results based on specified property switch ($SortBy) { "PercentFull" { $sortedResults = $results | Sort-Object PercentFull -Descending } "UsedSpaceGB" { $sortedResults = $results | Sort-Object UsedSpaceGB -Descending } "TotalQuotaGB" { $sortedResults = $results | Sort-Object TotalQuotaGB -Descending } "DisplayName" { $sortedResults = $results | Sort-Object DisplayName } default { $sortedResults = $results | Sort-Object PercentFull -Descending } } # Output results to pipeline Write-Output $sortedResults $stamp = Get-Date -Format 'yyyyMMdd_HHmmss' export-csv $sortedResults -Path "C:\Temp\$stamp-O365MailboxUsage.csv" -NoTypeInformation -Encoding UTF8 } } Export-ModuleMember -Function Get-O365MailboxUsage |