Apply Office 365 Retention Policies to all customers via PowerShell and Delegated Administration

eDiscovery and Litigation Holds are being phased out in favour of Retention Policies in the Office 365 Security and Compliance Center. The newer Retention Policies allow you to set hold and delete rules for data across a number of Office 365 services at once – and they’re quite easy to set up. See this Microsoft support article for more info.

Retention requirements can differ depending on the organisation, so it makes sense that these aren’t switched on by default. If you’d like to apply a baseline retention policy for all of your customers that haven’t set one up, you can follow the guides below.

An example Office 365 Retention Policy

In this example we’ll be creating a retention policy that applies to Exchange, Public Folders, Sharepoint, OneDrive and Office 365 Groups. This policy does not apply to Skype for Business content (apart from the Conversation History folder, which is stored in Exchange). This example rule will retain all data for forever. Note that the Exchange retention rules will only apply to Exchange Online Plan 1 mailboxes with Online Archiving, or Exchange Online Plan 2 mailboxes.

To create a retention policy in Office 365, we need to connect to the Office 365 Security and Compliance Center via Powershell. Then we need to run two commands – New-RetentionCompliancePolicy and New-RetentionComplianceRule.

New-RetentionCompliancePolicy

This cmdlet creates the Retention Policy and defines which services will be covered by it. For most Office 365 services, a policy can apply to everyone, or just specific users. Skype for Business requires that you specify which users are covered by the policy. For more information about the options for this cmdlet, see this article.

New-RetentionComplianceRule

This cmdlet specifies which actions will be taken on the content that the retention policy applies to. You can choose how long to keep information, what to do when the retention age is reached, and define whether those actions apply to different types of sensitive information. For more information about the options for this cmdlet, see this article.

Create an Office 365 Retention Policy for a single Office 365 tenant via PowerShell

Connect to the Office 365 Security and Compliance Center via PowerShell. Follow our quick guide for info on how to set this up. Edit and run the following cmdlets New-RetentionCompliancePolicy -Name "Company Policy" -ExchangeLocation All -SharePointLocation All -ModernGroupLocation All -OneDriveLocation All -PublicFolderLocation All -Enabled $true New-RetentionComplianceRule -Name "Company Policy Rule" -Policy "Company Policy" -RetentionDuration Unlimited

Create an Office 365 Retention Policy for all Office 365 tenants via PowerShell and Delegated Administration

You can apply this policy to all users using delegated administration. At this point, this script doesn’t support delegated administrator accounts that use two factor authentication. This script will check whether a SharePoint URL exists for a customer before attempting to apply retention to anything other than Exchange.

Open Visual Studio Code or PowerShell ISE Create a new PowerShell file then edit, save and run the following script: # Establish a PowerShell session with Office 365. You'll be prompted for your Delegated Admin credentials $PolicyName = "Company Policy" $Cred = Get-Credential Connect-MsolService -Credential $Cred $Comment = "If you require assistance retrieving data protected by this retention policy, please contact your associated Microsoft Partner: $((Get-MsolCompanyInformation).displayname)" $customers = Get-MsolPartnerContract Write-Host "Found $($customers.Count) customers for $((Get-MsolCompanyInformation).displayname)." foreach ($customer in $customers) { $InitialDomain = Get-MsolDomain -TenantId $customer.TenantId | Where-Object {$_.IsInitial -eq $true} $SharepointURL = "$($InitialDomain.name.split(".")[0]).sharepoint.com" Write-Host "Applying retention policy to $($Customer.Name)" $DelegatedOrgURL = "https://ps.compliance.protection.outlook.com/powershell-liveid?DelegatedOrg=" + $InitialDomain.Name $s = New-PSSession -ConnectionUri $DelegatedOrgURL -Credential $Cred -Authentication Basic -ConfigurationName Microsoft.Exchange -AllowRedirection Import-PSSession $s -AllowClobber # By default, we don't want to add our retention policy if the customer has already configured their own. This is checking for existing policies. $ExistingPolicy = Get-RetentionCompliancePolicy # If you want to add your policy no matter what, use the below cmdlet. Your policy will be added if a policy with the same name doesn't already exist. # $ExistingPolicy = Get-RetentionCompliancePolicy | Where-Object {$_.name -contains $PolicyName} if ($ExistingPolicy.Count -eq 0) { # We're checking if the customer has a SharePoint URL. If so, we'll add SharePoint, OneDrive and Modern Group data to the Retention Policy. if (Test-Connection $SharePointURL -Count 1 -ErrorAction ignore) { New-RetentionCompliancePolicy -Name $PolicyName -ExchangeLocation All -SharePointLocation All -ModernGroupLocation All -OneDriveLocation All -PublicFolderLocation All -Enabled $true -Comment $Comment -ErrorAction Ignore } else { New-RetentionCompliancePolicy -Name $PolicyName -ExchangeLocation All -PublicFolderLocation All -Enabled $true -Comment $Comment -ErrorAction Ignore } New-RetentionComplianceRule -Name "$PolicyName Rule" -Policy $PolicyName -RetentionDuration Unlimited -ErrorAction Ignore } else { Write-Output "Policy exists for $($Customer.Name)" } Remove-PSSession $s }

