Created
January 31, 2024 23:54
-
-
Save bill-long/2f001a7d015a5f955181ec836ac61aa6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Public folder hierarchy and statistics retrieval options | |
## Test scenario | |
# | |
# PF mailboxes in Exchange Online. | |
# | |
# ❯ Get-PublicFolder -Mailbox MB1 -ResidentFolders -Recurse -ResultSize Unlimited | Measure | Select Count | |
# | |
# Count | |
# ----- | |
# 816 | |
# | |
# ❯ Get-PublicFolder -Mailbox MB2 -ResidentFolders -Recurse -ResultSize Unlimited | Measure | Select Count | |
# | |
# Count | |
# ----- | |
# 1112 | |
## | |
## Hierarchy | |
## | |
### | |
### Hierarchy - fastest method | |
### | |
Get-PublicFolder -Recurse -ResultSize Unlimited | Export-Csv test.csv | |
# ❯ Measure-Command { Get-PublicFolder -Recurse -ResultSize Unlimited } | Select TotalMinutes | |
# | |
# TotalMinutes | |
# ------------ | |
# 2.15 | |
### | |
### Hierarchy - slower method with retry | |
### | |
Get-Mailbox -PublicFolder | ForEach-Object { | |
while ($true) { | |
try { | |
Get-PublicFolder -Mailbox $_.Name -Recurse -ResidentFolders -ResultSize Unlimited -ErrorAction Stop | |
break | |
} catch { | |
Write-Host "Error: $($_.Exception.Message)" | |
Write-Host "Retrying in 5 seconds..." | |
Start-Sleep -Seconds 5 | |
} | |
} | |
} | Export-Csv test.csv | |
# ❯ Measure-Command { Get-Mailbox -PublicFolder | ForEach-Object { | |
# > while ($true) { | |
# > try { | |
# > Get-PublicFolder -Mailbox $_.Name -Recurse -ResidentFolders -ResultSize Unlimited -ErrorAction Stop | |
# > break | |
# > } catch { | |
# > Write-Host "Error: $($_.Exception.Message)" | |
# > Write-Host "Retrying in 5 seconds..." | |
# > Start-Sleep -Seconds 5 | |
# > } | |
# > } | |
# > } } | Select TotalMinutes | |
# TotalMinutes | |
# ------------ | |
# 1.44 | |
### | |
### Hierarchy - slowest method with retry | |
### | |
$folderCount = 0 | |
function GetChildren($folder) { | |
while ($true) { | |
try { | |
$children = Get-PublicFolder $folder -GetChildren -ResultSize:Unlimited -ErrorAction Stop | |
break | |
} catch { | |
Write-Warning "Error: $_" | |
Write-Host "Retrying in 5 seconds..." | |
Start-Sleep -Seconds 5 | |
} | |
} | |
$children | ForEach-Object { | |
$_ | |
$folderCount++ | |
if ($folderCount % 10 -eq 0) { | |
Write-Progress -Activity "Getting public folders" -Status "Folders: $folderCount" | |
} | |
GetChildren $_ | |
} | |
} | |
$rootFolder = Get-PublicFolder "\" | |
GetChildren $rootFolder | Export-Csv test.csv | |
# ❯ Measure-Command { $folderCount = 0 | |
# > | |
# > function GetChildren($folder) { | |
# > while ($true) { | |
# > try { | |
# > $children = Get-PublicFolder $folder -GetChildren -ResultSize:Unlimited -ErrorAction Stop | |
# > break | |
# > } catch { | |
# > Write-Warning "Error: $_" | |
# > Write-Host "Retrying in 5 seconds..." | |
# > Start-Sleep -Seconds 5 | |
# > } | |
# > } | |
# > | |
# > $children | ForEach-Object { | |
# > $_ | |
# > $folderCount++ | |
# > if ($folderCount % 10 -eq 0) { | |
# > Write-Progress -Activity "Getting public folders" -Status "Folders: $folderCount" | |
# > } | |
# > | |
# > GetChildren $_ | |
# > } | |
# > } | |
# > | |
# > $rootFolder = Get-PublicFolder "\" | |
# > GetChildren $rootFolder } | Select TotalMinutes | |
# | |
# TotalMinutes | |
# ------------ | |
# 48.89 | |
## | |
## Statistics | |
## | |
### | |
### Statistics - fastest method | |
### | |
Get-PublicFolderStatistics -ResultSize Unlimited | Select-Object @{Name = "FolderPath"; Expression = { $_.FolderPath -join "\" } }, ItemCount, @{Name = "TotalItemSizeMB"; Expression = { [math]::Round(($_.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",", "") / 1MB), 2) } } | Export-Csv test.csv | |
# ❯ Measure-Command { Get-PublicFolderStatistics -ResultSize Unlimited } | Select TotalMinutes | |
# | |
# TotalMinutes | |
# ------------ | |
# 8.48 | |
### | |
### Statistics - slower method with retry | |
### | |
Get-Mailbox -PublicFolder | ForEach-Object { | |
while ($true) { | |
try { | |
Write-Host "$(Get-Date) Getting statistics for $($_.Name)" | |
$stats = Get-PublicFolder -Mailbox $_.Name -ResidentFolders -Recurse -ResultSize Unlimited -ErrorAction Stop | Get-PublicFolderStatistics -ErrorAction Stop | |
Write-Host "$(Get-Date) Found $($stats.Count) public folders in mailbox $($_.Name)" | |
break | |
} catch { | |
Write-Host "Error: $($_.Exception.Message)" | |
Write-Host "Retrying in 5 seconds..." | |
Start-Sleep -Seconds 5 | |
} | |
} | |
} | Select-Object @{Name = "FolderPath"; Expression = { $_.FolderPath -join "\" } }, ItemCount, @{Name = "TotalItemSizeMB"; Expression = { [math]::Round(($_.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",", "") / 1MB), 2) } } | Export-Csv test.csv | |
# ❯ Measure-Command { Get-Mailbox -PublicFolder | ForEach-Object { | |
# > while ($true) { | |
# > try { | |
# > Write-Host "$(Get-Date) Getting statistics for $($_.Name)" | |
# > $stats = Get-PublicFolder -Mailbox $_.Name -ResidentFolders -Recurse -ResultSize Unlimited -ErrorAction Stop | Get-PublicFolderStatistics -ErrorAction Stop | |
# > Write-Host "$(Get-Date) Found $($stats.Count) public folders in mailbox $($_.Name)" | |
# > break | |
# > } catch { | |
# > Write-Host "Error: $($_.Exception.Message)" | |
# > Write-Host "Retrying in 5 seconds..." | |
# > Start-Sleep -Seconds 5 | |
# > } | |
# > } | |
# > } } | Select TotalMinutes | |
# 01/31/2024 15:30:51 Getting statistics for MB1 | |
# 01/31/2024 15:54:36 Found 816 public folders in mailbox MB1 | |
# 01/31/2024 15:54:36 Getting statistics for MB2 | |
# 01/31/2024 16:27:40 Found 1112 public folders in mailbox MB2 | |
# | |
# TotalMinutes | |
# ------------ | |
# 56.83 | |
# Note this is not any better than calling Get-PublicFolderStatistics once per folder: | |
# | |
# ❯ Measure-Command { Get-PublicFolder -Recurse -ResultSize Unlimited | % { Get-PublicFolderStatistics $_ } } | Select TotalMinutes | |
# | |
# TotalMinutes | |
# ------------ | |
# 60.29 | |
### | |
### Statistics - slowest method with retry | |
### | |
$folderCount = 0 | |
function GetChildren($folder) { | |
while ($true) { | |
try { | |
$children = Get-PublicFolder $folder -GetChildren -ResultSize:Unlimited -ErrorAction Stop | |
break | |
} catch { | |
Write-Warning "Error: $_" | |
Write-Host "Retrying in 5 seconds..." | |
Start-Sleep -Seconds 5 | |
} | |
} | |
$children | ForEach-Object { | |
while ($true) { | |
try { | |
$_ | Get-PublicFolderStatistics -ErrorAction Stop | |
} catch { | |
Write-Warning "Error: $_" | |
Write-Host "Retrying in 5 seconds..." | |
Start-Sleep -Seconds 5 | |
} | |
} | |
$folderCount++ | |
if ($folderCount % 10 -eq 0) { | |
Write-Progress -Activity "Getting public folders" -Status "Folders: $folderCount" | |
} | |
GetChildren $_ | |
} | |
} | |
$rootFolder = Get-PublicFolder "\" | |
GetChildren $rootFolder | Select-Object @{Name = "FolderPath"; Expression = { $_.FolderPath -join "\" } }, ItemCount, @{Name = "TotalItemSizeMB"; Expression = { [math]::Round(($_.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",", "") / 1MB), 2) } } | Export-Csv test.csv | |
# Did not run this test. The previous test took an hour, and this would take longer | |
# due to the manual traversal, with little benefit I think. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment