Skip to content

Instantly share code, notes, and snippets.

@bill-long
Created January 31, 2024 23:54
Show Gist options
  • Save bill-long/2f001a7d015a5f955181ec836ac61aa6 to your computer and use it in GitHub Desktop.
Save bill-long/2f001a7d015a5f955181ec836ac61aa6 to your computer and use it in GitHub Desktop.
# 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