Create an Azure Function to ensure that all customers’ tenants are covered by an Office 365 Retention Policy

You can use an Azure Function to ensure that all current and future customer Office 365 tenants remain covered by a Retention Policy. Follow this guide on how to set up an Azure Function to connect to Office 365.

Before moving on, you should have completed the following:

Create a new Azure Function app service

Created a new timer triggered PowerShell function – you can call this one SetUnlimitedRetentionPolicy

Set the function to run as often as required (eg Monday – Friday 9:30AM GMT time)

Downloaded the MSOnline PowerShell module locally, then uploaded it to your Azure Function via FTP

Secured your Office 365 Credentials in your Azure Function properties

Replace the code in your Azure Function with this script:

Write-Output "PowerShell Timer trigger function executed at:$(get-date)"; $FunctionName = 'SetUnlimitedRetentionPolicy' $ModuleName = 'MSOnline' $ModuleVersion = '1.1.166.0' $username = $Env:user $pw = $Env:password #import PS module $PSModulePath = "D:\home\site\wwwroot\$FunctionName\bin\$ModuleName\$ModuleVersion\$ModuleName.psd1" $res = "D:\home\site\wwwroot\$FunctionName\bin" Import-module $PSModulePath # Build Credentials $keypath = "D:\home\site\wwwroot\$FunctionName\bin\keys\PassEncryptKey.key" $secpassword = $pw | ConvertTo-SecureString -Key (Get-Content $keypath) $credential = New-Object System.Management.Automation.PSCredential ($username, $secpassword) # Connect to MSOnline Connect-MsolService -Credential $credential $PolicyName = "Internal Company Policy" $Comment = "If you require assistance retrieving data protected by this retention policy, please contact your associated Microsoft Partner: $((Get-MsolCompanyInformation).displayname)" $customers = Get-MsolPartnerContract Write-Output "Found $($customers.Count) customers for $((Get-MsolCompanyInformation).displayname)." foreach ($customer in $customers) { $InitialDomain = Get-MsolDomain -TenantId $customer.TenantId | Where-Object {$_.IsInitial -eq $true} $SharepointURL = "$($InitialDomain.name.split(".")[0]).sharepoint.com" Write-Output "Applying retention policy to $($Customer.Name)" $DelegatedOrgURL = "https://ps.compliance.protection.outlook.com/powershell-liveid?DelegatedOrg=" + $InitialDomain.Name $s = New-PSSession -ConnectionUri $DelegatedOrgURL -Credential $credential -Authentication Basic -ConfigurationName Microsoft.Exchange -AllowRedirection Import-PSSession $s -AllowClobber # By default, we don't want to add our retention policy if the customer has already configured their own. This is checking for existing policies. $ExistingPolicy = Get-RetentionCompliancePolicy # If you want to add your policy no matter what, use the below cmdlet. Your policy will be added if a policy with the same name doesn't already exist. # $ExistingPolicy = Get-RetentionCompliancePolicy | Where-Object {$_.name -contains $PolicyName} if ($ExistingPolicy.Count -eq 0) { # We're checking if the customer has a SharePoint URL. If so, we'll add SharePoint, OneDrive and Modern Group data to the Retention Policy. if (Test-Connection $SharePointURL -Count 1 -ErrorAction ignore) { New-RetentionCompliancePolicy -Name $PolicyName -ExchangeLocation All -SharePointLocation All -ModernGroupLocation All -OneDriveLocation All -PublicFolderLocation All -Enabled $true -Comment $Comment -ErrorAction Ignore } else { New-RetentionCompliancePolicy -Name $PolicyName -ExchangeLocation All -PublicFolderLocation All -Enabled $true -Comment $Comment -ErrorAction Ignore } New-RetentionComplianceRule -Name "$PolicyName Rule" -Policy $PolicyName -RetentionDuration Unlimited -ErrorAction Ignore } else { Write-Output "Policy exists for $($Customer.Name)" } Remove-PSSession $s }