PowerShell Script to Create Office 365 Security and Compliance Center eDiscovery Case and Holds

This week my customer and a peer both asked for a sample PowerShell script to automate the creation of an Office 365 Security and Compliance Center eDisovery case, hold, and content search.  This post will share out that script and a few things to be aware of (ex. deprecating basic authentication) that are important.

Background

The below script accomplishes the following tasks:

  • Create a Security and Compliance Center eDiscovery case
  • Place an in-place hold on multiple users’ Exchange Online mailboxes
  • Create a content search within eDiscovery case for any folders named “Legal Hold” and the child folders under them

Important Note

As of the publish date (Mar 4th, 2020) the Security and Compliance Center remote PowerShell module relies on basic authentication.  The Exchange team has publicly shared that basic authentication for Exchange Online will be deprecated by Oct 2020.  As such that means the below script may not be usable in its current form in ~6 months.  When a replacement or update is available I will attempt to update this sample to reflect that.

Exchange Online deprecating Basic Authentication
https://support.microsoft.com/en-us/help/4521831/exchange-online-deprecating-basic-auth

In terms of the Exchange Online remote PowerShell module there is a v2 module being developed (active development, not ready for production) which you can find on the PowerShell Gallery.  This new module support OAuth authentication which resolves the issue of deprecated basic authentication.

ExchangeOnlineManagement module on PSGallery
https://www.powershellgallery.com/packages/ExchangeOnlineManagement

Solution

Before running this script, ensure that the account you log in with has the appropriate permissions to both Exchange Online as well as Security and Compliance Center.  My sample uses a single admin account but you may adapt the script to use separate accounts if needed.  See the following articles for more details.

Connect to Exchange Online PowerShell
https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps

Connect to Office 365 Security & Compliance Center PowerShell
https://docs.microsoft.com/en-us/powershell/exchange/office-365-scc/connect-to-scc-powershell/connect-to-scc-powershell?view=exchange-ps

Note: If you do not see the below Gist please refer to code at this location: EXO_New-SCCeDiscoveryCaseAndHold.ps1


Set-StrictMode Version "Latest"
# eDiscovery case creation
$caseName = 'Smith v. Johnson';
$UPN = 'user1@contoso.onmicrosoft.com', 'user2@contoso.onmicrosoft.com'
$description = "$caseName"
$policyName = "$caseName – Hold Policy"
$ruleName = "$caseName – Hold Rule"
$searchName = "$caseName – Search Name"
$rootFolderNameQuery = "Legal Hold"
function GetFolderQueries {
param (
[string]
$rootFolderNameQuery,
[string[]]
$UPN
)
$folderQueries = @()
foreach($user in $UPN)
{
$rootFolderStats = Get-MailboxFolderStatistics Identity $user | Where-Object name -eq $rootFolderNameQuery
$childFolderStats = Get-MailboxFolderStatistics Identity $user | Where-Object FolderPath -like "$($rootFolderStats.FolderPath)*"
# sample script to convert folderId: https://docs.microsoft.com/en-us/microsoft-365/compliance/use-content-search-for-targeted-collections?view=o365-worldwide#step-1-run-the-script-to-get-a-list-of-folders-for-a-mailbox-or-site
foreach ($folderStatistic in $childFolderStats)
{
$folderId = $folderStatistic.FolderId;
$folderPath = $folderStatistic.FolderPath;
$encoding= [System.Text.Encoding]::GetEncoding("us-ascii")
$nibbler= $encoding.GetBytes("0123456789ABCDEF");
$folderIdBytes = [Convert]::FromBase64String($folderId);
$indexIdBytes = New-Object byte[] 48;
$indexIdIdx=0;
$folderIdBytes | Select-Object skip 23 First 24 | %{$indexIdBytes[$indexIdIdx++]=$nibbler[$_ -shr 4];$indexIdBytes[$indexIdIdx++]=$nibbler[$_ -band 0xF]}
$folderQuery = "folderid:$($encoding.GetString($indexIdBytes))";
$folderStat = New-Object PSObject
Add-Member InputObject $folderStat MemberType NoteProperty Name UPN Value $user
Add-Member InputObject $folderStat MemberType NoteProperty Name FolderPath Value $folderPath
Add-Member InputObject $folderStat MemberType NoteProperty Name FolderQuery Value $folderQuery
$folderQueries += $folderStat
}
}
return $folderQueries
}
# Connection to EXO and SCC PowerShell Modules
$UserCredential = Get-Credential
$Session = New-PSSession ConfigurationName Microsoft.Exchange ConnectionUri https://outlook.office365.com/powershellliveid/ Credential $UserCredential Authentication Basic AllowRedirection
Import-PSSession $Session AllowClobber
$SccSession = New-PSSession ConfigurationName Microsoft.Exchange ConnectionUri https://ps.compliance.protection.outlook.com/powershellliveid Credential $UserCredential Authentication Basic AllowRedirection
Import-PSSession $SccSession AllowClobber DisableNameChecking
# Create eDiscovery case, hold, and compliance search
New-ComplianceCase Name $caseName Description $description
New-CaseHoldPolicy Name $policyName Case $caseName ExchangeLocation $UPN Enabled $true
New-CaseHoldRule Name $ruleName Policy $policyName Disabled $false
$folderQueries = GetFolderQueries rootFolderNameQuery $rootFolderNameQuery UPN $UPN
New-ComplianceSearch Name $searchName Case $caseName HoldNames "All" ContentMatchQuery $folderQueries.FolderQuery

Conclusion

In this post I shared a sample script for automating the creation of an Office 365 Security and Compliance Center eDiscovery case, hold, and folder scoped content search.  The folder scoping was an interesting detour as I had to track down the way to gather folder IDs from a product group engineer sample (linked in the above sample).  I hope you find this useful and good luck scripting.

-Frog Out

2 thoughts on “PowerShell Script to Create Office 365 Security and Compliance Center eDiscovery Case and Holds

  1. This is a great article. It helped me to understand the concept of creating advanced ediscovery case. However, when I run this script I hot the following message. what is the correct syntax should be used in the LINE #25?

    The property ‘FolderPath’ cannot be found on this object. Verify that the property exists.

    Thanks in advance, Peter

    Like

    • Peter, if you look further up the script on line 10 you can find the folder name ($rootFolderNameQuery = “Legal Hold”) it is first querying for. In my testing I used “Legal Hold” folder under the root of the inbox.

      Like

Leave a Reply

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

WordPress.com Logo

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

Facebook photo

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

Connecting to %s