Understand and script the Get-MailboxFolderStatistics cmdlet

This blog post is going to give you some insight on how you can script the Get-MailboxFolderStatistics cmdlet, but also how to understand it’s output, as well as how is it important to plan a mailbox migration project.

Why are the mailbox folder statistics important to plan a migration project?

That is indeed the first thing you need to consider: Why do I need those statistics? To better answer that let me start by showing you an output of the command.

1

What you see above is the output of a mailbox, where I filtered the Folder Path, the number of items in the folder and sub folders, as well as the size of each folder. So let me bullet point why is this important for a migration project planning:

  • It will give you item counts per user and per item type (Mail, calendar, contacts). Those numbers are important, specially if extremely large, to estimate migration timelines when using the Bittitan MigrationWiz mailbox migration.
  • It will show you the size of every folder as well as the entire mailbox size. This is important to identify which folders are larger on a very big mailbox. I’ve seen examples of some of those folder being considered irrelevant for a migration (i.e deleted items, sent items) and with a flexible tool like the Bittitan MigrationWiz you can filter them out.
  • It will show you not only the folders visible to the end user, but also the recoverable deleted items folder. This might be very important in scenarios where you have in place hold active. It will give you the exact estimate of how many items are under in place hold on the recoverable items, that you will eventually need to move to the same folder on the destination mailbox.

So in summary, and giving a quick example, if you’re moving 1000 mailbox from Exchange Online tenantA to tenantB, you should use the Bittitan MigrationWiz tool, that will be not only fast but also flexible on what you can include and exclude in the migration, leveraging the Exchange Web Services API. To do that the insight of what’s in the mailbox is fundamental to plan the entire migration. You can plan the timelines and how long it will take, what type of licensing you will need at the destination tenant and many other important variables for the project.

How can I filter the output per item type?

When running the cmdlet you need to use the “-FolderScope” parameter to filter the output per item type. That parameter allows you to enter many different folder scope types, the most common being:

  • All
  • Calendar
  • Contacts
  • RSSSubscriptions
  • RecoverableItems

See the entire list in the official Technet article of the Get-MailboxFolderStatistics cmdlet.

Some cmdlet examples

See below some examples on how to obtain specific data:

Get total number of items in the mailbox (does not include recoverable deleted items):

Get-MailboxFolderStatistics user@domain.com | Where-Object {$_.foldertype -eq ‘root’} |ft folderpath, itemsinfolderandsubfolders, folderandsubfoldersize

2

Get total number of contacts in the mailbox:

Get-MailboxFolderStatistics user@domain.com -FolderScope Contacts |ft folderpath, items*, folderandsubfoldersize

3

Note: the above will work for calendar items if you change the folder scope from “Contacts” to “Calendar”

Get total number of items in the Recoverable deleted items folders:

Get-MailboxFolderStatistics user@domain.com| where {$_.FolderType -eq ‘RecoverableItemsRoot’}|ft folderpath, itemsinfolderandsubfolders, folderandsubfoldersize

4

And finally… the script that exports all of this to a csv:

Now that we discussed how important it is to get the statistics, and I gave you same examples on how to run some one line commands to get some insight on the mailbox, I will share with you a script that was done by me and my colleague and friend Alberto Nunes.

Below are the details of what the script does:

  • The script will run the statistics against a list of users that needs to be specified on a file called users.csv (see csv format below). The file needs to be on the same folder as the script.
  • The script runs Exchange PowerShell commands, so make sure you’re connected to the Exchange PowerShell (online or on premises)
  • The script will export the results to a file statistics.csv
  • The script will ask you for a source or destination parameter. The statistics for the recoverable deleted items folders will only be included if you select Destination.
  • This script is provided as is and there’s no guarantee that it will work in your environment.

The Users.csv file:

5

Note: Make sure you name the column A “EmailAddress”

The Script:

Copy the text below (in red) to a notepad. Save it as .ps1 and run it from a PowerShell session connected to Exchange.

