Category Archives: Office365

Deploy MFA to all Administrator accounts in all (Partner) tenants

As a MSP we tend to take over a lot of Microsoft tenants which therefore do not have their state of security in order. To make sure that we always use MFA for administration purposes we have an Azure Function running that deploys MFA for our administrator accounts. We do this by using our central phone number. That way MFA is always configured and we notice when an admin is trying to log in. We tend to use our delegated access as the normal administration purpose but some tasks require a local admin account in the customer’s portal.

We currently have the following running as an Azure Function. I’ve edited the script to allow anyone to run this directly. If you need help converting this to an Azure Function please see my other blog here.

The great thing about this script is that we completely negate the need for our helpdesk to configure MFA for the admin accounts. The script makes sure that MFA is completely prepared for them all.

Script breakdown

In the first part of the script we set our phone numbers, connect to the MSOLService and get all the Microsoft Partner Contracts we have permissions on

$MobileNumber = "+31611111111"
$AltNumber = "+31010101010"
$ClientList = get-msolpartnerContract -All

Now that $ClientList contains all our clients we loop trough these to get all of our admin accounts.

foreach($Client in $ClientList){
$adminemails = Get-MsolRoleMember -TenantId $Client.tenantid -RoleObjectId (Get-MsolRole -RoleName "Company Administrator").ObjectId
$admins = $adminemails | get-msoluser -TenantId $client.tenantid

Now that we have our admin accounts in $Admins the next step is to create two objects – One for the Strong Authentication Requirements and another for the Strong Authentication Method.

$AuthReq = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$AuthReq.RelyingParty = "*"
$AuthReq.State = "Enabled"
$AuthReq.RememberDevicesNotIssuedBefore = (Get-Date)
$AuthMethod = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$AuthMethod.MethodType = "TwoWayVoiceMobile"
$AuthMethod.IsDefault = $true
$AuthMethodObj = @($AuthMethod)

This makes sure that the user is completely pre-provisioned and does not need to go through the entire process of activating MFA first, which saves us valuable time. To finalize we run a for-each loop which enables all found Admin accounts with Multi Factor Authentication. It also sets the phone numbers to the ones we’ve entered as variables above.

foreach ($admin in $admins | Where-Object {$_.StrongAuthenticationMethods -eq $Null}) {
        Write-Host "Enabling MFA for $($admin.userprincipalname)" -ForegroundColor Green
        Set-MsolUser -UserPrincipalName $admin.userprincipalname -StrongAuthenticationRequirements $AuthReq -StrongAuthenticationMethods $AuthMethodObj -TenantId $admin.tenantid  -MobilePhone $MobileNumber -AlternateMobilePhones $AltNumber

And thats it! as a result the clients Secure Score will increase by about 50 points. Awesome! The complete script will look like this

Final Script

$MobileNumber = "+31611111111"
$AltNumber = "+31010101010"
$ClientList = get-msolpartnerContract -All

foreach($Client in $ClientList){
$adminemails = Get-MsolRoleMember -TenantId $Client.tenantid -RoleObjectId (Get-MsolRole -RoleName "Company Administrator").ObjectId
$admins = $adminemails | get-msoluser -TenantId $client.tenantid
$AuthReq = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$AuthReq.RelyingParty = "*"
$AuthReq.State = "Enabled"
$AuthReq.RememberDevicesNotIssuedBefore = (Get-Date)
$AuthMethod = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$AuthMethod.MethodType = "TwoWayVoiceMobile"
$AuthMethod.IsDefault = $true
$AuthMethodObj = @($AuthMethod)
foreach ($admin in $admins | Where-Object {$_.StrongAuthenticationMethods -eq $Null}) {
        Write-Host "Enabling MFA for $($admin.userprincipalname)" -ForegroundColor Green
        Set-MsolUser -UserPrincipalName $admin.userprincipalname -StrongAuthenticationRequirements $AuthReq -StrongAuthenticationMethods $AuthMethodObj -TenantId $admin.tenantid  -MobilePhone $MobileNumber -AlternateMobilePhones $AltNumber

Tada! as always, be careful, and happy PowerShelling!

Connecting to all O365 services at the same time in PowerShell (Including Installation and Teams)

I often use scripts that uses cmdlets from different modules so I can use all sorts of data sets when handling my Office365 administration tasks. The problem is that I often found myself connecting to a specific service such as the Exchange services, only to need the security center moments later – or the MSOL Module right after. When reinstalling my laptop I decided to not bump into this anymore, mostly to just get rid of my annoyance.

After a short search online I’ve found that there already was a bit of an example here on the Microsoft docs website. Unfortunately this guide is outdated and does not included the newer Teams Module. It also does not automatically find the correct SharePoint URL. As I am quite lazy and never want to look things up I also added the functionality to find the correct URL and to download the right modules. Currently it connects to the following services:


ServiceModule Name
AzureAD (Graph)AzureAD Module
AzureAD(MSOL)MSOL Module (Legacy)
Exchange OnlinePSSession to Exchange Endpoint
Security & CompliancePSSession to Protection endpoint
Skype for Business SkypeOnlineConnector

The function has only two options; a -Disconnect in case you want to end the sessions cleanly, and a -Credentials option for passing the credentials. Both are optional. To make sure the Function is always available to me I’ve added it both to my VSCode Profile and my PowerShell profile by starting a PowerShell prompt in both tools and entering the following one-liner:

New-Item -Path $profile -ItemType File

This creates a file in your profile path. Any code you paste here will always be loaded on startup. Because I use a lot of functions I do not like posting my code directly here, instead I save my modules to a specific folder, and have it look in that folder for any functions that I add.

$MyFunctions = "C:\Posh\Functions"
write-host "Loading Functions" -ForegroundColor Yellow
Get-ChildItem "$MyFunctions\*.ps1" | %{.$_}
write-host "Done Loading functions." -ForegroundColor Green 

This small piece of code looks in C:\Posh\Functions for all .PS1 files and loads these files as if I just run them as a script. This makes sure small functions which do not need to be an entire module on their own are loaded correctly. In C:\Posh\Functions I’ve saved the following script which I’ve called “Connect-Office365.ps1”


function Connect-Office365 {
    Get-PSSession | remove-pssession
    exit }
write-host "Checking Prerequisites" -ForegroundColor Green
    Import-Module AzureAD -ErrorAction stop 
} catch { 
        write-host "Could not find AzureAD Module. Installing."  -ForegroundColor Green
        install-module -Name AzureAD -Scope CurrentUser -force
        Import-Module AzureAD -ErrorAction stop 
     Import-Module MSOnline -ErrorAction stop
        } catch { 
     write-host "Could not find MSOL Module. Installing."  -ForegroundColor Green
     install-module -Name MSOnline -Scope CurrentUser -force
     Import-Module MSOnline -ErrorAction stop 

     Import-Module MicrosoftTeams -ErrorAction stop
    } catch { 
     write-host "Could not find MSTeams Module. Installing"  -ForegroundColor Green
     install-module -Name MicrosoftTeams -Scope CurrentUser -force
     Import-Module MicrosoftTeams
    Import-Module Microsoft.Online.SharePoint.PowerShell -ErrorAction stop
    } catch { 
    write-host "Could not find Sharepoint Module. Installing"  -ForegroundColor Green
    Install-Module -Name Microsoft.Online.SharePoint.PowerShell -Scope CurrentUser -force
    Import-Module Microsoft.Online.SharePoint.PowerShell
    Import-Module SkypeOnlineConnector -ErrorAction stop
    } catch { 
    write-host "Could not find Skype For Business Module. Installing"  -ForegroundColor Green
    Invoke-WebRequest "" -OutFile "$($env:TEMP)/SkypeOnlinePowerShell.exe"
    Start-Process "$($env:TEMP)/SkypeOnlinePowerShell.exe" -ArgumentList "/install /quiet" -wait
    Import-Module "C:\Program Files\Common Files\Skype for Business Online\Modules\SkypeOnlineConnector"
if(!$Credential){ $credential = Get-Credential }
write-host "Connecting to AzureAD Module" -ForegroundColor Green
Connect-AzureAD -Credential $credential
write-host "Connecting to MSOL Services" -ForegroundColor Green
Connect-msolservice -Credential $credential
write-host "Connecting to Teams Services" -ForegroundColor Green
Connect-MicrosoftTeams -Credential $credential
write-host "Connecting to Exchange Online" -ForegroundColor Green
$exchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "" -Credential $credential -Authentication "Basic" -AllowRedirection
Import-PSSession $exchangeSession -DisableNameChecking
write-host "Connecting to Security & Compliance Center" -ForegroundColor Green
$SccSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "" -Credential $credential -Authentication "Basic" -AllowRedirection
Import-PSSession $SccSession -Prefix cc
Connect-MicrosoftTeams -Credential $Credential
write-host "Getting initial domain for Sharepoint Online"
$InitDomain = (Get-MsolDomain | Where-Object { $_.IsInitial -eq $true }).name
$InitDomain = $InitDomain.Split(".")
$SharepointDomain = $InitDomain[0]
write-host "Connecting to $($SharePointDomain) Sharepoint"
Connect-SPOService -Url "https://$($SharepointDomain)" -credential $Credential
$sfboSession = New-CsOnlineSession -Credential $credential
Import-PSSession $sfboSession -AllowClobber

And that’s it! the code above is a bit rough around the edges but that is because it is just a simple function I use for my own personal preference. To use it, all you have to do is type Connect-Office365 and there you go 🙂

If you encounter any issues or have questions, let me know! and as always, Be careful and happy PowerShelling!

Running Office365 Powershell scripts cross tenant

When you manage multiple tenants or have a Microsoft Partner account to manage a lot of tenants it often gets annoying having to redeploy the same scripts to each tenant over and over. You can try using the MSOL commands but most of the times the scripts you are trying to run are Exchange, Skype for business, or Teams scripts, and you’re not able to run these just by using the Azure Active Directory Module for PowerShell.

The great thing is that Microsoft actually has a perfect solution for this by using your partner credentials cross tenant. You can change the session URL to match the specific client you are trying to manage, this means you can deploy scripts across all clients with relative ease when using the following scripts.

To get started on this, I’ll demonstrate how to get all mailbox sizes across your multiple tenants.
First, we’ll have to connect to Office365 by using the MSOL Microsoft Azure Active Directory Module for Windows PowerShell 

$clients = Get-MsolPartnerContract -All

When we’re connected, our client list is filled in $clients. This means we can loop trough each client and perform actions for them. In our case we’ll simply be gathering information, but you could also change settings such as disabling clutter, or enabling other functionality.

foreach ($client in $clients) { 
$ClientDomain = Get-MsolDomain -TenantId $client.TenantId | Where-Object {$_.IsInitial -eq $true}
    Write-host "Logging into portal for $($client.Name)"
    $DelegatedOrgURL = "" + $ClientDomain.Name
    $ExchangeOnlineSession = New-PSSession -ConnectionUri $DelegatedOrgURL -Credential $credential -Authentication Basic -ConfigurationName Microsoft.Exchange -AllowRedirection
    Import-PSSession -Session $ExchangeOnlineSession -AllowClobber -DisableNameChecking

Now that we’re connected to the Exchange PowerShell session for this client we can run whaterver Exchange commands we’d like. in our case, getting the mailboxes and respective size:

Get-Mailbox | Get-MailboxStatistics | Select-Object DisplayName, IsArchiveMailbox, ItemCount, TotalItemSize | format-table

When we’ve performed our commands, we do need to destroy our session as PowerShell sessions on Office365 can be rate limited.

Remove-PSSession $ExchangeOnlineSession

See that final curly bracket? With that one we close our for-each loop, Simply put we’re telling PowerShell that the loop is over, and it can continue with the next client in the list. If we put all of this together our script will look like this:

$credential = Get-Credential
connect-msolservice -Credential $credential
$clients = Get-MsolPartnerContract -All
foreach ($client in $clients) { 
    $ClientDomain = Get-MsolDomain -TenantId $client.TenantId | Where-Object {$_.IsInitial -eq $true}
    Write-host "Logging into portal for $($client.Name)"
    $DelegatedOrgURL = "" + $ClientDomain.Name
    $ExchangeOnlineSession = New-PSSession -ConnectionUri $DelegatedOrgURL -Credential $credential -Authentication Basic -ConfigurationName Microsoft.Exchange -AllowRedirection
    Import-PSSession -Session $ExchangeOnlineSession -AllowClobber -DisableNameChecking
    Get-Mailbox | Get-MailboxStatistics | Select-Object DisplayName, IsArchiveMailbox, ItemCount, TotalItemSize | format-table
    Remove-PSSession $ExchangeOnlineSession

So that’s it. you can easily replace the command for something as disabling clutter, focused inbox, enable auditing, etc. The great thing is that by combining this with an Azure Function gives your the ability to automatically apply your preffered settings to all clients. Happy PowerShelling!

Adding branding to the Office 365 portal

Hi all,

Today we’re going to change the branding of the Office365 portal. Something that helps clients identify that they are logging into the correct portal and are entering their usernames correctly. The great thing about this is you can have your own support information directly on the office365 portal.

you should make notes of some prerequisites before you start:
Company branding is a feature that is available only if you are using the Premium or Basic edition of Azure Active Directory, or are an Office 365 user. To check if branding is available you can try the following link

If you’ve checked that you can use branding, and you have your Office 365/Azure Admin account available you first log in on the portal at, If you’ve previously used Azure you can directly log into Azure using

After logging in browse to the admin panel and click on the “Azure Active Directory” link in the sidebar. This will open the Azure Portal. In case you have never signed into the Azure portal you will be forced to fill in some minor information such as e-mail address and physical address.

When logged into the Azure Portal you can click on Azure Active directory in the sidebar. You will not be presented with the following screen, Click on the area i’ve marked as yellow;

After clicking, a new sidebar appears and you can select the option to “Configure Company Branding Now”. You can upload your images directly and also change the login tips and support information. After uploading your images you can log out of the portal. When logging in again you will see the branding as soon as you’ve entered your e-mail address or when you log into the portal using the URL If you want users to access the webmail or portal using their own domain-name my advise would be to create a forward from to

An example of the branding can be found below;

A screenshot of the branding applied

A screenshot of the branding applied

Happy branding! 🙂

Creating a Poor Man’s Express Route

Lately we’ve been running into issues with client’s connecting to Office 365 and having high latency with this connection. this results in issues such as “Outlook is not Responding” & “Getting data from server”. Both of these issues disappear when running in Cached mode due to less data-traffic being required for normal operations such as opening e-mails and retrieving folder lists.

After researching we’ve found that this is mostly related to enormous detours that the ISP was taking to reach the Office 365 back-end. Mostly due to “cheaper” connections to the DUB(EU) or AMS(EU) data-centers of Microsoft. A good example of this can be seen with the Dutch ISP RoutIT, where you have 28 hops on average to the Office 365 back-end(of which 90% is still in their network), but only 5 hops to the Azure back-end strangely enough. After contacting Microsoft Support we’ve got the dreaded answer: Please invest into an Express-Route solution to circumvent these issues or have the provider resolve the connection problems.

We have multiple small sites with 5+ users that simply cannot afford this, and the clients can’t accept this latency. So we decided to ignore Microsoft’s advice and go on our own path of discovery 😉 After reading some of the service descriptions we’ve found that Microsoft assures better connections from Azure to Office 365 by using extensive QoS, and of course simply because the virtual machines are in the same network as the Office 365 services.

I’ve created the step-by-step below to research, test, and implement a solution.


first we needed to discover if the client actually suffered from this issue:

  • Open outlook on a user with connection issues.
  • Right-click the tray icon, while holding CTRL and click on “Connection Status”
  • In online mode you’d want the AVG. Proc time to be lower than 25(Cached mode this can be anything from 25-300)
  • In online mode you’d want the AVG RTT Time to be lower than 200(Cached mode this can be anything from 0-1000)
  • If you have results higher than above, you are possibly having issues connecting to and a poor-man’s ExpressRoute might help you run your outlook in Online mode.

After these tests, we run a Traceroute to tripple-check if the route is the issue, or if the connection latency itself is the issue. You expect a traceroute to to always be less than 20 hops, preferably in the 10-15 range, such as my results;


Tracing route to []
over a maximum of 30 hops:

  1     1 ms    <1 ms     1 ms
  2     9 ms    9 ms    10 ms
  3     7 ms     8 ms     7 ms []
  4     4 ms    4 ms    12 ms []
  5     4 ms    4 ms    13 ms []
  6     6 ms    7 ms    14 ms []
  7     13 ms    12 ms    15 ms []
  8     14 ms    16 ms    16 ms []
  9     6 ms     5 ms     5 ms

Trace complete.

If you have results as above, this solution might not be the one for you, Of course you can continue testing below but YMMV.

Create Virtual Machine Azure for performance tests & RRAS

Create a virtual machine in the Azure portal with the following specifications and configuration, If you have never created a virtual machine please use the  following guide on the Microsoft website. The interfaces changes every couple of months so its best to use the resources from Microsoft themselves.


  • at least 1 Core
  • at least 1.75GB of RAM
  • Static Internal IP for the server
  • Allow traffic: SSL to server(443)
  • Install the following roles: Remote Access, DHCP Server.
  • Setup DHCP and Remote Access.

After configuring the Azure side of the requirements make sure you configure SSTP VPN connections(Not required – For testing only.) and allow Router advertisement and IP forwarding. If you require a SSL Certificate you can use a free certificate from LetsEncrypt for this test.

After performing all configurations connect to the SSTP VPN from a client that experienced issues. Remember to set the “Use default gateway on remote network” to force all traffic over this tunnel for the sake of the test. Restart outlook and perform the testing steps once more. You should see a lower AVG. Proc Time and lower AVG. RTT Time. Have the user work on the SSTP connection for a day to see if they actually see a noticeable difference. If this is the case, its time for a more permanent solution.

Create IPSec tunnel

If the tests above have been performed, and you are ready for a permanent solution you can use Azure to create an ipsec tunnel, for that I advise the following guide.

After configuration of your ipsec tunnel, remember to tunnel all Office 365 traffic using the Microsoft IP address list found on this link. You can choose what traffic you route over the tunnel and what traffic you’d prefer using your local internet connection. When using the IPSEC tunnel remember that you must use your RRAS server as the gateway or else the routing will end on the side of the the Azure S2S VPN.

an ipsec VPN Tunnel and RRAS for NAT/Routing costs about 90% less than ExpressRoute, and might resolve most issue you have with sluggish outlooks, or slow responding Office 365 services.

Happy O365ing.

Managing Office 365/Azure tenants using powershell

One of the fantastic benefits of having Microsoft partner portal access is the ability to remote manage your clients/tenants. One of the downsides of this is that the partner portal is sometimes somewhat slow, or has a convoluted approach for remote management. A great way to resolve this is by using PowerShell to manage the tenants instead. This is just a quick post that could help you understand the commands involved;

First off – You’ll need to download and install the tooling required to connect with the Azure Powershell objects

  • Download the Microsoft Online Services Sign-In Assistant for IT Professionals: here
  • Download the Microsoft Azure Active Directory Powershell objects here

After downloading these and following all the required reboots you’ll be able to connect to Azure/O365 by issuing the following command in your new Azure Powershell Module;


After connecting to the MSOL service you now have access to the Microsoft online service modules. To manage your allowed partners we’ll first try to retrieve the tenant IDs that are available to us by executing the following command:

Get-MsolPartnerContract  | fl

Of course, this gives us way too much information – We only need to see the tenant id, to make sure we get this we execute the following:

Get-MsolPartnerContract -All
Get-MsolPartnerContract -Domainname ClientDomain.ORG

Now with this tenant ID, We’re able to execute PowerShell commands based on the tenant instead of our own environment simply by adding -tenantID to the normal MSOL commands. e.g.

Get-MsolUser -TenantId tenantID | set-msoluser -StrongPasswordRequired $true

Happy PowerShelling!

Using Azure MFA on an onsite RDS 2012R2

Azure MFA is a fantastic product – Its easy to setup and maintain, and not very costly to purchase (for pricing, click here). The great thing about Azure MFA is that it becomes very easy to secure your local directory, but also your remote desktop connections or RDS your 2008/2012 farms. There is just one downside; Out of the box Remote Desktop(terminal services) security does not work on Server 2012R2. I’m not sure why Microsoft decided to not support 2012R2 RDP access. I actually have a ticket outstanding with the Azure MFA team.

Of course there a solution; instead of securing direct RDP access, you can decide to secure Remote Desktop Gateway and have your users connect to the Remote Desktop Gateway. This might sound like a large change but I always advise my clients to use RD gateway – mostly due to it being accessible from almost all locations due to running on port 443 and having SSL security is a nice added bonus.

To add MFA to RD gateway we need to perform the following prerequisites ;

  1. Deploy a standard RD-Gateway, with NPS. This can be done on a separate server, or on the RDS server if you have a small farm.
  2. Deploy Microsoft Azure MFA on a different server, Please note: MFA and NPS cannot run on the same server due to NPS and MFA Radius clients running on the same ports. For a good tutorial on how to install Azure MFA see the following link: link
  3. Open port 443 to your RD gateway server.
  4. Choose a shared secret and note it – We’ll use the example “ThisIsNotASecret”

After performing the first 3 steps, its time to set up RD Gateway, NPS and the Azure MFA Server

RD Gateway setup:

  • Open the RD Gateway console, and right-click the server name, choose the tab “RD CAP Store”
  • Turn off the “Request clients to send a statement of health” check box if you have clients that are not NAP capable.
  • Select “Central server running NPS” and remove the current server if there is any, Now enter the hostname of the MFA server and our selected shared secret “ThisIsNotASecret”.
  • Close the Console – we’re done on this side. 🙂

NPS Setup:

  • Open the NPS console and go to RADIUS Clients, Right click and select New
  • Enter a friendly name – e.g. AzureMFA and note this.
  • enter the IP of the MFA server & our selected shared secret “ThisIsNotASecret”
  • click OK and move to “Remote Radius servers” in the left hand menu.
  • Double click the default TS Gateway Server Group and click edit, select the Azure MFA server from this list and click on load balancing.
    • Change the priority to 1 and the weight to 50
    • change the number of seconds before a connection is dropped to 45 seconds.(could be less, but I select 45 seconds to keep uniformity among servers)
    • Change the number of seconds before server is unavailable to 45 seconds.(could be less, but I select 45 seconds to keep uniformity among server
    • Click OK and close this window. Move to Connection Request Policies
  • You should see the default connection policy here – disable or delete this, as we will create our own policies.
  • Right click the policies and select “New” Name this policy “Receive MFA Requests”. The settings for this policy are:
    • NAS Port type: Virtual(VPN)
    • Client Friendly Name: AzureMFA
    • Authentication Provider: Local Computer
    • Override Authentication: Disabled
  • Create another policy and name this “Send MFA requests”. The settings for this policy are:
    • NAS Port type: Virtual (VPN)
    • Accounting provider name: TS GATEWAY SERVERS GROUP
    • Authentication Provider name: TS GATEWAY SERVER GROUP
    • Authentication provider: Forwarding request
  • And that concludes the NPS setup. Almost there! 🙂

Azure MFA Setup:

The last steps are fairly straight forward:

  • Open the MFA administrator console and select the RADIUS option in the left hand menu.
  • Enable Radius and on the clients tab add the IP of the NPS server.
  • enter the shared secret “ThisIsNotASecret”.
  • Now select the tab “Targets” and enter the IP of the RDS Server.
  • Go to the left hand menu and select user. Enable a user for tests with SMS messages or the app.
  • Open the Windows Firewall for inbound Radius traffic
  • Test! 🙂 If you followed the manual to the letter you now secured your RD Gateway with MFA.


Happy MFA’ing! 🙂

Stop AADSync logs from clogging up your servers disk space

I’ve been rolling out a lot of large AADSync deployments recently – I love how AADSync gives a SSO experience to the SMB markets without having to deploy ADFS. But as always these deployments in SMB markets have some downsides; The default configuration for AADSync/Dirsync is that it logs everything using tracing and ForeFront MSSQL Logs.

On smaller deployments or deployments where diskspace is expensive you might want to limit the usage of these logs. Of course my advice as always is to only make these changes when your DirSync/AADSync environment is running well and not experiencing any issues whatsoever.

To prevent the SQL database from growing to absurd sizes:

$DirSync = Get-WmiObject -Class “MIIS_SERVER” -Namespace “root\MicrosoftIdentityIntegrationServer”
$DirSync.ClearRuns([DateTime]::Today.AddDays(-$DaysToKeep)) | Format-Table ReturnValue

Save this script as .\ClearDirSyncDB.ps1 and run it. Of course you can set this as a schedulded task to automate it.

To prevent the TRACING folder from filling with logs:

  • Stop FIMSynchronizationService service via services.msc.
  • Run Notepad or your favorite text editor as administrator
  • Open the MIISERVER.Config file at X:\Program Files\Microsoft Online Directory Sync\SYNCBUS\Synchronization Service\Bin\miiserver.exe.config (Where X is the drive you installed AADSYNC)
  • Paste the following after
  • </appSettings>

  <trace autoflush=”true”>
  <add name=”DirectorySynchronizationTraceFile” type=”System.Diagnostics.TextWriterTraceListener” initializeData=”C:\Temp\DirectorySynchronizationTrace.log” traceOutputOptions=”DateTime” />
  <source name=”passwordSync” switchName=”sourceSwitch” switchType=”System.Diagnostics.SourceSwitch”>
  <add name=”console” type=”System.Diagnostics.ConsoleTraceListener”>
  <filter type=”System.Diagnostics.EventTypeFilter” initializeData=”Information” />
  <add name=”sharedTextLogger” type=”System.Diagnostics.TextWriterTraceListener” initializeData=”PasswordSync.log”>
  <filter type=”System.Diagnostics.EventTypeFilter” initializeData=”Verbose” />
  <remove name=”Default” />
  <add name=”sourceSwitch” value=”Verbose” />

  • Re-start FIMSynchronizationService service via services.msc.
  • Reactivate your syncronisation by running the configuration wizard and entering your domain details

And then you’re all done! dirsync should not longer eat up your precious diskspace 🙂

Creating hosted mailboxes while on premises mailboxes still exist.

One of the major drawbacks when using AADSync or Dirsync is that the remote mailboxes are not created when a local mailbox exists. This could prove difficult when migrating to Office 365 due to the mailboxes not existing simultaneously.

For instance we use third party migration tools that require the remote mailbox to exist. In a normal situation when assigning a office 365 exchange license to a user a mailbox is automatically created. When this user still has an on premises mailbox this will not happen due to the msExchMailboxGuid property that has been set in active directory. Removing this property also marks the mailbox for deletion in Exchange as it no longer is able to find the correct GUID for the user.

To resolve this we have 2 options, both require some work – It just depends on which you personally prefer

Option 1; Disable Dirsync or AADSync and create the mailboxes online.


The first option is quite simple and requires manual intervention, this option is best if the following statements are both true;

  1. you are not working in the Cloud environment yet and the users have never logged in.
  2. You are phasing out the local directory you are syncing from or are planning to remove Exchange locally on short notice.

If these are not true, I’d advise you to use option 2 which gives you more of a solution

First you remove licenses from all the users you have synced with Active Directory. Then disable Active Directory Sync. Your synchronized users will be converted into Cloud objects and you will be able to reassign licenses. When reassigning licenses an online mailbox will be created.

After 24 hours you can re-enable Active Directory Sync and the users Office 365 mailboxes will exist and ignore the msExchMailboxGuid

Option 2; Change the Dirsync or AADSync settings to prevent msExchMailboxGuid replication.

Another option is to prevent the synchronization of the msExchMailboxGuid – I often prefer this as I do not need to make any modifications to the already setup Cloud environment and it gives me more freedom when creating new users locally – I often incorporate auto provisioning script for mailboxes and other specialized items so I am still able to use these local scripts and not worry that the hosted mailbox will not be created.

As always, Please be careful when preforming these tasks. Do so at your own risk;

  • Launch X:\Program Files\Windows Azure Active Directory Sync\SYNCBUS\Synchronization Service\UIShell\miisclient.exe (where X: is the drive you installed the sync tool.)
  • Click on “Management Agents”
  • Right click on “Active Directory Connector” and click on “Configure Attribute Flow”
  • Open the ObjectType:User property.
  • Find the to msExchMailboxGuid.
  • Click the Delete button to remove the mapping to the msExchMailboxGuid.
  • Click Ok to save the changes
  • Close the MIIClient.

We have now prevented new objects from syncing the msExchMailboxGuid property to the cloud – The problem that remains is that existing objects have already replicated this property to the Office 365 Azure Active Directory. To make sure that at the next import job we clear this property on the hosted side we will need to perform a few SQL tasks. First we use SQL Management studio to connect to the Servername\MSONLINE SQL instance. When connected we run the following query;

UPDATE mms_metaverse SET msExchMailboxGuid = NULL WHERE (msExchMailboxGuid IS NOT NULL)

When this query runs the status of the msExchangeMailboxGuid in the SQL database is set to NULL. Your local active directory object is not changed. Now you can force a full import using the miisclient or using the Dirsync powershell module.

After a successful sync we are able to reassign a license and the hosted mailbox will be created! That way the local and hosted mailbox coexist and you are able to replicate the data using third party tools.

Have fun migrating!