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/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $Session -AllowClobber
$SccSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.compliance.protection.outlook.com/powershell-liveid -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 comment