#Start Script
Param
(
[Parameter(Position=0,Mandatory = $true)][ValidateSet(‘Source’,’Destination’,’MigrationWiz’)][String]$Location,
[Parameter(Mandatory = $false)][String]$Folder = “.”,
[Parameter(Mandatory = $false)][String]$UsersCSV = “Users.csv”,
[Parameter(Mandatory = $false)][String]$OutputCSV = “Statistics.csv”
)
Get-Date
$ErrorActionPreference = “SilentlyContinue”
$SourceFile = $Folder + “\” + $UsersCSV
$OutputFile = $Folder + “\” + $OutputCSV
$mailboxes = Import-Csv -Path “$SourceFile”
$CSV = @()
Foreach ($mailbox in $mailboxes)
{
Write-Host “Working on $($mailbox.EmailAddress)”

$AllStats = Get-MailboxFolderStatistics $($mailbox.EmailAddress)| Where-Object {$_.foldertype -eq ‘root’}

$ContactStats = Get-MailboxFolderStatistics $($mailbox.EmailAddress) -FolderScope Contacts
$TotalContactsItems = ($ContactStats | select -expand ItemsInFolder |Measure-Object -Sum).Sum

$CalendarStats = Get-MailboxFolderStatistics $($mailbox.EmailAddress) -FolderScope Calendar
$TotalCalendarItems = ($CalendarStats | select -expand ItemsInFolder |Measure-Object -Sum).Sum

$RSSFeeds = Get-MailboxFolderStatistics $($mailbox.EmailAddress) -FolderScope RssSubscriptions -ErrorAction SilentlyContinue
If ($RSSFeeds)
{
$TotalRSSFeeds = ($RSSFeeds | select -expand ItemsInFolder | Measure-Object -Sum).Sum
}
Else
{
$TotalRSSFeeds = 0
}

# In the source, we don’t need to know the Size of the RecovableItems
If ($Location -eq “Destination”)
{
$recoverableItems = Get-MailboxFolderStatistics $($mailbox.EmailAddress)| where {$_.FolderType -eq ‘RecoverableItemsRoot’}
[double]$recoverableSize = $recoverableItems.FolderAndSubfolderSize.TrimEnd(” bytes)”).Split(“(“)[1].replace(‘,’,”) |%{“{0:N2}” -f ($_ /1mb)}
}

$TotalMailItems = $AllStats.ItemsInFolderAndSubfolders – $TotalContactsItems – $TotalCalendarItems – $TotalRSSFeeds

$ISSize = $AllStats.FolderAndSubfolderSize.tostring()
[double]$ISSize =$ISSize.TrimEnd(” bytes)”).Split(“(“)[1].replace(‘,’,”) |%{“{0:N2}” -f ($_ /1mb)}

$Output = New-Object PSObject
$Output | Add-Member -MemberType NoteProperty -Name “User” -Value $mailbox.EmailAddress
$Output | Add-Member -MemberType NoteProperty -Name “Location” -Value $Location
$Output | Add-Member -MemberType NoteProperty -Name “TotalItems” -Value $AllStats.ItemsInFolderAndSubfolders
$Output | Add-Member -MemberType NoteProperty -Name “MailboxSize MB” -Value $ISSize
$Output | Add-Member -MemberType NoteProperty -Name “TotalContactItems” -Value $TotalContactsItems
$Output | Add-Member -MemberType NoteProperty -Name “TotalCalendarItems” -Value $TotalCalendarItems
$Output | Add-Member -MemberType NoteProperty -Name “TotalMailItems” -Value $TotalMailItems
$Output | Add-Member -MemberType NoteProperty -Name “TotalRSSFeeds” -Value $TotalRSSFeeds
If ($Location -eq “Destination”)
{
$Output | Add-Member -MemberType NoteProperty -Name “RecovableSize in MB” -Value $recoverableSize
$Output | Add-Member -MemberType NoteProperty -Name “RecovableItems” -Value $recoverableItems.ItemsInFolderAndSubfolders
$Output | Add-Member -MemberType NoteProperty -Name “Total Mailbox Size including Recovable” -Value $($ISSize + $recoverableSize)
$Output | Add-Member -MemberType NoteProperty -Name “Total Mailbox Count including Recovable” -Value $($AllStats.ItemsInFolderAndSubfolders + $recoverableItems.ItemsInFolderAndSubfolders)
}
$CSV += $Output
Write-Host “Completed $($mailbox.EmailAddress)” -ForegroundColor Green
}

$CSV | export-CSV “$OutputCSV” -NoTypeInformation
#End Script

To run the script you need to specify the location parameter:

.\MailboxFolderStats.ps1 -Location Source

.\MailboxFolderStats.ps1 -Location Destination (includes recoverable deleted items statistics)

As always I hope the above is helpful. Thanks for reading.

Office 365 tip: Enable Directory Sync via PowerShell

There’s no easy way to say this. The new Office 365 admin Portal comes with a new way to enable Directory Sync, a wizard that tries to guide you through with a series of questions and suggestions. The end result is bad, to say the least.

 

ADSyncWiz1

The wizard is confusing and the end result is sometimes not the expected. It happened to me several times finishing the wizard just to find out that Directory Sync was still disabled.

In my opinion things like finishing the wizard if you select “1-10” in the number of users of your organization, assuming of course that you don’t want Directory Sync, are not welcome. I understand the “dummy proof” idea behind it, but let’s face it not everything needs to be designed in such way.

ADSyncWiz2

As you can see above once you run the wizard you’ll get a summary report of the results, and links to download  AD Connect and the IdFix tool.

But the purpose of this blog post is to explain you how to get away from the wizard and on a simple command activate Directory Synchronization. Here it goes:

  1. Download and install the Windows Azure Active Directory Module for Windows PowerShell
  2. Connect to Office 365 and run the cmdlets below

ADSyncWiz3

Enable Directory Sync:

Set-MsolDirSyncEnabled -EnableDirSync $true

Verify Directory Sync state:

(Get-MsolCompanyInformation).DirectorySynchronizationEnabled

I hope the above is helpful. As always, any questions please let me know.