How do you plan and execute a successful Public Folder migration?

From all the years as a consultant, and now directly in the migration business, helping partners successfully plan and execute migrations, Public Folders as always been the one of the most challenging workloads I had to deal with.

There’s always a lot of questions when you have to execute such migrations, so I decided to write a blog post about it, where I am going to try and address as much as possible.

To try and keep it as organized as possible, and because there are so many different scenarios, I will divide this post into three main sections: General migration considerations, Migrating Hybrid Public Folders and Migrating Public Folders cross organization.

We will then also discuss some more generic questions, such as why use a third party tool vs the Microsoft native tool.

General migration considerations

This blog post is focused both on Hybrid and cross organization Public Folder migrations. Some steps however are exactly the same, regardless of what the migration scenario is. Those steps are described below. After reading this section you can then focus on your specific scenario in the sections that follow.

Prepare your On Premises Environment

One of the first things you need to look at is to the On Premises Public folder structure, to check if there’s any inconsistencies or invalid folders. The best way to that is of course via scripting, and you should use this excellent script from Aaron @Microsoft, called IDFix for Public Folders. Download it, run it and fix everything that the script highlights as needing to be fixed.

You should also make sure you create a report with all mail enabled Public Folders and address, and to do so you can leverage the Get-MailPublicFolder cmdlet.

How to migrate Public Folder access permissions, as well as Send-As and Send-on-behalf rights

Public Folder permissions should be migrated by the migration tool, provided of course identities match between on premises and Exchange Online (which should of course be true for Hybrid scenarios), or between premises  in cross organization migrations.

As for the Send-As and Send-on-behalf rights, the best option is to export them from the source system and import them into the destination system, once the migration is completed. Since this is not PowerShell code I’ve focused on recently, I did a quick research online and found this article online where you can find the code to export and import those access rights.

Note: I am not the author of the code below and I am only putting it directly in my blog post just so it’s easier for you to locate it and copy it. The code was taken from the article mentioned in the line above, written by Aaron Guilmette.

Export Send-As

Get-MailPublicFolder -ResultSize Unlimited | Get-ADPermission | ? {($_.ExtendedRights -Like "Send-As") -and ($_.IsInherited -eq $False) -and -not ($_.User -like "*S-1-5-21-*")} | Select Identity,User | Export-Csv Send_As.csv -NoTypeInformation

Export Send-on-behalf

Get-MailPublicFolder | Select Alias,PrimarySmtpAddress,@{N="GrantSendOnBehalfTo";E={$_.GrantSendOnBehalfTo -join "|"}} | Export-Csv GrantSendOnBehalfTo.csv -NoTypeInformation

$File = Import-Csv .\GrantSendOnBehalfTo.csv
$Data = @()
Foreach ($line in $File)
    If ($line.GrantSendOnBehalfTo)
        Write-Host -ForegroundColor Green "Processing Public Folder $($line.Alias)"
        [array]$LineRecipients = $line.GrantSendOnBehalfTo.Split("|")
        Foreach ($Recipient in $LineRecipients)
            Write-Host -ForegroundColor DarkGreen "     $($Recipient)"
            $GrantSendOnBehalfTo = (Get-Recipient $Recipient).PrimarySmtpAddress
            $LineData = New-Object PSCustomObject
            $LineData | Add-Member -Type NoteProperty -Name Alias -Value $line.Alias
            $LineData | Add-Member -Type NoteProperty -Name PrimarySmtpAddress -Value $line.PrimarySmtpAddress
            $LineData | Add-Member -Type NoteProperty -Name GrantSendOnBehalfTo -Value $GrantSendOnBehalfTo
            $Data += $LineData
$Data | Export-Csv .\GrantSendOnBehalfTo-Resolved.csv -NoTypeInformation

Import Send-As

$SendAs = Import-Csv .\SendAs.csv
foreach ($obj in $SendAs) 
    write-host "$($i)/$($SendAs.Count) adding $($obj.User) to $($obj.Identity)"
    Add-RecipientPermission -Identity $obj.Identity.Split("/")[2] -Trustee $obj.User.Split("\")[1] -AccessRights SendAs -confirm:$false; $i++

Import Send-on-behalf

$GrantSendOnBehalfTo = Import-Csv .\GrantSendOnBehalfTo-Resolved.csv
Foreach ($obj in $GrantSendOnBehalfTo)
    Write-host "$($i)/$($grantsendonbehalfto.count) Granting $($obj.GrantSendOnBehalfTo) Send-On-Behalf to folder $($obj.PrimarySmtpAddress)"
    Set-MailPublicFolder -Identity $obj.PrimarySmtpAddress -GrantSendOnBehalfTo $obj.GrantSendOnBehalfTo

Migrating Hybrid Public Folders

This scenario, when compared to the cross organization migration, is far more complex, because besides moving the data you will also have to worry about things like mail flow, user public folder access, etc. But lets address one thing at the time.

Microsoft Official guidance to configure Hybrid Public Folders

If you’re reading this article because you’re planning to migrate your Hybrid Public folders, chances are you already read and executed the Microsoft guidance to make your on premises Public Folders available to Exchange Online users, under a Hybrid deployment. Configure legacy on-premises Public Folders for a Hybrid Deployment is the article for legacy public folders and Configure Exchange Server Public Folders for a Hybrid Deployment is the one for modern Public Folders.

Both articles are focused on the hybrid coexistence and not the migration planning of the Public Folders, but they are important to mention as they impact the migration planning, based on what type of coexistence you configured and steps you followed.

Public Folder end user access in the context of a hybrid migration

When planning a Public Folder migration, under a hybrid scenario, one of the most important things you need to consider is, end user access. With that in mind, consider the following:

  • On premises users cannot access Exchange Online Public Folders
  • Exchange Online users can access on premises public folders and/or Exchange Online Public folders, although you cannot configure a single user to access both, you can configure some users to have access to on premises folders and some to see them locally, in Exchange Online.

Have the two principles in mind, during your planning. The Public Folder access for Exchange Online users is complex and by itself worthy of a dedicated blog post.

The Microsoft official guidance, mentioned in the previous section, explains how you configure Exchange Online users to access on premises Public Folders.

The bottom line of this section is, make sure you move all users to Exchange Online, before you consider moving the Public Folders, and if you don’t, make sure that the users left on premises do not require any Public Folder access.

Public Folder mail flow coexistence before, during and after the migration. How do you handle mail enabled Public Folders.

Another very important component of your Public Folder migration is the mail flow coexistence, or to be more precise, the way you deal with the mail enabled Public Folders.

Mail Enabled Public Folders before the migration

When you follow the guidance provided by Microsoft, you will be asked to execute the Sync-MailPublicFolders script.

This script enables Exchange Online users to send emails to on premises mail enabled Public Folders, by creating mail objects in Exchange Online with the primary and all other SMTP addresses that those folders have on premises. This objects are not actual Exchange Online Public Folder nor they are visible in the Exchange Online Public Folder tree. They also allow those on premises Public Folders to be present in the Exchange Online GAL (Global Address List), and once a user in Exchange Online emails that folder, the email gets forwarded to Exchange On Premises.

Mail Enabled Public Folders during the migration

During the Public Folder migration, whether it’s a single or multiple pass (with pre-stage + full migration) migration strategy, you should not change the Public Folder mail flow. That means that you should not mail enable the Public Folders in Exchange Online (chose a tool that gives you that option). Actually as you will see below, there are things that you need to do in Exchange Online, before mail enabling the Public Folders.

Mail Enabled Public Folders after the migration

Once your migration (or the pre-stage) is completed, you should transition the Public Folder mail flow to Exchange Online. To do so, you should follow these steps:

  1. Start the pre-stage or full migration and wait for it to be completed
  2. Once the migration pass is done, go to Exchange Online and delete all mail objects created by the Sync-MailPublicFolders script (NOTE: this will temporarily break mail flow between Exchange Online users and mail enabled Public Folders, online or on premises)
  3. Mail enable the Exchange Online Public Folders, either via a script or using the migration tool. Make sure you add all addresses from the on premises to the online Public Folders
  4. Run a full migration pass if in step 1 the pass that you ran was a pre-stage

To elaborate a little bit more in step 2, the reason that you need to delete those objects is because you need to avoid conflicting addresses, when enabling the mail enabled Public Folders in Exchange Online, and those objects are not associated with the new EXO Public Folders.

Migrating Public Folders cross Organization

Migrating Public Folders cross organization is not as complex, and you’ll see why in the sections below. This scenario can include migrations such as:

  • Exchange Online to Exchange Online
  • Hosted Exchange to Exchange on premises or Exchange Online
  • Exchange on premises to Exchange on premises

When to migrate users and Public Folders

Usually this Public Folder migrations cross organization come as an additional step to a migration that also includes mailboxes.

Although there’s no 100% correct answer, when it comes to the question of what should be migrated first, mailboxes or Public Folders, in this cases normally the best option is to migrate mailboxes first and Public Folders last. The main reason for that is because you should migrate the Public Folders when they’re not being used anymore, allowing you to do a clean single pass migration of all the data.

Public Folder end user access and mail flow coexistence

This is where things gets simple, for this type of scenarios. There’s no Public Folder access cross organization (unless the user is using the credentials for the 2 systems) and although technically you can configure mail flow between any two email systems, it’s not something you should consider for the majority of the cases.

Mail enabled Public Folders can and should be created at the destination during the folder hierarchy creation.

Why use a third party tool to migrate Public Folders

That’s probably the question I get the most, working for a third party migration tool company, that has an amazing Public Folder migration tool, BitTitan. And here is a list of reasons:

  • Migrate large volumes of data: Migrating 2, 5 or 10GB is easy with any tool, but not all tools can deal with Terabytes of Public Folder data.
  • Migrate parts of the structure or prioritize data: Either by targeting just specific parts of the Public Folder hierarchy or by using folder filtering. This is a very commonly used feature in tools like BitTitan MigrationWiz.
  • Flexibility on handling mail enabled Public Folders: As explained in the Hybrid mail flow section of this posts, you might need some flexibility on how to handle mail enabled Public Folders during the migration. MigrationWiz will mail enable in the destination all Public Folders that are mail enabled at the source, but you can also suppress that option, and should in some scenarios.
  • Data transformation: While planning a migration of Public Folders, some customers want to take that opportunity to also move that data into a different structure, which can be shared or resource mailboxes, office 365 groups, etc. That is something that can be successfully done with tools that are flexible enough to perform that transformation (i.e in many cases requires recipient mapping, folder mapping, folder filtering, etc), like MigrationWiz.
  • Supported sources and destinations: Exchange 2007+ to Exchange 2007+, including of course Exchange Online and hosted as source and/or destination – this is the answer most customers want to hear from the support ability stand point of a third party tool, to migrate their Public Folders, and that is something they won’t get with the native tool.

The bottom line

While reading this post, before publishing it, I always get the feeling that there’s so many other things that I could mention and talk about, but I do think that it addresses the core concerns of most Public Folder migrations, and hopefully it addresses yours.

Nevertheless, if you do have any questions don’t hesitate to reach out.





Office 365: Not sure if your vanity domain is being used by another Office 365 tenant? Don’t worry.

I remember not long ago, the pain of trying to find out in which Office 365 tenant your vanity domain was validated, when you bumped into the error stating that the domain was in use, while adding it to your current tenant.

This was maybe because I work with multiple tenants and I recycle my tenants quite often, for testing purposes, but I’ve also seen it with others while trying to assist them in their migration projects.

Fortunately Microsoft now is very clear in the error message you’ll see, when trying to add a domain to a tenant, that is in use. This is what you will see now:


As you can see above, it will tell you exactly in which tenant the domain is, just so you can login to it and remove it.

Now is there a catch with this? Of course!! Microsoft won’t give you such privileged information, until you enter a valid DNS record for the domain validation. You’ll see something similar to this, if the domain validation is not done properly:


So remember to add the DNS record first and click “Verify”, Microsoft will either add the domain or explain exactly why they can’t, which I am sure it was for a long time one of the main asks of Office 365 admins and consultants.

Populate Exchange mailboxes using Exchange Web Services

I just came across a very nice and handy script, that allows you to quickly populate your Exchange mailbox with test data, leveraging EWS.

Being in the migration business and having to do all sorts of tests and demos all the time, this to me is a very useful script, and I am assuming if you’re reading this post, there’s a chance that you also need it.

So this PowerShell script to generate mailbox test data over a period of time, when compared to other methods that leverage SMTP, is great because you can actually populate the mailbox with “old” data.

The parameters you can specify can also be found in the page of the author of the script. You can specify the target mailbox, number of days to fill the mailbox with, messages per day and message size, EWS endpoint or to use autodiscover and some EWS API specific parameters.


Above you can see and example of the script execution.


And this is how it’s going to look, as it executes.

The script should work perfectly both in Exchange Online and On Premises, as long as it’s a version that supports EWS.

Disclaimer: Unlike many other scripts I blog about, I am not the author of this script. I’ve seen it in the Technet Gallery, used it, and though I should blog about the experience. If you have any issues and/or recommendations or evens kudos to sent, refer to the author, identified in the Technet gallery page.


The differences in quotas and how to handle Public Folder migrations to Exchange 2013+ On premises vs Exchange Online

When we talk about migrating Public Folders, and believe me I talk about that a lot, the usual assumption is that the migration is to Exchange Online. That is true most of the times, but not all.

BitTitan MigrationWiz is a tool that adapts to all sorts of scenarios, the rule being if you have an Exchange 2007+ in the source and destination, and that of course includes Exchange Online, that MigrationWiz will be able to migrate your Public Folders. That being said I find myself discussing scenarios such as migrating Public Folders from Exchange on premises or Exchange Online, to a destination Exchange On Premises.

For those used to migrate Public Folders into Exchange Online, you would know that one of the main things to take into account is the volume of data to be migrated and how to make that work seamlessly, since the Public Folder mailboxes in Exchange Online have quotas you can’t change, as you can see here.

One of the things that makes MigrationWiz such a good tool to migrate large volume of Public Folder data, into Exchange Online, is that we will automatically split the Public Folder data into multiple mailboxes, therefore preventing a migrate failure and delay if one of the mailboxes gets full during the migration. This is done via support and explained in all the relevant migration guides, such as this one.

So the question now is, would this process be necessary when the destination are Exchange On Premises 2013+?

Answer: No. You can’t change Public Folder mailbox quotas in Exchange Online, but you can change them in Exchange On premises, so you don’t need to automatically split the data into multiple destination mailboxes.

And should I use a single On Premises mailbox for a large volume of data?

Answer: You can, but you shouldn’t. If you have 100, 150 or 200GB of Public Folder data, then yes a single mailbox approach seems reasonable, but if you have more than that you should think about having multiple mailboxes, for reasons like backup and restore management, among others. Another reason for having multiple Public Folder mailboxes might be if you have a multi region Exchange Organization and you want to provide localized access to Public Folders.

Why do you reference the destination as being Exchange 2013+?

Answer: Because this blog post focuses specifically in modern public folders (mailbox vs database).

Now lets have a look at a Public Folder mailbox in Office 365:


As you can see above the quotas are well defined and cannot be changed.

How does that look in Exchange On premises?


Above you can see 2 Public Folder mailboxes. One comes with the quota set to unlimited, which is the default when you create a new Public Folder mailbox in Exchange 2013, and for the other one I’ve set the limits to 150GB, with the following command:

Set-Mailbox -PublicFolder <mailboxname> -ProhibitSendReceiveQuota 150GB -ProhibitSendQuota 150GB -IssueWarningQuota 150GB -UseDatabaseQuotaDefaults $false

Note: Don’t forget to set the database quota defaults to false, if you want the new quotas to apply at the mailbox level.

As you can see above there are differences between Exchange Online and On Premises, and the control you have over both. Consider them when planning your migration.


While having Public Folder access in 365 set as remote in the Organization Config, point some users to the Exchange Online Public Folders

Some key things you should have in mind, when you’re moving your Exchange Organization from On Premises to Office 365, and Public Folders are in scope:

  • Before moving the Public Folders to Exchange Online, you need to move all of your users (at least you should move all of the ones that require Public Folder access). Users in Exchange On Premises cannot access Public Folders in Exchange Online.
  • You need to follow the Microsoft Official guidance to configure legacy on premises Public Folders under a hybrid deployment.
  • You can (and should in some scenarios) point some mailboxes to the online Public Folders and that’s what this blog post is all about

Now lets look at how a Hybrid Public Folder Organization Config looks like:


As you can see above, the Public Folders in 365 are configured as remote (step 5 in the guide mentioned above), and an on premises public folder mailbox is defined as their mailbox (created in step 2 of the guide).

What this does is very simple: at the mailbox level, for each mailbox, it will set the parameter “EffectivePublicFolderMailbox” to the mailbox “OnPremPFMBX”, which is a synced mailbox object from on premises, as you can see below:


And how do we change this, per user?

The answer is simple, you run a set-mailbox cmdlet, to one or multiple users, and you define the -defaultpublicfoldermailbox parameter, to a 365 Public Folder mailbox, that you of course need to have created before hand.

set-mailbox <Mailbox> -DefaultPublicFolderMailbox 365PFMBX

The command above is what you need to run, and you can adapt if to multiple users. Let me know if you need help with that.

Before closing this blog post lets just discuss one last thing: creating the Office 365 Public Folder mailbox.

A Public folder mailbox created under a Hybrid scenario, where public folder access is set to remote, will be set by default to a HoldForMigration state. Follow this excellent BitTitan article to understand why and resolve that issue. You need to resolve it before you can create new public folders in Exchange Online.

And while doing that don’t forget that, the best tool out there to migrate your Public Folders is the BitTitan MigrationWiz tool, so while you’re in our help center go ahead and read our migration guides and ask for a quote from our sales team.

[Updated Version] Office 365: Script to bulk change the UserPrincipalName to match the Email Address

As I was seeing a lot of feedback in my original post, regarding how the scripts below had issues, I decided to post this new updated version. I will underline the updates  to be easier to follow, but if you never read the original post, please try not to skip any parts in this one.

When you are preparing your local Active Directory, to be synced with Office 365, one of the things you should consider is to make the UserPrincipalName of each user you are syncing to match the user’s email address. Why? Because that is going to be his UserPrincipalName and his primary SMTP address on Office 365.

So there are different ways of achieving this, some more manual than others. The procedure I am going to outline today on this blog post is a two step procedure:

Step 1: Export all UserPrincipalNames and Email Addresses from the local AD to a CSV File.

Step 2: Use that CSV file to bulk change the UserPrincipalNames to match those Email Addresses.

Like I said there are different ways of doing this, and I will probably develop a more elaborated script that can do this in a single step. The reason I went for this two step process is because most of the times customers want to check the CSV generated on step 1, and remove all the users that they don’t want to change the UPN, because those users will not be synced to Office 365.

Before we detail the steps above, make sure that you’ve added additional UPN domain suffixes for all the primary SMTP domains that you will have. See the article “How to add UPN suffixes to a forest” for more information.

Also have a detailed read on the article “Prepare to provision users through Directory Synchronization to Office 365”, to fully understand all the tasks you have to do to prepare your local Active Directory.

Making the UPN’s match the email addresses and have a domain that is validated on Office 365 is just one of the several tasks you have to do.

Now back to the two step process to change those UPN’s.

Step 1:

On step one all you have to do is open a PowerShell module on your local AD, and run the cmdlet below.

#If needed Import the Active Directory Module into your PowerShell session before you run the cmdlet

Import-Module ActiveDirectory

#Run the cmdlet to export all the users to a CSV. Change the CSV name and path as appropriate

Get-AdUser -Filter * -Properties UserPrincipalName, Name, EmailAddress | ? {$_.UserPrincipalName -notlike "DiscoverySearchMailbox*" -and $_.UserPrincipalName -notlike "HealthMailbox*" -and $_.UserPrincipalName -notlike "SystemMailbox*" -and $_.UserPrincipalName -ne $null} | Select-Object UserPrincipalName, Name, EmailAddress | Export-CSV -Path C:\MyADUsers.csv -NoTypeInformation
UPDATE: I’ve added some additional filtering in this cmdlet, specifically to filter out users that don’t have a UserPrincipalName, or users for some types of Exchange system mailboxes such as the discovery search or health mailboxes. You do not want to run the script to change UPNs for system users or any user which is not a regular user that will be syncing up to Office 365. Make sure you filter the output file appropriately before you use it to change the UPNs. Below some example of users that you might still need to filter out from the output CSV.

After you run the cmdlet you should get a CSV like the one shown below:


On the example above you can see that the UserPrincipalName does not match the user’s email address, and therefore needs to be changed.

Once you get the CSV check all users that you want to change and remove from that CSV the ones that you don’t.

Step 2:

Now that you have the CSV with all the users you want to change, all you have to do on step 2 is run the script below. The script will change all the UPN’s to match the email address, based on the CSV file you will use.

#Script to Change the UPN on the Active Directory

#This script should run from an Active Directory Module for Windows PowerShell

#Version 2.0 - 06/22/2018

#Author: Antonio Vargas -

#Disclaimer: All scripts and other powershell references on this blog are offered "as is" with no warranty. While these scripts are tested and working in my environment, it is recommended that you test these scripts in a test environment before using in your production environment.

#Import the AD Module

Import-Module ActiveDirectory

#Static properties (change where needed)

$CSVPath = "C:\MyADUsers.csv"

#Count variables

$usersprocessed = 0

$userswitherrors = 0

$usersskipped = 0

#Import CSV

Try {

$CSV = Import-Csv -Path $CSVPath -ErrorAction Stop


Catch {

Write-Host "ERROR: Cannot import the CSV file. The script will abort. '$($Error[0].Exception.Message)'" -foregroundcolor Red



Write-Host "INFORMATION: The CSV was imported and you have '$($CSV.count)' users to be processed." -foregroundcolor Green

ForEach ($line in $CSV) {

$UPN = $line.UserPrincipalName

$Email = $line.EmailAddress

if ($UPN -eq $Email) {

Write-host "SKIPPING: The UPN '$($UPN)' matches the email address" -foregroundcolor Yellow



Else {

try {

$ADUser = Get-ADUser -Filter {UserPrincipalName -eq $UPN -and Enabled -eq $true} -ErrorAction Stop

If ($ADUser -eq $null) {

write-host "SKIPPING: The user '$($UPN)' is disabled or cannot be found." -foregroundcolor Yellow



Else {

Write-Host "Working on User '$($AdUser.UserPrincipalName)'" -foregroundcolor Yellow

try {

$result = Set-ADUser -Identity $ADUser.SamAccountName -Userprincipalname $Email -ErrorAction Stop


Write-Host "SUCCESS: UPN Changed from '$($AdUser.UserPrincipalName)' to '$($Email)'." -foregroundcolor Green


catch {

Write-Host "ERROR: Cannot change the UPN of the user '$($AdUser.UserPrincipalName)'. '$($Error[0].Exception.Message)'." -foregroundcolor Red





Catch {

Write-Host "ERROR: Cannot retrieve user '$($UPN)'. '$($Error[0].Exception.Message)'." -foregroundcolor Red





write-host "`n"

write-host "############################# REPORTS ####################################" -foregroundcolor Green

Write-Host "REPORT: Total number of users processed with success '$($usersprocessed)'" -foregroundcolor Green

Write-Host "REPORT: Total number of users that were skipped for not meeting the criteria '$($usersskipped)'" -foregroundcolor Yellow

Write-Host "REPORT: Total number of users that failed to process '$($userswitherrors)'" -foregroundcolor Red

Copy the entire content above into a notepad, and save it as a .ps1 file.

Some changes done to the script from the original blog post:

  • Error handling added
  • the script imports the Active Directory module
  • added count for users done with success, skipped or failed
  • small report at the end
  • the entire logic of the code on when to process users was changed 

Disclaimer: All scripts and other PowerShell references on this blog are offered “as is” with no warranty. While these scripts are tested and working in my environment, it is recommended that you test these scripts in a test environment before using in your production environment.

I highly recommend running the script first against a small group of up to 5 users, and then make sure that the changes were applied successfully. Also you need to take into account that you are changing the UserPrincipalName of the user on your local Active Directory, so make sure to test the access to all internal systems that rely on AD for authentication, before you replicate the change to all of your users.

For large environments, if you want a version of the script that exports to CSV all the user results (i.e changed, skipped, failed) feel free to send me an email via the blog.

Go ahead and test the script with its new changes and let me know how that goes.

As always, if you have any questions please let me know.

Exchange Public Folders: Export item count, per item type, of your public folder structure

Just recently, I was asked to help investigate which Exchange cmdlets would help a partner the I work with, do an item count in an on premises Exchange Public folder structure. Their specific ask was to get, per folder, the number of contact items.

So starting with the best command to do this, it’s easy to get to the conclusion that it will be the Get-PublicFolderItemStatistics, and the first thing that you need to know about that cmdlet is that it’s only available in Exchange 2010+.

The second thing you need to focus on is, in which folders do you want to run the count on? All of them? And if not all, do you want to run the count based on folder type? i.e do you want to just count calendar items on folders of type calendar? How can we achieve this?

Lets break this down:

  • To be able to select the folders you want to count the items for, you need of course to start with the Get-PublicFolder cmdlet
  • If you want to filter just one or multiple folder type (i.e Calendar, Contacts, etc) you need to do it using the “FolderClass” attribute.

Note: The “FolderClass” attribute doesn’t exist in all versions of Exchange. I haven’t checked in detail but at least apparently in Exchange 2010 you won’t be able to leverage this attribute to filter just the folders you want. Worst case scenario you can always run a count against all folders. Also note that as you can see below, not all folders have a “FolderClass”.


And finally the code to grab all the folders you want.

With the FolderClass attribute filtering:

#Get all folders
$folders = get-publicfolder \ -recurse -resultsize unlimited | ? {$_.FolderClass -like “IPF.Contact”}
And without:
#Get all folders
$folders = get-publicfolder \ -recurse -resultsize unlimited


Note: The Where-Object filtering (? sign in the command above) in PowerShell caches all its results into memory, so if you have a very large public folder structure you might want to have that in mind and run the commands in a machine with enough resources.

Now that we know how to grab all the folders we need, lets look at how to do the folder count:

  • The command used to do the folder count is, as mentioned above in this post, the Get-PublicFolderItemStatistics
  • Because all you want to do is count items of a certain type, you will leverage the “ItemType” attribute in your filtering
  • Don’t forget that the Get-PublicFolderItemStatistics is an Exchange 2010+ cmdlet

Below see the output of an item count of a specific folder.


Now, finally, the entire script (in bold the item count):


(and the copy/paste version)
#Get all folders
$folders = get-publicfolder \ -recurse -resultsize unlimited | ? {$_.FolderClass -like “IPF.Contact”}
#Process All folders
Foreach ($folder in $folders){
$ContactCount = 0
$Contacts = get-publicfolderitemstatistics $Folder.Identity|? {$_.ItemType -like “IPM.Contact”}
If($Contacts -eq $null){
Write-Host”The folder ‘$($Folder.Identity)’ has 0 Contacts”
foreach($Contact in $Contacts){
Write-Host”The folder ‘$($Folder.Identity)’ has $($ContactCount) Contacts”
Lets break down the script above:
  • we start by getting all folders of class contact. Again you can do this filtering or not, depending on the Exchange version and what you need exactly.
  • we then enter a loop where, for each folder, we will grab all items of type contact and count them
  • once that is done we write the output into the console

This script is very simple and doesn’t have error handling, logging and output to CSV. If you want those features feel free to contact me via the blog and I can build you a very complete version of the script.

Running the simple version of the script in a large environment can make the results difficult or impossible to analyse, however, with the code above gives you an insight in how to filter and count Public folders, by type and class.

As always I hope this is helpful.

Azure AD Connect: A quick way to check (online) the last time the sync ran

I was just doing some work in a devops work tenant, that usually has a Hybrid setup created and Azure AD Connect installed and running, and I realized that I needed to check when was the last time that:

  • the Directory synchronized successfully
  • Passwords synchronized successfully

As this is a very simple process I thought I should write a 5min blog post about it.

All you have to do is connect to the Azure Active Directory of your tenant and execute the Get-MSOLCompanyInformation.


The 3 parameters that you want to look at are:

  • DirectorySynchronizationEnabled (this one is not mentioned above. It shows if the tenant has the synchronization enabled or not)
  • LastDirSyncTime
  • LastPasswordSyncTime

Hope that this information is helpful.

Office 365: Run a script connected to 2 Exchange online sessions

Have you ever wondered how you can connect to 2 Exchange Online sessions, in the same PowerShell window?

For example, if you want to run a script that connects to 2 tenants, exports all mailbox permissions from one tenant and imports them into the other. Same thing applies to Distribution groups and memberships.

With the Microsoft Tenant 2 Tenant Migrations in high demand, and because there are so much that you might want to bring from one Exchange Online to the other, I thought I should write a quick blog article on how to connect and manage 2 Exchange Online tenants in one PowerShell window, ideal for scripting.

Before you look at the code below, let me outline two key parameters, of the Import-PSSession cmdlet to achieve your goal:

  • Prefix – Specifies a prefix to the nouns in the names of imported commands.
    Use this parameter to avoid name conflicts that might occur when different commands in the session have the same name.
    For instance, if you specify the prefix Remote and then import a Get-Date cmdlet, the cmdlet is known in the session as Get-RemoteDate, and it is not confused with the original Get-Date cmdlet.
  • AllowClobber – Indicates that this cmdlet imports the specified commands, even if they have the same names as commands in the current session.
    If you import a command with the same name as a command in the current session, the imported command hides or replaces the original commands. For more information, see about_Command_Precedence.
    By default, Import-PSSession does not import commands that have the same name as commands in the current session.

Note: Both the definitions above were taken from the Import-PSSession cmdlet official Microsoft article, that you can see by clicking here.

So how does this work actually? Have a look at the code below:


Date: October 4th 2017
 Version: 1

 This lines of code will connect 2 PowerShell Exchange Online sessions to 2 different tenants. 
 By opening 2 PowerShell sessions, using the PREFIX parameter for each one of those sessions it will allow you to manage both tenants at the same time (ideal for tasks where you want to migrate configurations from one tenant to the other)

### Input source and destination credentials

$SourceCred = Get-credential -message "Please Enter your SOURCE tenant credentials"

$DestCred = Get-credential -message "Please Enter your DESTINATION tenant credentials"

### Create Source EXO Session

$SourceSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri -AllowRedirection -Authentication Basic -Credential $SourceCred

$result = Import-PSSession $SourceSession -prefix SRC -AllowClobber

### Create Destination EXO Session

$DestSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri -AllowRedirection -Authentication Basic -Credential $DestCred

$result = Import-PSSession $DestSession -prefix DST -AllowClobber

### Run a get-mailbox to validate connection to both tenants

Write-Host "Listing mailboxes in the source tenant" -ForegroundColor Green

Start-Sleep -s 5

Get-SRCMailbox -resultsize unlimited |ft alias, *smtp*

Write-Host "Listing mailboxes in the destination tenant" -ForegroundColor Green

Start-Sleep -s 5

Get-DSTMailbox -resultsize unlimited |ft alias, *smtp*

### Showing a count of mailboxes in source and destination

Write-Host "Counting mailboxes in the source tenant" -ForegroundColor Green

Start-Sleep -s 5

(Get-SRCMailbox -resultsize unlimited).count

Write-Host "Counting mailboxes in the destination tenant" -ForegroundColor Green

Start-Sleep -s 5

(Get-DSTMailbox -resultsize unlimited).count


Write-Host "Your list of active PS Sessions" -ForegroundColor Green

Get-PSSession |fl

Some considerations of the code above:

  • There’s no logging or error handling in the code. The purpose of the code above is to provide you the insight on how to connect to 2 sessions with the same cmdlets.
  • The code is provided as is and you should test it before you run it in production.
  • The code includes blocks to perform the following:
    • Request input for source and destination credentials
    • Create the source Exchange Online session
    • Create the destination Exchange Online session
    • Code to demonstrate how to run cmdlets in the source and destination tenant (example with get-mailbox)
    • Code to list both PS Sessions created

Now lets see the output of the code:


Simple, right? Again this can be very useful for tenant to tenant migrations.

No Outlook 2007 in Exchange Online. Be prepared with BitTitan HealthCheck for O365

I just wrote yesterday a blog post about the dead of RPC over HTTP in Exchange Online, and how that terminates Outlook 2007 as a functioning version to connect to the cloud Exchange.

In that article I briefly talked about how you can use the Exchange PowerShell and mailbox audit logging to determine the version of Outlook your users have, but that has some limitations, such as:

  • If you’re moving to 365, from a non Exchange system, or one previous to Exchange 2010, you won’t have mailbox audit logging.
  • Mailbox Audit logging is off by default and in Exchange on premises systems that are very low on resources (hence the possible move to Exchange Online), it’s something that some Exchange administrators might be reluctant to turn on (although the truth is the load is minimal).
  • The report is extensive and includes all connectivity that each user did to Exchange. Identifying the computer with the outdated Outlook in some cases might be tricky (users that have roaming profiles and log into multiple computers).

So in summary, if you are assessing your users mail clients as part of a migration or if your users use multiple workstations, the approach above is not ideal.

That being said, the solution for you is the free BitTitan HealthCheck for Office 365 module, that is part of the BitTitan Device Management Agent software.

From a technical perspective, once the DMA agent is deployed (via email or automated process such as Group Policy), the HealthCheck for Azure module will run a full assessment to the machine. It will provide much more information than just Outlook, such as:

  • Operating System
  • Disk Space, CPU and memory
  • Internet download and upload speed
  • Device specifications
  • Browsers and Outlook versions

As you can see you’ll get a very complete report and it doesn’t require any license.

As a final note the Device Management Agent also has the DeploymentPro module, that you can use to automatically reconfigure the Outlook profile, as part of your migration.