Public Folder Migration Fail #2

Another day, another Public Folder migration failure. This time, on testing your Public Folder migration to Office 365, they appear to be unavailable and are not visible in the Outlook client.

I always follow the wonderful guide provided by Microsoft on how to migrate your Public Folders from Exchange > Office 365 (I’m not being sarcastic, it is actually a good guide) available here:

The last two times I have run through this process, I have attempted to test the PF Migration on a single user prior to going live for all users. Microsoft suggest the following command for doing this:

Set-Mailbox -Identity <Test User> -DefaultPublicFolderMailbox <Public Folder Mailbox Identity>

However since the Exchange 2016 wave of Office 365 has gone live, this command no longer appears to have the desired effect. What seems to happen is that because the -IsExcludedFromServingHierarchy parameter is set to $true, the command does not fully enable the Public Folders for that user.

In both situations, I have taken the plunge and enabled Office 365 Public Folders for all users by running:

Get-Mailbox -PublicFolder | Set-Mailbox -PublicFolder -IsExcludedFromServingHierarchy $false

The end result (after a little patience) is that Public Folders become available for all users. I’m not sure if this is a general bug or a result of the Exchange 2016 backend of Office 365, but I’d be interested to hear your experiences!


Public Folder Migration Fail

The above title isn’t a surprise for anybody working in IT, but unusually for Public Folders, this one has a fairly simple fix!

The situation is thus; when attempting to complete a Public Folder migration to Office 365, you come across the following error:

Before finalizing the migration, it is necessary to lock down public folders on the legacy Exchange server (downtime required). Make sure public folder access is locked on the legacy Exchange server and then try to complete the batch again.

Public Folder migration error

The problem with this error is that you have already locked down Public Folders on the legacy Exchange Server by running:

Set-OrganizationConfig -PublicFoldersLockedForMigration:$true

So what’s an admin to do when they’ve already run the command they are being told needs to be run?! Some googling may lead you to the idea of rebooting the server, or restarting the Information Store. Both of these will work, but a much simpler solution is simply to dismount the Public Folder database/s, and then mount them. The PFs are already locked so are unavailable to the users so there is no negative impact of doing this.

TL;DR – turn it off, and turn it on again.


How many users are in my AD group?

Nice simple three liner here. I often want to check how many users are in a particular group, and find it a bit annoying that ADUC doesn’t show this in the Group Properties. So to find out, run this from a Powershell window on a DC:

Import-Module ActiveDirectory
$group = Get-ADGroupMember "group name" -recursive | Select-Object name

The second line puts all the members into a variable called $group, and if you didn’t already know, putting .count after any variable will enumerate the objects in that variable:-)

Happy days!

Add X500/X400/SMTP address for a list of users

This process can be reused to add (not overwrite, just append) any type of email address to a list of users. All you need is a simple CSV file with 2 rows, SamAccountName and the new email address. The example I’ve used is an X500 address, but this could be X400: or SMTP. Remember when adding an SMTP address, case sensitivity matters! = secondary email alias = primary email address

brucewa X500:/O=WAYNE ENTERPRISES/OU=First Administrative Group/cn=Recipients/cn=brucewa
harleyqu X500:/O=WAYNE ENTERPRISES/OU=First Administrative Group/cn=Recipients/cn=harleyqu
poisoniv X500:/O=WAYNE ENTERPRISES/OU=First Administrative Group/cn=Recipients/cn=poisoniv

Once you have your lovely CSV file in a location on the Exchange server, crack open the Exchange Management Shell and run this command:

Import-Csv C:\migration\x500.csv | ForEach-Object{
  $name = $_.SAM
  $proxy = $
  Set-Mailbox -Identity $name -EmailAddresses @{add= $proxy}


Office 365 PowerShell and Scheduled Tasks

There are many reasons why you might want to run PowerShell scripts against Office 365/Exchange Online on a schedule, so I won’t fuss with any examples. Here is how it is done.

First you must create an encoded script file which contains the password for the Exchange Online/Office 365 admin which you want to use to login. It is important that you create the .key file

a) on the computer which will be running the scheduled task
b) using the account which will run the Scheduled Task

This is because as only the creator can decrypt the .key file, and this can only be done on the computer which generated the key file. To create your encrypted password file, open Powershell and run the following command:

Read-Host "Enter Password" -AsSecureString |  ConvertFrom-SecureString | Out-File "C:\scripts\Password.txt"

This will ask you to enter the password and then give you a file full of rubbish. Now let’s do something with that rubbish! Your script to connect to Exchange Online and Office 365 should look like the following:

$TenantUname = ""
$TenantPass = cat "c:\scripts\password.key" | ConvertTo-SecureString
$TenantCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $TenantUname, $TenantPass
$msoExchangeURL = “”
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $msoExchangeURL -Credential $TenantCredentials -Authentication Basic -AllowRedirection 
Import-PSSession $session
Connect-MSOLService -Credential $TenantCredentials

After these lines, add in the Powershell commands you wish to run, or a reference to a script. Save this as a .ps1 file.

For example, Clutter can’t be disabled for the whole tenancy, so to get around this I might want to disable clutter for all my users every night by adding this line to the end of my script:

Get-Mailbox -ResultSize Unlimited | Set-Clutter -Enable $false

Once you are all done with your script, open Task Scheduler and create a new task.

On the general tab, ensure that the user account being used to run the task is the same account which created the password file, and make sure the ‘Run whether user is logged on or not’ is ticked. Add whichever time based triggers you need, and on the Actions page choose to ‘Start a Program’ with the following settings:

Program/script: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Add arguments: C:\Scripts\TestScript.ps1

Voila! You now have a script which uses an AES encrypted text file to connect to Exchange Online and Office 365 so that you can run your daily maintenance tasks from a single management server. Yay!

Append Description to a list of users

Today I needed to append, not overwrite, the description variable for a list of users. To do this, I created a simple .txt file containing the usernames I wanted to change.


I then ran this very simple command which takes the existing Description and adds the phrase “User Enabled 07/06/2016” to the end of the Description.

Get-Content "c:\migration\userstest.txt" | get-aduser -Properties Description | ForEach-Object { Set-ADUser $_ -Description "$($_.Description) User Enabled 07/06/2016" }

Easy peasy lemon squeezy!

Stale Forest / External Trust

Recently I had to remove an External Trust between two domains and replace it with a Forest Trust. Simple work for an Active Directory consultant, you might think, but as with most consultancy work, it’s the simple stuff that catches you out!

After removing the external trust, I validated that it had indeed been removed by checking in Active Directory Domains & Trusts, and also by running netdom query trust. However when trying to create the new Forest Trust, an error message was shown stating that an external trust still existed. More specifically, the error stated:

A trust relationship with the domain you specified already exists

It turned out that, although both the GUI and the netdom commands showed that the trust had been deleted, a stale object still existed. To remove this object, ADSIEdit.msc was used, which is always a risky business! The process for this was:

  1. Open ADSIEdit.msc – If you are running Server 2003, you must install the Windows Server 2003 Support Tools
  2. Connect to the Domain partition
  3. Expand the System container
  4. Find the stale object, the name of this will be of the domain being trusted, and the class is trustedDomain
  5. Delete this trust object

trustedDomain object

This should allow you to create the new trust object.