Skip to content

Instantly share code, notes, and snippets.

@bill-long
Last active July 5, 2018 00:15
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save bill-long/2806c97e9df4b7252cb889d8c1170392 to your computer and use it in GitHub Desktop.
# 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