Category Archives: Powershell

Onedrive For Business Silent Deployment, Configuration and Folder Redirection through Intune MDM for Windows 10

I’ve taken information from several sources and written a single “Do It All – Onedrive For Business configuration script” for the Windows 10 Modern Management (Intune MDM Azure AD Join) scenario.

The script can be deployed through Intune to your Windows 10 MDM clients and will do the following silently:

    • check latest O4B version and update to it
    • detect O4B configuration, start auto config
    • completely silent / invisible configuration with SSO
    • optionally, enable Files On Demand
    • optionally, redirect folders to Onedrive
    • optionally, copy old content

O4BClientAutoConfig + source code.


Restarting a x86 Powershell Process as x64 automatically

Let’s say something (like Intune) starts your Powershell script in 32 bit and you really need commands that only 64 bit Powershell has….

#Restart self in x64
If (!([Environment]::Is64BitProcess)){ 
        Write-Output "Running 32 bit Powershell on 64 bit OS, restarting as 64 bit process..."
        $arguments = "-NoProfile -ExecutionPolicy ByPass -WindowStyle Hidden -File `"" + $myinvocation.mycommand.definition + "`""
        $path = (Join-Path $Env:SystemRoot -ChildPath "\sysnative\WindowsPowerShell\v1.0\powershell.exe")
        Start-Process $path -ArgumentList $arguments -wait
        Write-Output "finished x64 version of PS"
        Write-Output "Running 32 bit Powershell on 32 bit OS"

With the above at the top of your script, it’ll automatically restart itself if needed 🙂

Exchange Online reconnect script v2

A few weeks ago I posted a script that would automatically, periodically, reconnect to Exchange Online. In field testing it would still prompt for credentials after 1-2 days, whatever I did.

So I took a different route and am now rewriting Microsofts’ module on the fly to no longer prompt for credentials. If you use below function to connect to Exchange Online, you should never receive reconnect prompts 🙂

disclaimer: don’t overwrite $o365Creds with invalid creds elsewhere in your script as those are used globally.

function buildResilientExchangeOnlineSession {
    Write-Verbose "Connecting to Exchange Online"
    Set-Variable -Scope Global -Name o365Creds -Value $o365Creds -Force
    $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri -Credential $o365Creds -Authentication Basic -AllowRedirection
    Import-PSSession $Session -AllowClobber -DisableNameChecking
    Write-Verbose "Connected to Exchange Online, exporting module..."
    $temporaryModulePath = (Join-Path $Env:TEMP -ChildPath "temporaryEXOModule")
    $res = Export-PSSession -Session $Session -CommandName * -OutputModule $temporaryModulePath -AllowClobber -Force
    $temporaryModulePath = Join-Path $temporaryModulePath -ChildPath "temporaryEXOModule.psm1"
    Write-Verbose "Rewriting Exchange Online module, please wait a few minutes..."
    $found = $False
    (Get-Content $temporaryModulePath) | % {
        if(!$found -and $_.IndexOf("host.UI.PromptForCredential(") -ge 0){
            $line = "-Credential `$global:o365Creds ``"
                $found = $True
            $newContent += $line
            $newContent += $_
        $newContent += "`r`n"
    $newContent | Out-File -FilePath $temporaryModulePath -Force -Confirm:$False -ErrorAction Stop
    $Session | Remove-PSSession -Confirm:$False
    Write-Verbose "Module rewritten, re-importing..."
        Import-Module -Name $temporaryModulePath -Prefix $commandPrefix -DisableNameChecking -WarningAction SilentlyContinue -Force
        Write-Verbose "Module imported, you may now use all Exchange Online commands using $commandPrefix as prefix"
        Import-Module -Name $temporaryModulePath -DisableNameChecking -WarningAction SilentlyContinue -Force
        Write-Verbose "Module imported, you may now use all Exchange Online commands"
    return $temporaryModulePath



CSP delegation on non CSP azure subscriptions

If you’re a Cloud Solution Provider and you supply a CSP azure subscription to that tenant, your AdminAgents will have Owner access to that subscription. Lets say the customer also has an existing subscription.

When you add your accounts as Owner to the existing tenant subscription, your users are added as Guest accounts in the customer’s Azure AD. This removes the delegated CSP subscriptions because the reference to the foreign accounts breaks.

So, alternatively, use

Get-AzureRmRoleAssignment -Scope "/subscriptions/<SUBSCRIPTION ID>

on the CSP subscription to get the Foreign Principal ID for your own tenant. Then use

New-AzureRMRoleAssignment -ObjectId <FOREIGN PRINCIPAL ID> -Scope "/subscriptions/ 
<SUBSCRIPTION ID>" -RoleDefinitionName Owner

to add the foreign principal ID to the existing customer subscription to get delegated access 🙂


Exchange Online Reconnect script

I’ve seen and known many scripts that interact with Exchange Online for extended periods of time. After a while, Exchange Online likes it if you reconnect, this can be an Impliciet Authentication popup, or it can simply drop you based on what command you’re using.

If you call the following function every loop in whatever you’re doing, it’ll automatically force a reconnect to Exchange Online every hour (adjustable if you prefer longer):

Edit: read v2 of this post 🙂

Note: if you run this script in an Exchange Shell, something in the Exchange Shell modules will still prompt for reconnects every 1-2 days. In a normal PS window, I’ve verified it working for up to a week until it asks for a reconnect.

Public Folder to Office 365 Groups Migration Script

Earlier, I wrote on a new technet article that details migration to Office 365 groups from on prem public folders. Actually walking through that I noticed some inconveniences I figured I could improve on with a script. The main one being that the endpoint in Office 365 only supports a single Public Folder, excluding child folders.

So I wrote up a script (with resume support) that will map your Public Folders to O365 Groups and migrate them in as many batches as are required, fully automated.

You’ll end up with a nice csv file with all the details. Note:

  1. this script expects you to know what you’re doing!
  2. only tested with Exchange 2010 as source
  3. everything on prem is left untouched
  4. groups are not mail enabled, and security settings are not copied
  5. contacts are not copied
  6. make sure you read the code/in-script instructions between line 1 and line 48, and then if you’re curious, from line 71720

update 05/01: improved the connection status check + reconnect for remote ExO and fixed report file path auto generation

update 11/01: moved everything to start-job so exchange sessions are always isolated (no prompting after 1-2 days) and added total migration overview display 

update 25/01: exported the remote exchange module and added it as inline code with a modification so it won’t prompt for credentials, nothing else seems to otherwise prevent such prompts. This means the module may not match Microsoft’s if they update Exchange Online. Let me know if that causes issues for you or re-create it yourself with export-pssession and replace.

Setting up Okta User -> Office 365 contact synchronisation

Okta natively does not allow you to sync users to Office 365 contacts; they either exist as users in Office 365, or they don’t exist at all.

In hybrid scenarios where you are doing a staged migration to Office 365, or where you simply manage your contacts in Okta, you may want to populate the Global Address List in Office 365 with your Okta users.

I’ve written a simple solution for this, you will require:

  1. Okta Admin Access (to obtain a token)
  2. Office 365 credentials (to write / modify Contacts)
  3. An Azure Subscription (for automation)

The solution will sync your users in Okta to Office 365, take note of the following: Continue reading Setting up Okta User -> Office 365 contact synchronisation

Migrating Public Folders to Office 365 Groups

Recently, I stumbled upon an article detailing how to migrate on-premises (or online) Public Folders to Office 365 Groups

Of course I had to try that out asap 🙂 I used an older script to make a report of my on prem public folders to pick one below 50GB.

It was mostly a breeze and the interface of Office 365 groups allows users to easily search and administer their old Public Folders. We purposely only use them for archive access, where the IM team manages access to the groups holding PF data. I can really recommend this strategy, especially if you can easily split them up in under 50GB sized groups.

I did have one slight error you may run into:

“MigrationTransientException: Couldn‎’t find a request that matches the information provided. Reason: No such request exists in the specified index. –> Couldn‎’t find a request that matches the information provided. Reason: No such request exists in the specified index. “

Reason for this: The source public folder path is incorrect, make sure your CSV is mapped correctly or your batch will spin forever (or at least longer than I had patience), never completing.



Redirecting My Documents to Box Drive, using Intune (Windows 10 MDM)

One of my customers is doing a full cloud-only pilot of Windows 10, Mobile (MDM) managed through Intune to leverage a least-infrastructure solution worldwide.

They’re using Azure AD, but opted out of Onedrive for Business and are using Box Drive instead.

To encourage their users to actually save data to Box instead of Onedrive or locally, I wrote a little Powershell script (since Intune native PS script deployment isn’t live yet).  This script checks if Box has been configured, if not it throws a little popup to the user. If it has, it redirects My Documents, and copies any existing content from it to Box.

I used Advanced Installer to wrap this in an MSI for easy deployment through Intune, and would like to share this with you 🙂

ZIP download:

Zip contents:

  1. ps1 file which does the actual work
  2. vbs wrapper to run it silently (hidden windows)
  3. .aip file (advanced installer)
  4. .msi file (to roll out with Intune or other tools)

Update 10/10:

  1. added a caching mechanism to force Box Drive to locally cache files (normally Box only does this when they are opened)
  2. added a caching filter to prevent caching of files above 25MB to reduce initial bandwidth overhead

Update 04/12:

  1. added a 5 minute loop / wait cycle to allow box to initialize, as the script may otherwise run before Box can initialize

On-Demand MSI customization using Azure Functions

This post describes how you can use the WIX Toolkit or any DLL file in an Azure Function, in this case to edit an MSI file on the fly. The WIX Toolkit is free, but only runs on Windows. Azure Functions run on Windows too, isn’t that nice 🙂

So, an example use case could be my OnedriveMapper MSI file, which is installed with a configuration GUID property by an admin to customize OnedriveMapper. If that GUID was already in the MSI, no such parameter would be necessary.

Using an Azure function in a download link or http request, we could insert a GUID on the fly and create personalized MSI files on demand.

I’ll leave other applications to your imagination, let’s get started!

  1. Download the WIX toolkit (binaries)
  2. Extra Microsoft.Deployment.WindowsInstaller.dll
  3. Add it to the function files or host it at an URL somewhere. In my example, I’m hosting it at
  4. Add your MSI file to your function files or host it at an URL somewhere. In my example, I’m hosting it at
  5. Add the following code to the Azure Function:

Continue reading On-Demand MSI customization using Azure Functions