Enable multi-factor authentication for office 365 users using PowerShell

The script enables strong authentication for Office 365 users from a CSV input. Before you turn on strong auth or multi-factor auth, take necessary measure to communicate with users to notify them that they will have to register their mobile phone for MFA. On the next sign-in attempt to Office 365, they will be prompted to provide OTP from the text message of their mobile phone, username and password to sign-in to Office 365. To sign-in to Outlook App they have to generate an app password, then use username and app password to sign-in to Outlook.

#CSV File Header UserPrincipalName
#Example row testuser1@domain.com

Import-CSv -Path “c:\Temp\StrongAuthUsers.CSV” | ForEach {
$Users=Get-MsolUser -User $UPN
$Auth= New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$Auth.RelyingParty = “*”
$MFA= @($Auth)

#Enable MFA for a user
#Set-MsolUser -UserPrincipalName test1@domain.com -StrongAuthenticationRequirements $mfa
#Enable MFA for all users in the CSV files(use with CAUTION!)
#You have to create app password after strong auth configuration

$Users | Set-MsolUser -StrongAuthenticationRequirements $MFA

#Disable strong auth requirement
# $Users | Set-MsolUser -StrongAuthenticationRequirements $False


Add multiple users to Office 365 security groups using PowerShell Scripts

Step1:  Connect MSOL Services


Step2: Find out ObjectID of the Security Group you would like add members to

Get-MsolGroup –Maxresults 100000 | Where-Object {$_.DisplayName -eq “Test Security Group”}

Get-MsolGroup –ObjectId “af407072-7ae1-4b07-a0ca-6634b7396054”


Sign-in to Portal.Azure.Com and Select Azure Active Directory>Security Groups>Search the Group>Go to properties of the group and copy the ObjectID

Step3: Create a CSV file with a header UserPrincipalName and list all email addresses in one column of CSV file e.g.




Step4: Execute the PowerShell Script to add users into the Security group

Copy the script and paste it in a notepad. Rename the notepad to Add-MsolGroupMembers.PS1

Import-CSv -Path “c:\Temp\testscript.CSV” | ForEach {


$Users=Get-MsolUser -UserPrincipalName $UPN

$Groupid = Get-MsolGroup -ObjectId “0c3c9f82-2392-43cc-bc00-b0d7b5734ac4”

$Users | ForEach {Add-MsolGroupMember -GroupObjectId $GroupID.ObjectID -GroupMemberObjectId $Users.ObjectID -GroupMemberType User}


Run the scripts

Configuring Retention Policies in Office 365

Retention policies are used to manage email lifecycle. Retention policies are applied by creating retention tags, adding them to a retention policy, and applying the policies to mailboxes.

To Create various retention policies in Office 365 using simple PowerShell. Connect Office 365 PowerShell module and run the below cmdlets. Tweak the cmdlets as desired.

7 Years (2,556 days) Retention Policy
New-RetentionPolicyTag -Name “7 Years Retention” -Type All -AgeLimitForRetention 2556 -RetentionAction DeleteAndAllowRecovery

2 Years (730 days) Retention Policy

New-RetentionPolicyTag -Name “2 years retention” -Type All -AgeLimitForRetention 730 -RetentionAction MoveToArchive

Delete voice mail messages after 30 days.

New-RetentionPolicyTag -Name “Delete Voicemail After 30 Days” -Type All -MessageClass Voicemail -AgeLimitForRetention 30 -RetentionAction DeleteAndAllowRecovery

Permanently delete messages in the Junk EMail folder after 30 days.

New-RetentionPolicyTag -Name “Delete Junk Email After 30 Days” -Type JunkEmail -AgeLimitForRetention 30 -RetentionAction PermanentlyDelete

Apply Retention Policy to a single mailbox
Set-Mailbox “John Doe” -RetentionPolicy “RP-Finance”

Apply Retention Policy to All Mailboxes
Get-Mailbox -ResultSize unlimited | Set-Mailbox -RetentionPolicy “Delete Junk Email After 30 Days”

Placing a mailbox on retention hold suspends the processing of a retention policy or managed folder mailbox policy for that mailbox. Retention hold is designed for situations such as a user being on vacation or away temporarily.

Enable Retention Hold on a Single Mailbox
Set-Mailbox “John Doe” -RetentionHoldEnabled $true

To extract retention holds for all mailboxes, issue the following cmdlets.
Get-Mailbox -ResultSize unlimited | Where-Object {$_.RetentionHoldEnabled -eq $true} | Format-Table Name,RetentionPolicy,RetentionHoldEnabled -Auto

Office 365: Configuring catch-all mailbox during migration

Step1: Create Catch-All Mailbox

1. Sign in to portal.office.com>Active Users

2. Create a new user named “Catch-All-Mailbox” and assign licenses either E1 or E3.

Step2: Create exception Security Group (Optional Step)

1. Log onto Office 365 admin portal

2. Go to Admin>Exchange>Recipients>Groups

3. Create a new Security Group named Catch-All-Exception

4. Add members to this group

Step3: Create a Transport Rule

5. Log onto Office 365 admin portal

6. Go to Admin>Exchange>Click “Mail Flow” icon, Click “Rules”

7. Click the “+” icon, then “Create a new rule”

8. As soon as the new rule box appears, click “More Options…” link towards the bottom of the page

9. Give rule a name, CatchAll-Mailbox Migration

10. Change the “apply this rule if…” to “The Sender is…”–>”Internal/External”–>”Outside this Organisation”

11. Change the “do the following…” to “Redirect the message to…”–>”These recipients”–> then select “Catch-All-Mailbox”

12. *OPTIONAL*  Click “Add Action” and then “Modify the message properties”–>”Set a message header”, then set the header to “X-Catchall-Migration-Rule” and value to “Yes”

13. Under “Except if”, Click “Add action” and then “If Recipient…”–>”Is this person”–>and select the “all” Group which contains all exclusions (this should be the “All” group which contains all users/groups INCLUDING the Catchall mailbox/group that you don’t want diverted)

14. Save

15. Once Migration is complete, delete the rule.


Branding and Customizing the ADFS Sign-in Pages

Branding and promoting Company name and logos are common business practices. You would like to see your own brand whilst signing into to Microsoft Office 365. ADFS provides opportunity for businesses to customize sign in page and promote own brand. Here are the simple steps and procedure to brand ADFS sign in page.

Remote into ADFS Server and implement below steps to customize ADFS Portal.

Change company name

Import-Module ADFS

Set-AdfsGlobalWebContent –CompanyName “Domain Corp”

Change company logo

Create a logo with 260×35 pixels @ 96 dpi with a file size of no greater than 10 KB and save the file into a path e.g. C:\Domain\logo.png. Then execute the PowerShell.

Set-AdfsWebTheme -TargetName default -Logo @{path=”c:\Domain\logo.png”}

Change Illustration

Create an illustration photo to be displayed on the left hand side of the sign in page. Photoshop illustration.png file to be 1420×1080 pixels @ 96 DPI with a file size of no greater than 200 KB.

Set-AdfsWebTheme -TargetName default -Illustration @{path=”c:\Domain\illustration.png”}

Add sign-in page description

Set-AdfsGlobalWebContent -SignInPageDescriptionText “<p>Sign-in to Domain Corp requires you comply with corporate information uses policy. Click <A href=’http://www.Domain.com/policies/’>here</A&gt; for more information.</p>”

Add Help Desk Link

Set-AdfsGlobalWebContent -HelpDeskLink https://www.Domain.com/help/ -HelpDeskLinkText Help

Add Home Link

Set-AdfsGlobalWebContent -HomeLink https://www.Domain.com/home/ -HomeLinkText Home

Add Privacy Link

Set-AdfsGlobalWebContent -PrivacyLink https://www.Domain.com/privacy/ -PrivacyLinkText Privacy

Customize the Update Password page description

Set-AdfsGlobalWebContent -UpdatePasswordPageDescriptionText “This is the Domain Corp Update Password page.”

Customise error page

Set-AdfsGlobalWebContent -ErrorPageGenericErrorMessage “This is a generic error message.  Contact Domain Corp IT Support on 123466 for assistance.”

Build Custom theme

Export current theme using below Cmdlets.

Export-AdfsWebTheme -Name default -DirectoryPath c:\Domain\Theme\Custom

Replace existing theme with Custom Theme.

New-AdfsWebTheme -Name Custom -SourceName default

Open the script file you downloaded from “C:\Domain\Theme\Custom\script\onload.js” in Notepad

Add this line at the bottom of the script to change the placeholder text in the username input box

document.forms[‘loginForm’].UserName.placeholder = ‘username@domain.com’;

Add these blue lines at the bottom of the script to add a text above the login form, this is an example from Microsoft that you can find further down

// Sample code to update the username format test “someone@example.com”.

var userNameInput = document.getElementById(Login.userNameInput);
if (userNameInput) {
// userNameInput element is present, modify its properties.
userNameInput.setAttribute(‘placeholder’, ‘Corp UserName OR EmailAddress’);

// Sample code to change “Sign in with organizational account” string.

// Check whether the loginMessage element is present on this page.
var loginMessage = document.getElementById(‘loginMessage’);
if (loginMessage)
// loginMessage element is present, modify its properties.
loginMessage.innerHTML = ‘Sign in with your company email address OR Corp UserName and password’;

var AppendUPN = function () {
var userName = document.getElementById(Login.userNameInput);

if ((/^\d+$/.test(userName.value)) && userName.value.length == 6)
userName.value = ‘Corp\\’ + userName.value;
return true;

document.getElementById(‘submitButton’).onclick = new Function(“AppendUPN();return Login.submitLoginRequest();”);
document.getElementById(‘loginForm’).onkeypress = function(event){ if(event && event.keyCode == 13) {AppendUPN();Login.submitLoginRequest()}};

When you are done and save changes. Upload the changes to the newly created theme

Set-AdfsWebTheme -TargetName Custom -AdditionalFileResource @{Uri=’/adfs/portal/script/onload.js’; path=”c:\Domain\Theme\Custom\script\onload.js”}

Now apply the changes with this command

Set-AdfsWebConfig -ActiveThemeName Custom

Use these commands to verify your settings



Centralized Mailflow: NDR Remote Server returned ‘550 5.7.1 Unable to relay’


  • Mailbox hosted on the Exchange Online
  • Hybrid on-prem Exchange 2010/2013 with Microsoft Exchange Online
  • Centralized Mailflow configured for Exchange 2013
  • Route all emails through on-premises configured for Exchange 2010
  • Accepted domain configured either Managed or Authoritative on the Exchange Online Side 
  • MX Record pointed to third party cloud Antispam or On-prem Antispam/Firewall

 Issue: When you send email from a mailbox hosted in Exchange Online to an internal recipient or an external recipient via on-premises server, you receive a NDR ‘550 5.7.1 Unable to relay’

Root Cause: There are customers who would like to utilize existing investment on the on-premises Antispam filter or use third part cloud based Antispam filter for compliance purpose. Hence these customers configured centralized mailflow on the hybrid configuration wizard which lead to “unable to relay” NDR when they change few configuration and introduce new domain on the Exchange Online. There are many possible reasons why you have been issued with a NDR ‘550 5.7.1 Unable to relay’.

  • You have added multiple federated domains (e..g @domain1.com, @domain2.com ) but these domains (e.g. @domain1.com, @domain2.com) are not in Hybrid Configuration
  • You have added multiple federated domains (e.g. @domain1.com, @domain2.com ) and domains (e.g. @domain1.com, @domain2.com ) have been setup as “Authoritative Domain” instead of “Internal Relay” on the Exchange Online side
  • You have added multiple federated domains (e.g. @domain1.com, @domain2.com ) but you have configured Office 365 Connectors to Send and Receive Email from only One Domain e.g. domain.com. Wild card “*” not configured within the Send Connector of Exchange Online.
  • Microsoft has changed EOP IP addresses and you did not add latest EOP IP Addresses on the Receive Connector of Edge Server
  • You configured an application to use Office 365 SMTP Relay but the Receive Connector of on-premises server has not been configured to accept email from any recipient

 To remediate the root cause, follow the steps.

  1. Copy the Message Header of Original NDR and Paste on the message analyser of https://testconnectivity.microsoft.com/ website. Analyse the message. Find out which IP address the message coming from e.g. EOP APAC IP Address is Make sure these EOP IP Addresses are added on the receive connector of the on-premises server. List of EOP IP Addresses are subject to change without notice. Add all EOP IP addresses on the receive connector “Inbound from Office 365”. Refer to Microsoft KB 2750145
  2. Make sure Datacentre IP Addresses are added on the Receive Connector Properties. Refer to TechNet Blog.
  3. View Extended Rights of Receive Connectors of On-premises Server.

 Get-ReceiveConnector | Get-ADPermission | where {$_.User -like ‘*anonymous*’} | ft identity,user,extendedrights,accessrights

     4. Assign Extended Rights to accept email from any recipient.

Get-ReceiveConnector Inbound from Office 365 | Add-ADPermission -User “NT AUTHORITY\ANONYMOUS LOGON” -ExtendedRights “ms-Exch-SMTP-Accept-Any-Recipient”

     5. Open Office 365 Connector on the Office 365 Admin Center and make sure you have entered “*” wild card as the domain

    6. Rectify SPF Record with the following records. If you have DKIM Record and DMARC Record. Rectify those records as well. SPF Record of domain.com looks like this one

 v=spf1 ip4:<Public IP Address of domain.com>, ip4: :<Public IP Address of MX Record>, ip4: :<Public IP Address of Application/devices>, include:spf.protection.outlook.com ~all

   7. Download .NET Framework 4.5 and install .NET Framework. .NET is a Pre-req. Run Hybrid Configuration wizard select desired Federated Domains, Select all CAS Servers, Type the correct public IP addresses of Edge Server, select centralised mailflow, Select Correct certificate. Complete the Wizard.

 8. Open Send Connector on the On-premises Server, Remove all the Hub/CAS servers and add Edge Servers.

 Restart Transport Services from On-premises Server

 9. On a Hybrid Configuration, you must configure Accepted Domain as Authoritative Domain on the On-premises side and Office 365 side as Internal Relay. For Example, domain1.com should be configured as Authoritative Domain on the on-premises side and domain1.com should be configured as Internal Relay on the Exchange Online side.  

 10. Open On-premises Exchange Management Shell and run Start-EdgeSynchronization start syncing Edge Transport Server.

 11. Test mailflow from internal and external sender to internal recipient

 Relevant Articles

Fix email delivery issues for error code 5.7.1 in Office 365

Exchange Online Protection IP addresses

Hybrid Mailflow Best Practices

Set up connectors to route mail between Office 365 and your own email servers

Transport Options Hybrid Deployment

 Transport Routing Hybrid Deployment 

Export Office 365 Licenses

An Office 365 admin perform one repetitive task on the Azure AD PowerShell is to generate license report from Office 365. Two simple Cmdlets Get-MsolUser  and Get-MsolAccountSku can be used to generate many reports. This article uses variation of these Cmdlets to extract license report.

Connect to Exchange Online Services

Import-Module MSOnline

Find out what licenses are available for you to consume from Office 365 tenant.

Get-MsolAccountSku | Format-Table AccountSkuId, SkuPartNumber

Generate a license report for all users with Office 365 licenses

Get-MSOLUser –MaxResults 100000 | select-object Displayname,userprincipalname,islicensed,{$_.Licenses.AccountSkuId}| Export-CSV c:\temp\userlist.csv –NoTypeInformation

Once CSV is generated, just filter the report to suit your need.

Find Consumed Licenses for specific license type

Get-MsolAccountSku | Where-Object {$_.SkuPartNumber -eq “ENTERPRISEPACK”}

Find all consumed licenses


Find all licenses users in a specific domain

Get-MsolUser -MaxResults 100000 –DomainName domain.com.au | Select-Object Displayname,UserPrinciPalname,IsLicensed

Find out all users who consumed any licenses

Get-MsolUser -all | where {$_.isLicensed -eq “True”} | Select-Object DisplayName,UserPrincipalname,IsLicensed

Find out all users in a specific location who consumed any licenses

Get-MsolUser -all | where {$_.UsageLocation -eq “Australia”} | Select-Object DisplayName,UserPrincipalname,IsLicensed,UsageLocation