Background

The eDiscovery service in the Office 365 Compliance and Security center dramatically improves both SharePoint and Exchange eDiscovery services. As Microsoft makes considerable strides in building eDiscovery feature sets, however, some limitations persist. Two of these limitations that we have been asked to address are eDiscovery searches and placing SharePoint sites on hold when specific users contribute to SharePoint sites. Currently, eDiscovery searches are point-in-time.

eDiscovery search results within eDiscovery cases only contain content that has been indexed by SharePoint and/or Exchange. Any new content that is indexed after an eDiscovery search has completed will not be included in the results for an eDiscovery search.

When a hold is placed on a specific user, organizations generally want to place holds correlating to any SharePoint site that user has contributed to.

While these tasks can be performed in the Compliance and Security center, it is time consuming and tedious.

Solution

The point-in-time characteristic of eDiscovery searches and placing holds on SharePoint sites linked to specific user contributions can both be addressed using PowerShell.

Placing all of the SharePoint sites on hold that specific users contribute to is accomplished by first generating a new content search. The content search covers all SharePoint sites using the UPN condition to locate the user you are seeking.

The list of SharePoint sites that are returned in the content search are used to build a new eDiscovery case and legal hold within that case. Each SharePoint site in the content search is then placed on a legal hold, thus ensuring all sites the specific user contributed to is on legal hold.

Perform the following steps before executing the contributor script:

Note: Load the PowerShell Script in ISE, matching line numbers

The Integration of the Author PowerShell script is fairly straight forward. To implement the Author script, follow the steps below.

  1. Copy all content in the script section and save it to a .PS1 file; author.ps1
  2. When prompted, enter your username and password

  3. Provide a name for the eDiscovery search

  4. Provide the UPN for the user that should be placed on hold

  5. Navigate to the Security and Compliance center
  6. Under Search & investigation > Content Search there should be a new content search

  7. The results section will display the number of items that matched your search.

  8. To see sites that are on hold, navigate to Search & investigation > eDiscovery.
  9. Select the newly created eDiscovery case
  10. Select Hold > highlight the case and select edit
  11. Under Locations > Site is the list of SharePoint sites that are on hold

Force Sync

To update eDiscovery cases, add the code below to a .PS1 file. Once the PS1 file is created, use the information in this link to create a schedule task.

$Site = Get-ComplianceCase

Foreach ($case in $site){

    write-host
$case.Name

    Start-ComplianceSearch -Identity $case.Name

}

Author

# Get user credentials 
 
if (!$credentials ) 
 
 {
 
 
 $credentials = Get-Credential 
 
 }
 
# Get the user's MySite domain name. We use this to create the admin URL and root URL for OneDrive for Business 
 
$AdminUrl = "https://Cb5lab-admin.sharepoint.com" 
 
# Get other required information 
 
#$inputfile = "C:\temp\User.csv" 
 
$searchName   =   Read-Host 
"Enter the name for the new search" 
 
$searchQuery   =   Read-Host 
"Enter the search query you want to use" 
 
# Connect to Office 365 
 
if (!$s -or !$a) 
 
 {
 
 $s = New-PSSession   -ConfigurationName   Microsoft.Exchange   -ConnectionUri   "https://ps.compliance.protection.outlook.com/powershell-liveid" -Credential 
 $credentials -Authentication Basic -AllowRedirection -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck)
 
 $a = Import-PSSession 
 $s -AllowClobber 
 
 
 if (!$s ) 
 
  {
 
  Write-Error 
 "Could not create PowerShell session." 
 
   return ;
 
     }
 
 }
 
# Load the SharePoint assemblies from the SharePoint Online Management Shell 
 
# To install, go to http://go.microsoft.com/fwlink/p/?LinkId=255251 
 
   if (!$SharePointClient  -or 
 ! $SPRuntime  -or 
 ! $SPUserProfile ) 
 
 {
 
 
 $SharePointClient = [System.Reflection.Assembly]:: LoadWithPartialName("Microsoft.SharePoint.Client") 
  
 
 $SPRuntime = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") 
  
 
 $SPUserProfile = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles") 
  
 
 if (!$SharePointClient) 
 
  {
 
 
 Write-Error 
 "SharePoint Online Management Shell isn't installed, please install from: http://go.microsoft.com/fwlink/p/?LinkId=255251 and then run this script again" 
 
 
 return ;
 
     }
 
 }
 
if (!$spCreds ) 
 
 {
 
 
 $spCreds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials ($credentials.UserName, $credentials.Password) 
 
 }
 
# Add the path of the User Profile Service to the SPO admin URL, then create a new webservice proxy to access it 
 
$proxyaddr = "$AdminUrl/_vti_bin/UserProfileService.asmx?wsdl" 
  
$UserProfileService = New-WebServiceProxy -Uri $proxyaddr -UseDefaultCredential False 
 
$UserProfileService.Credentials = $credentials 
 
# Take care of auth cookies 
 
$strAuthCookie = $spCreds.GetAuthenticationCookie($AdminUrl)
 
$uri = New-Object System.Uri ($AdminUrl)
 
$container = New-Object System.Net.CookieContainer 
 
$container.SetCookies ($uri, $strAuthCookie)
 
$UserProfileService.CookieContainer = $container 
 
Write-Host 
"Creating and starting the search" 
 
$search = New-ComplianceSearch -Name $searchName -SharePointLocation all -ContentMatchQuery 
$searchQuery 
 
Start-ComplianceSearch 
$search.Name 
 
Start-Sleep 
90 
 
  #===================================================================================== 
 
$Case = Get-ComplianceSearch 
$search.Name 
 
if ($Case.Status -ne "Completed" ) 
 
 {
 
 
"Please wait until the search finishes." ;
 
 
break ;
 
}
 
$CaseResult = $Case.SuccessResults; 
 
if (($Case.Items -le 0) -or [string]::IsNullOrWhiteSpace( $CaseResult ))) 
   
 {
 
 
"The compliance search " + $search.Name + "didn't return any useful results." ; 
 
 
 break;
 
 }
 
 $Case 
 | 
 fl 
 
  #===================================================================================== 
 
$search = Get-ComplianceSearch 
$SearchName 

if  ( $search . Status  -ne "Completed" ) 
 
 {
 
"Please wait until the search finishes" ;
 
     break ;
 
 }
 
$results = $search.SuccessResults; 
 
if  (($search.Items -le 0 ) -or [string]::IsNullOrWhiteSpace($results))) 
   
 {
 
 "The compliance search " + $SearchName + "didn't return any useful results" ;
 
 "A SharePoint search object wasn't created" ;
 
      break ;
 
 }
 
$Sites = @();
 
 $lines = $results -split '[\r\n]+' ;
 
   foreach  ($line in $lines)
 
 {
 
 
 if ($line -match 'Location:(\S+),.+Item count: (\d+)' -and $matches [2] -gt  0) 
  
  {
 
 
 $Sites += $matches [1] ; 
   
  }
 
 }
 
$msPrefix = $SearchName + "_SharePointSearch" ;
 
$I = 1;
 
$query = $search.KeywordQuery; 
 
if [string]::IsNullOrWhiteSpace($query)) 
  
 {
 
 
 $query = $search.ContentMatchQuery; 
 
 }
 
#> 
 
New-ComplianceCase -Name $searchName 
 
Start-Sleep 
90 
 
New-CaseHoldPolicy -Case $searchName -SharePointLocation 
$Sites -name 
 $msPrefix$i 
 
New-CaseHoldRule -Name 
$msPrefix$i -Policy 
$msPrefix$i