Last active
July 5, 2018 00:15
Star
You must be signed in to star a gist
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
# AlternateMailboxMapGenerator.ps1 | |
# by bilong@microsoft.com | |
# An alternative to PublicFolderToMailboxMapGenerator.ps1 | |
param($sizeLimit, $inputFile, $outputFile) | |
Add-Type @" | |
using System; | |
using System.Collections.Generic; | |
public class FolderInfo { | |
public string Path; | |
public long AggregateSize; | |
public FolderInfo(string path, long size) { | |
this.Path = path; | |
this.AggregateSize = size; | |
} | |
} | |
"@ | |
function UpdateAggregateSizesForPath($path, $difference) | |
{ | |
$pathSplit = $path.Split(@('\')) | |
$parentPath = $path | |
for ($x = 1; $x -lt $pathSplit.Length; $x++) | |
{ | |
$parentPath = $parentPath.Substring(0, $parentPath.LastIndexOf('\')) | |
if ($folderInfos.ContainsKey($parentPath)) | |
{ | |
$folderInfos[$parentPath].AggregateSize += $difference | |
} | |
} | |
} | |
$folderInfos = New-Object 'System.Collections.Generic.Dictionary[string, FolderInfo]' | |
$rootFolder = New-Object FolderInfo("", 0) | |
$folderInfos.Add($rootFolder.Path, $rootFolder) | |
Write-Host "Reading folder sizes from CSV..." | |
$folderSizes = Import-Csv $inputFile | |
foreach ($sizeInfo in $folderSizes) | |
{ | |
$newFolder = New-Object FolderInfo($sizeInfo.FolderName, $sizeInfo.FolderSize) | |
UpdateAggregateSizesForPath $sizeInfo.FolderName $sizeInfo.FolderSize | |
$folderInfos.Add($newFolder.Path, $newFolder) | |
} | |
Write-Host $folderInfos.Keys.Count " folders." | |
Write-Host $folderInfos[""].AggregateSize " total bytes." | |
if ($folderInfos.Keys.Count -lt 2) | |
{ | |
return | |
} | |
$currentMailboxNumber = 2 | |
$alreadyMapped = New-Object 'System.Collections.Generic.Dictionary[string, bool]' | |
$mailboxSizes = New-Object 'System.Collections.Generic.Dictionary[int, long]' | |
$mailboxSizes.Add(2, 0) | |
$mailboxFolderMap = New-Object 'System.Collections.Generic.Dictionary[int, System.Collections.Generic.List[string]]' | |
$mailboxFolderMap.Add(2, (New-Object 'System.Collections.Generic.List[string]')) | |
$folderStack = New-Object 'System.Collections.Generic.Stack[FolderInfo]' | |
$sortedPaths = New-Object 'System.Collections.Generic.List[string]' | |
$sortedPaths.AddRange($folderInfos.Keys) | |
$sortedPaths.Sort([StringComparer]::Ordinal) | |
for ($x = 0; $x -lt $sortedPaths.Count; $x++) | |
{ | |
$path = $sortedPaths[$x] | |
if ($alreadyMapped.ContainsKey($path.Substring(0, $path.LastIndexOf('\') + 1))) | |
{ | |
# Parent is already mapped, so this one is too. | |
$alreadyMapped.Add($path + "\", $true) | |
continue | |
} | |
if ($folderStack.Count -gt 0 -and $folderStack.Peek().AggregateSize -lt $sizeLimit) | |
{ | |
$currentFolder = $folderStack.Pop() | |
$x-- | |
} | |
elseif ($folderStack.Count -gt 0 -and !$path.StartsWith($folderStack.Peek().Path)) | |
{ | |
# The parent folder on the stack has no more children, but it's still too big. | |
# Put it in a new mailbox and log a warning. | |
$currentFolder = $folderStack.Pop() | |
$currentMailboxNumber++ | |
$newMappedFolderList = New-Object 'System.Collections.Generic.List[string]' | |
$newMappedFolderList.Add($currentFolder.Path) | |
$mailboxFolderMap.Add($currentMailboxNumber, $newMappedFolderList) | |
"WARNING. Folder is too big and has been assigned to a mailbox of its own." | |
" Folder: " + $currentFolder.Path | |
" Size: " + $currentFolder.AggregateSize | |
UpdateAggregateSizesForPath $currentFolder.Path $currentFolder.AggregateSize | |
$alreadyMapped.Add($currentFolder.Path + "\", $true) | |
$x-- | |
continue | |
} | |
else | |
{ | |
$currentFolder = $folderInfos[$path] | |
} | |
# If this folder exceeds the limit, try to split it up | |
if ($currentFolder.AggregateSize -gt $sizeLimit) | |
{ | |
$folderStack.Push($currentFolder) | |
} | |
else | |
{ | |
# This folder is under the limit. | |
# Will it fit in the current mailbox? | |
if ($mailboxSizes[$currentMailboxNumber] + $currentFolder.AggregateSize -lt $sizeLimit) | |
{ | |
$mailboxFolderMap[$currentMailboxNumber].Add($currentFolder.Path) | |
$mailboxSizes[$currentMailboxNumber] += $currentFolder.AggregateSize | |
} | |
else | |
{ | |
# Start a new mailbox | |
$currentMailboxNumber++ | |
$newMappedFolderList = New-Object 'System.Collections.Generic.List[string]' | |
$newMappedFolderList.Add($currentFolder.Path) | |
$mailboxFolderMap.Add($currentMailboxNumber, $newMappedFolderList) | |
$mailboxSizes.Add($currentMailboxNumber, $currentFolder.AggregateSize) | |
} | |
UpdateAggregateSizesForPath $currentFolder.Path (0 - $currentFolder.AggregateSize) | |
$alreadyMapped.Add($currentFolder.Path + "\", $true) | |
} | |
} | |
Set-Content $outputFile "FolderPath,TargetMailbox" | |
Add-Content $outputFile "\,Mailbox1" | |
$sortedMailboxNumbers = $mailboxFolderMap.Keys | Sort | |
foreach ($mailboxNumber in $sortedMailboxNumbers) | |
{ | |
foreach ($folderPath in $mailboxFolderMap[$mailboxNumber] | Sort) | |
{ | |
if ($folderPath -eq "") { | |
continue | |
} | |
Add-Content $outputFile "$folderPath,Mailbox$mailboxNumber" | |
} | |
} | |
"Done!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment