Public/Get-Mailbox.ps1
|
function Get-Mailbox { #Requires -Version 5.1 <# .SYNOPSIS Lists domain user mailboxes with storage and message counts. .DESCRIPTION Queries Google Workspace via GAM to produce a per-user mailbox summary including availability status, last login, storage usage, and message count. .PARAMETER Email Optional mailbox email address (or addresses). When provided, only those mailboxes are returned. .OUTPUTS PSCustomObject with Email, Suspended, Archived, LastLogin, MailboxMB, MailboxDisplay, Messages, and StorageDate properties. .EXAMPLE Get-Mailbox | Sort-Object Email | Format-Table -AutoSize .EXAMPLE Get-Mailbox | Where-Object { -not $_.Suspended -and -not $_.Archived } | Measure-Object MailboxMB -Sum .EXAMPLE Get-Mailbox -Email stephen.tracy@northone.com #> [CmdletBinding()] param( [Parameter()] [string[]] $Email ) $activity = 'Get-Mailbox' $requestedEmails = @($Email | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $_.Trim().ToLowerInvariant() } | Sort-Object -Unique) $filteringByEmail = $requestedEmails.Count -gt 0 $newMailboxRecord = { param( [object] $User, [object] $MailboxMB, [object] $Messages, [string] $StorageDate ) $mb = if ($null -ne $MailboxMB -and $MailboxMB -ne '') { [double]$MailboxMB } else { 0 } [PSCustomObject]@{ Email = $User.primaryEmail Suspended = $User.suspended -eq 'True' Archived = $User.archived -eq 'True' LastLogin = if ($User.lastLoginTime -eq 'Never' -or [string]::IsNullOrEmpty($User.lastLoginTime)) { 'Never' } else { ([datetime]$User.lastLoginTime).ToString('yyyy-MM-dd') } MailboxMB = $mb MailboxDisplay = if ($mb -gt 1024) { '{0:N1} GB' -f ($mb / 1024) } elseif ($mb -gt 0) { '{0:N0} MB' -f $mb } else { '-' } Messages = $Messages StorageDate = if ([string]::IsNullOrWhiteSpace($StorageDate)) { '-' } else { $StorageDate } } } if ($filteringByEmail) { Write-Progress -Activity $activity -Status "Fetching selected users ($($requestedEmails.Count))..." -PercentComplete 10 $users = @() for ($i = 0; $i -lt $requestedEmails.Count; $i++) { $target = $requestedEmails[$i] $pct = 10 + [int](15 * (($i + 1) / [Math]::Max($requestedEmails.Count, 1))) Write-Progress -Activity $activity -Status "Fetching selected users ($($i + 1)/$($requestedEmails.Count))..." -PercentComplete $pct $rows = @(& gam print users query "email:$target" fields primaryEmail,suspended,archived,lastLoginTime 2>$null | ConvertFrom-Csv) if ($rows.Count -eq 0) { Write-Warning "User not found: $target" continue } $match = @($rows | Where-Object { $_.primaryEmail -ieq $target }) if ($match.Count -gt 0) { $users += $match[0] } else { $users += $rows[0] } } } else { Write-Progress -Activity $activity -Status 'Fetching domain users...' -PercentComplete 10 $users = @(& gam print users fields primaryEmail,suspended,archived,lastLoginTime 2>$null | ConvertFrom-Csv) } if ($users.Count -eq 0) { Write-Warning 'No matching users found.' Write-Progress -Activity $activity -Completed return } if ($filteringByEmail) { Write-Progress -Activity $activity -Status "Fetching storage reports for $($users.Count) mailbox(es)..." -PercentComplete 30 $mbLookup = @{} $storageDateLookup = @{} for ($i = 0; $i -lt $users.Count; $i++) { $user = $users[$i] $pct = 30 + [int](30 * (($i + 1) / [Math]::Max($users.Count, 1))) Write-Progress -Activity $activity -Status "Fetching storage reports ($($i + 1)/$($users.Count))..." -PercentComplete $pct $rows = @(& gam report users user $user.primaryEmail parameters accounts:gmail_used_quota_in_mb 2>$null | ConvertFrom-Csv) if ($rows.Count -eq 0) { continue } $latest = $rows | Sort-Object date -Descending | Select-Object -First 1 if ($null -ne $latest) { $mbLookup[$user.primaryEmail] = [double]$latest.'accounts:gmail_used_quota_in_mb' $storageDateLookup[$user.primaryEmail] = [string]$latest.date } } Write-Progress -Activity $activity -Status "Fetching Gmail profiles for $($users.Count) mailbox(es)..." -PercentComplete 60 $msgLookup = @{} for ($i = 0; $i -lt $users.Count; $i++) { $user = $users[$i] $pct = 60 + [int](30 * (($i + 1) / [Math]::Max($users.Count, 1))) Write-Progress -Activity $activity -Status "Fetching Gmail profiles ($($i + 1)/$($users.Count))..." -PercentComplete $pct $profileRows = @(& gam user $user.primaryEmail print gmailprofile 2>$null | ConvertFrom-Csv) if ($profileRows.Count -gt 0) { $msgLookup[$user.primaryEmail] = [int]$profileRows[0].messagesTotal } } Write-Progress -Activity $activity -Status 'Building results...' -PercentComplete 95 for ($i = 0; $i -lt $users.Count; $i++) { $user = $users[$i] if ((($i + 1) % 200 -eq 0) -or ($i + 1 -eq $users.Count)) { $percent = 95 + [int](4 * (($i + 1) / [Math]::Max($users.Count, 1))) Write-Progress -Activity $activity -Status "Building results ($($i + 1)/$($users.Count))..." -PercentComplete $percent } & $newMailboxRecord -User $user -MailboxMB $mbLookup[$user.primaryEmail] -Messages $msgLookup[$user.primaryEmail] -StorageDate $storageDateLookup[$user.primaryEmail] } Write-Progress -Activity $activity -Completed return } # All-mailbox mode Write-Progress -Activity $activity -Status 'Fetching mailbox storage report (may take ~60s)...' -PercentComplete 30 $storageRaw = & gam report users parameters accounts:gmail_used_quota_in_mb 2>$null | ConvertFrom-Csv $latestDate = ($storageRaw | Sort-Object date -Descending | Select-Object -First 1).date $storageDay = @($storageRaw | Where-Object { $_.date -eq $latestDate }) $mbLookup = @{} foreach ($r in $storageDay) { $mbLookup[$r.email] = [double]$r.'accounts:gmail_used_quota_in_mb' } Write-Progress -Activity $activity -Status "Fetching Gmail profiles for $($users.Count) mailboxes (batched via GAM)..." -PercentComplete 70 $profileStart = 70 $profileEnd = 90 $profileRaw = @() $stderrLines = @() $currentProfiles = 0 $totalProfiles = [Math]::Max($users.Count, 1) $profileStdOut = Join-Path ([System.IO.Path]::GetTempPath()) ("gam-gmailprofile-{0}.csv" -f [guid]::NewGuid()) $profileStdErr = Join-Path ([System.IO.Path]::GetTempPath()) ("gam-gmailprofile-{0}.log" -f [guid]::NewGuid()) try { $gamPath = (Get-Command gam -ErrorAction Stop).Source $proc = Start-Process -FilePath $gamPath ` -ArgumentList @('all', 'users', 'print', 'gmailprofile') ` -PassThru ` -RedirectStandardOutput $profileStdOut ` -RedirectStandardError $profileStdErr $sw = [System.Diagnostics.Stopwatch]::StartNew() while (-not $proc.HasExited) { $tail = @(Get-Content -Path $profileStdErr -Tail 25 -ErrorAction SilentlyContinue) $line = $tail | Select-String -Pattern '^Getting Gmail Profile for .+\((\d+)\/(\d+)\)$' | Select-Object -Last 1 if ($line) { $m = [regex]::Match($line.Line, '\((\d+)\/(\d+)\)$') if ($m.Success) { $currentProfiles = [int]$m.Groups[1].Value $totalProfiles = [Math]::Max([int]$m.Groups[2].Value, 1) } } $percent = $profileStart + [int](($profileEnd - $profileStart) * ($currentProfiles / [double]$totalProfiles)) $elapsed = '{0:mm\:ss}' -f $sw.Elapsed Write-Progress -Activity $activity ` -Status "Fetching Gmail profiles for $($users.Count) mailboxes (batched via GAM)... elapsed $elapsed" ` -PercentComplete $percent Start-Sleep -Milliseconds 300 $proc.Refresh() } $stderrLines = @(Get-Content -Path $profileStdErr -ErrorAction SilentlyContinue) foreach ($line in $stderrLines) { $trimmed = $line.Trim() if ($trimmed -match '^User:\s+.+,\s+Gmail Service/App not enabled') { Write-Verbose $trimmed } } $stdoutLines = @(Get-Content -Path $profileStdOut -ErrorAction SilentlyContinue) if ($stdoutLines.Count -gt 0) { $profileRaw = $stdoutLines | ConvertFrom-Csv } if (($proc.ExitCode -ne 0) -and ($profileRaw.Count -eq 0)) { Write-Warning "GAM returned exit code $($proc.ExitCode) while fetching Gmail profiles." } } finally { Remove-Item -Path $profileStdOut, $profileStdErr -Force -ErrorAction SilentlyContinue } $currentProfiles = if ($currentProfiles -gt 0) { $currentProfiles } else { $profileRaw.Count } Write-Progress -Activity $activity ` -Status "Fetched Gmail profiles for $($users.Count) mailboxes (received $($profileRaw.Count))..." ` -PercentComplete $profileEnd Write-Verbose "Fetched Gmail profiles for $($profileRaw.Count) of $($users.Count) users." $msgLookup = @{} for ($i = 0; $i -lt $profileRaw.Count; $i++) { $r = $profileRaw[$i] if ((($i + 1) % 100 -eq 0) -or ($i + 1 -eq $profileRaw.Count)) { $percent = $profileEnd + [int](5 * (($i + 1) / [Math]::Max($profileRaw.Count, 1))) Write-Progress -Activity $activity -Status "Indexing message counts ($($i + 1)/$($profileRaw.Count))..." -PercentComplete $percent } $msgLookup[$r.emailAddress] = [int]$r.messagesTotal } Write-Progress -Activity $activity -Status 'Building results...' -PercentComplete 95 for ($j = 0; $j -lt $users.Count; $j++) { $user = $users[$j] if ((($j + 1) % 200 -eq 0) -or ($j + 1 -eq $users.Count)) { $percent = 95 + [int](4 * (($j + 1) / [Math]::Max($users.Count, 1))) Write-Progress -Activity $activity -Status "Building results ($($j + 1)/$($users.Count))..." -PercentComplete $percent } & $newMailboxRecord -User $user -MailboxMB $mbLookup[$user.primaryEmail] -Messages $msgLookup[$user.primaryEmail] -StorageDate $latestDate } Write-Progress -Activity $activity -Completed } |