Office 365 Litigation Hold with Powershell
Scenario:
Office 365 Litigation Hold with Powershell.
Litigation Hold is a feature that is needed to keep the company’s data on mailboxes as long as it is needed for legal purposes.
Litigation Hold on Office 365
Below is the explanation given by Microsoft.
Your organization may be required to retain content including email messages, attachments and documents for a specified period to meet business, legal or regulatory requirements. When a reasonable expectation of litigation exists, organizations are required to preserve electronically stored information (ESI), including email and documents that are relevant to the case, for eDiscovery. If you need to retain only mailbox content, you can use Litigation Hold in Exchange Online. To preserve mailbox content and content on SharePoint sites, OneDrive for Business locations, Office 365 groups, and Skype for Business conversations, you can use Office 365 retention policies that you create in the Office 365 Security & Compliance Center. You can also use holds that are associated with an eDiscovery case in the Security & Compliance Center to hold mailbox and site content for specific legal cases.
In this post we will look into litigation hold of mailboxes on Office365 and how you can enabled it using PowerShell. The solution provided below is configured to run on Azure Automation for Exchange Online on a schedule basis. In general the script checks everyday which mailboxes do not have litigation hold enabled and then enables litigation hold based on the company’s policy.
Azure Automation
This next part is provided by Microsoft:
Azure Automation delivers a cloud-based automation and configuration service that provides consistent management across your Azure and non-Azure environments. It consists of process automation, update management, and configuration features. Azure Automation provides complete control during deployment, operations, and decommissioning of workloads and resources.
Let’s see what the script does in more detail
First the script will save two different credentials that will be used later to perform the changes and send email. The first one is the admin account in Office 365 that will be used to connect and the perform the changes needed. and the second one is the credentials of the user that will be used to send the email report.
The the script checks if the are any active sessions and removes them. The reason I am using this, is that sometimes there is an issue on the previous run and the session stays open. If I will not remove the session all following scripts will fail also. So with this method I am sure that session is clear and the script will run fresh.
After that the script will connect to the new sessions using the administrator credentials so we will gather the information we need and then we will perform the changes needed if there are any.
After the connection, the script will collect all users in Azure Active Directory that they are using Exchange Online Plan 2 License and Office 365 Enterprise E3 license. The minimum requirement for a mailbox to be able to enable litigation hold is to assign an Exchange Online Plan 2 License. After the script will collect all user with the licenses above, it will filter them based on Litigation Hold. If there are any users with Litigation Hold disabled, it will save the users in a variable so we will proceed and enabled it.
After that the script will go through the list of users with litigation hold disabled and will enabled it with 10 years retention. This means that the data in the mailbox will be kept for 10 years, even if the user will delete them and purged the from his mailbox. Please note that litigation hold and based on the retention that you will you it will greatly affect you mailbox sizes as you will keep all the content of the mailbox based on your retention.
Reporting
As the script runs on a schedule basis, I would like to know if there are any errors without the need of checking everyday if something went wrong. So the script it will provide me an error report if there is any including all errors and / or exceptions that may appear during a run of the script. the report will be sent as an HTML email to the recipients that we have mentioned at the beginning of the script.
You can download the script here or copy it from below.
Hope you like this post. Comment below if you would like to ask anything or need more information.
Related Links:
- Hold in Office 365 – TechNet – Microsoft
- Email error variable in PowerShell
- Azure Automation Overview | Microsoft Docs
- Credential assets in Azure Automation | Microsoft Docs
- Get-PSSession – Microsoft Docs
- Remove-PSSession – Microsoft Docs
- Import-Module – Microsoft Docs
- Connect-MsolService (MSOnline) | Microsoft Docs
- New-PSSession – Microsoft Docs
- Import-PSSession – Microsoft Docs
- Get-MsolUser (MSOnline) | Microsoft Docs
- Set-Mailbox – TechNet – Microsoft
- Send-MailMessage – Microsoft Docs
- Get-Date – Microsoft Docs
Solution / Script:
$Credentials = Get-AutomationPSCredential -Name 'admin'
$EmailCredentials = Get-AutomationPSCredential -Name 'Email-User'
$To = 'User1@domain.com','User2@domain.com'
$From = 'Email-User@domain.com'
Get-PSSession | Remove-PSSession
Import-Module MSOnline
Connect-MsolService -Credential $Credentials
$Session = New-PSSession –ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Credentials -Authentication Basic -AllowRedirection
Import-PSSession -Session $Session -DisableNameChecking:$true -AllowClobber:$true | Out-Null
$UsersAll = (Get-MsolUser -All |
where {$_.Licenses.AccountSkuId -eq "companycloud:EXCHANGEENTERPRISE" -or
$_.Licenses.AccountSkuId -eq "companycloud:ENTERPRISEPACK"}).UserPrincipalName |
Get-Mailbox
$Users = ($UsersAll | where {$_.LitigationHoldEnabled -eq $false}).UserPrincipalName
Foreach ($User in $Users) {
Set-Mailbox -identity $User -LitigationHoldEnabled:$true -LitigationHoldDuration 3650
}
if ($error -ne $null) {
foreach ($value in $error) {
$EmailTemp = @"
<tr>
<td class="colorm">$value</td>
</tr>
"@
$EmailResult = $EmailResult + "`r`n" + $EmailTemp
}
$ErrorEmailUp = @"
<style>
body { font-family:Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif !important; color:#434242;}
TABLE { font-family:Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif !important; border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
TR {border-width: 1px;padding: 10px;border-style: solid;border-color: white; }
TD {font-family:Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif !important; border-width: 1px;padding: 10px;border-style: solid;border-color: white; background-color:#C3DDDB;}
.colorm {background-color:#58A09E; color:white;}
.colort{background-color:#58A09E; padding:20px; color:white; font-weight:bold;}
.colorn{background-color:transparent;}
</style>
<body>
<h3 style="color:#BD3337 !important;"> WARNING!!!</h3>
<p>There were errors during activation of Litigation Hold</p>
<p>Please check the errors and act accordingly</p>
<table>
"@
$ErrorEmailDown = @"
</table>
</body>
"@
$ErrorEmail = $ErrorEmailUp + $EmailResult + $ErrorEmailDown
send-mailmessage `
-To $To `
-Subject "Litigation Error Report $(Get-Date -format dd/MM/yyyy) - WARNING" `
-Body $ErrorEmail `
-BodyAsHtml `
-Priority high `
-UseSsl `
-Port 587 `
-SmtpServer 'smtp.office365.com' `
-From $From `
-Credential $EmailCredentials
}
The script throws the following error as soon as u run it:
Get-AutomationPSCredential : The term ‘Get-AutomationPSCredential’ is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is c
orrect and try again.
At C:\O365M\Scripts\06_LitigationHold\Enable_Litigation_Hold.ps1:1 char:16
+ $Credentials = Get-AutomationPSCredential -Name ‘admin’
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-AutomationPSCredential:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Get-AutomationPSCredential : The term ‘Get-AutomationPSCredential’ is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is c
orrect and try again.
At C:\O365M\Scripts\06_LitigationHold\Enable_Litigation_Hold.ps1:2 char:21
+ $EmailCredentials = Get-AutomationPSCredential -Name ‘Email-User’
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-AutomationPSCredential:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
The script immediately throws the following error:
Get-AutomationPSCredential : The term ‘Get-AutomationPSCredential’ is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is c
orrect and try again.
At C:\O365M\Scripts\06_LitigationHold\Enable_Litigation_Hold-ORIGINAL.ps1:1 char:16
+ $Credentials = Get-AutomationPSCredential -Name ‘admin’
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-AutomationPSCredential:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Get-AutomationPSCredential : The term ‘Get-AutomationPSCredential’ is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is c
orrect and try again.
At C:\O365M\Scripts\06_LitigationHold\Enable_Litigation_Hold-ORIGINAL.ps1:2 char:21
+ $EmailCredentials = Get-AutomationPSCredential -Name ‘Email-User’
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-AutomationPSCredential:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Hello Vitus,
The script has been setup to be used on Azure Automation.
The Get-AutomationPSCredential cmdlet is used when you have saved credentials in Azure automation for reuse. If you need to use it as a Scheduled Task or manually then you need to use Get-Credential cmdlet or retrieve the password from a file using the same way as I do it in my other scripts.
Hello Stephanos,
Thank you for your response. I think I understand what you mean. The script provided above needs to be scheduled in the Automate Account in Azure, right ?
Yes. That’s correct.
Hello Stephanos,
Thank you for your response. I think I understand what you mean. The script provided above needs to be scheduled in the Automate Account in Azure, right ?
Works well!
Just a suggestion, can you please modify the existing script so that it also send a report of mailboxes for which it found Litigation Holds missing and applied the same?
This way Admins can be made aware of the number and names of mailboxes which had Litigation Hold missing