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!

8 thoughts on “Office 365 PowerShell and Scheduled Tasks

  1. Josh says:

    Hey Miss Tech

    Awesome article, thank you! I’ve run through this process, and for some reason am not able to get the job to ever successfully execute via scheduled task. The script does what I want, and executes properly if run from an ISE or PS window, but the second I try to schedule it, it won’t run. My execution policy is set to RemoteSigned (and I’ve tried the script both signed and not signed) and I’ve tried setting the scheduled task up on multiple systems, two Server 2K12R2 boxes and a Windows 10. Across all of them, the script runs fine if manually run, but won’t ever execute if called from a scheduled task. I’ve tried chasing some of the 0x errors down from the task scheduler with no luck. Any ideas…?


    • Hi there! I’d check the settings of the task itself if I were you, such as making sure the script will run whether the user is logged in or not. The user account running the task also needs to be the same as the user who encrypted the password. Hope this helps a bit!


  2. Markus says:

    Thanks for posting this – I was able to follow it and get connected to our tenant and run a script. We’ll be able to start automating tasks again!


  3. Don Landry says:

    Hi Miss Tech,

    I am running Powershell scripts as Scheduled tasks on an in house on prem server against SharePoint online. One thing I run into intermittently is 401 unauthorized user issues against my SharePoint tenant. Even through the account I am using is an admin account and works fine I will get this error periodically. I’ve yet to find anything online that would explain in detail the authorization requirements of scripts needed to be run daily, weekly etc. Can you by chance point me to any documentation that outlines setting up PowerShell scripts to run on a regular schedule and what is required to ensure authorization errors don’t occur? I find these run like clock work for months and then start failing for no apparent reason, then all of a sudden are working fine again. I was going to put in a service ticket but saw your blog and thought I’d ask.




    • Hey Don, quite often this is due to having too many PS sessions open for that admin account. Have you tried using a dedicated account for the scheduled tasks?


      • Don Landry says:


        I do have a specific account that I use and when the 401 was happening I shut everything down to make sure I only had on PS Session going. Its happening on REST services. Here is a snippet and this typically works great without flaw. I pass in the ProjectOnline tenant url to execute the query, pass in the credentials etc.

        Before I call my rest service I grab my account from a config file and then pass it into a function that executes my rest service.

        I encrypt my password and then unexcrypt it using the following:

        $securePass = ConvertTo-SecureString $password -Key ([Byte[]]$key.Split(” “))

        Then I call my rest service passing in my username, password and tenant url:

        $url = $PWAURL + “/_api/ProjectData/Projects()?`$Filter=ClarityID_P ne ”&`$Select=ProjectId,ClarityID_P,ProjectName”

        while ($url){
        [Microsoft.SharePoint.Client.SharePointOnlineCredentials]$spocreds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($PWAUName, $sPass);
        $webrequest = [System.Net.WebRequest]::Create($url)
        $webrequest.Credentials = $spocreds
        $webrequest.Accept = “application/json;odata=verbose”
        $webrequest.Headers.Add(“X-FORMS_BASED_AUTH_ACCEPTED”, “f”)


  4. Don Landry says:

    again this typically works without issue, then periodically starts throwing a 401 unauthorized user, then after a few days and multiple attempts it works again.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s