Migrate-InPlaceHoldsToScc.ps1

<#PSScriptInfo
 
.VERSION 1.1
 
.GUID cb0c35a3-02a5-4601-b9c5-6d8354b91455
 
.DESCRIPTION Migrate legacy in-place holds to the Security & Compliance Center.
 
.AUTHOR Aaron Guilmette
 
.COMPANYNAME Microsoft
 
.COPYRIGHT 2021
 
.TAGS SCC In-Place hold
 
.LICENSEURI
 
.PROJECTURI https://www.undocumented-features.com/2019/01/10/migrating-from-exchange-online-ediscovery-and-in-place-hold-to-the-security-compliance-center/
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
#>


<#
.SYNOPSIS
Migrate Exchange Admin Center In-Place Hold Search to Security & Compliance Center
Cases
 
.PARAMETER AddCreatedByToEDiscoveryManagers
Add the user listed in the CreatedBy parameter of the original mailbox search
to the eDiscoveryManager role group.
 
.PARAMETER Credential
A credential object. If not present, you will be promtped.
 
.PARAMETER Debug
Enable debug logging.
 
.PARAMETER Logfile
Does just what you think it does.
 
.NOTES
2021-04-07 - Migrated to PowerShell Gallery.
2019-01-10 - Added WhatIf support. The SCC cmdlets do not support the -WhatIf
    parameter,so in order to implement test support, I simply check for the
    presence of the -WhatIf parameter.
    - Added Identity parameter to support migrating an individual mailbox search.
2019-01-09 - Initial release.
#>


param (
    [switch]$AddCreatedByToEDiscoveryManagers,
    $Credential,
    [switch]$Debug,
    [string]$Identity,
    [string]$Logfile = (Get-Date -Format yyyy-MM-dd) + "_Migrate-InPlaceHoldsToScc.txt",
    [switch]$WhatIf
)

# Define functions
# Office 365 Logon
Function o365Logon([switch]$Compliance, $Credential)
{
    If (!$Credential) { $Credential = Get-Credential }
    Else
    {
        $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Credential -Authentication Basic -AllowRedirection
        Import-PSSession $Session
    }
    Connect-MsolService -Credential $Credential
    If ($Compliance)
    {
        $ComplianceSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.compliance.protection.outlook.com/powershell-liveid -Credential $Credential -Authentication Basic -AllowRedirection
        Import-PSSession $ComplianceSession -AllowClobber -DisableNameChecking
    }
}

function Write-Log([string[]]$Message, [string]$LogFile = $Script:LogFile, [switch]$ConsoleOutput, [ValidateSet("SUCCESS", "INFO", "WARN", "ERROR", "DEBUG", "WHATIF")][string]$LogLevel)
{
    $Message = $Message + $Input
    If (!$LogLevel) { $LogLevel = "INFO" }
    switch ($LogLevel)
    {
        SUCCESS { $Color = "Green" }
        INFO { $Color = "White" }
        WARN { $Color = "Yellow" }
        ERROR { $Color = "Red" }
        DEBUG { $Color = "Gray" }
        WHATIF { $Color = "Magenta"}
    }
    if ($Message -ne $null -and $Message.Length -gt 0)
    {
        $TimeStamp = [System.DateTime]::Now.ToString("yyyy-MM-dd HH:mm:ss")
        if ($LogFile -ne $null -and $LogFile -ne [System.String]::Empty)
        {
            Out-File -Append -FilePath $LogFile -InputObject "[$TimeStamp] [$LogLevel] :: $Message"
        }
        if ($ConsoleOutput -eq $true)
        {
            Write-Host "[$TimeStamp] [$LogLevel] :: $Message" -ForegroundColor $Color
        }
    }
}

# Test for Office 365 available commands
$Command1 = (Get-Command Get-MailboxSearch -ea silentlycontinue)
$Command2 = (Get-Command Get-ComplianceCase -ea silentlycontinue)

If (!$Command1 -and !$Command2)
{
    o365Logon -Credential $Credential -Compliance
}

# Get old cases, which are MailboxSearches in Exchange Online
If ($Identity)
{
    [array]$MailboxSearches = Get-MailboxSearch $Identity
}
Else
{
    $MailboxSearches = Get-MailboxSearch -Resultsize Unlimited
}
# Get all existing Compliance Cases, since we need to have uniqueness in case names
[array]$ExistingCases = (Get-ComplianceCase).Name


# Create new cases
Foreach ($Search in $MailboxSearches)
{
    $Error.Clear()
    # Null potentially used vars
    $SearchDetails = $null
    $Case = $null
    $CaseHoldPolicy = $null
    $CaseHoldPolicyParams = $null
    $CaseHoldRuleParams = $null
    $CaseHoldRule = $null
    $ComplianceSearchParams = $null
    $ComplianceSearch = $null
    $ContentMatchQuery = $null
    $ContentMatchQueryTemp = $null
    
    # Retrieve Search Details
    $SearchDetails = (Get-MailboxSearch -Identity $Search.Identity)
    If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " Processing $($Search.Name)" }
    Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Processing $($Search.Name)"}
    
    # Create the Description value
    $Description = New-Object System.Text.StringBuilder
    $Description.AppendLine("$($SearchDetails.Description)") | Out-Null
    $Description.AppendLine("=========================================================") | Out-Null
    $Description.AppendLine("Reference object identifiers from original Mailbox Search") | Out-Null
    $Description.AppendLine("=========================================================") | Out-Null
    If ($SearchDetails.InPlaceHoldIdentity)
    {
        $Description.AppendLine("Original InPlaceHold Identity: $($SearchDetails.InPlaceHoldIdentity)") | Out-Null
    }
    $Description.AppendLine("Original Search Identity: $($SearchDetails.Identity)") | Out-Null
    $Description = $Description.ToString()
    
    # Create the Case Hold Container
    If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " Creating new compliance case." }
    Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Creating new compliance case."}
    
    # Check for case uniqueness
    $CaseName = $SearchDetails.Name
    If ($ExistingCases -match $CaseName)
    {
        If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel WARN -ConsoleOutput -Message " Case name $($CaseName) already in use. Generating new name." }
        Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Case name $($CaseName) already in use. Generating new name." }
        Do
        {
            $RandomValue = ([guid]::NewGuid()).Guid.ToString().SubString(0, 16)
            $CaseName = $($SearchDetails.Name) + "_$($RandomValue)"
            If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " New case name is $($CaseName)." }
            Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "New case name is $($CaseName)."    }
    }
    Until ($Cases -notmatch $CaseName)
}
try
    {
        If (!$WhatIf) { $Case = New-ComplianceCase -CaseType eDiscovery -Name $CaseName -Description $Description -ea stop }
        Else
        {
            Write-Log -LogLevel WHATIF -ConsoleOutput -Message "The cmdlet that would be run is:"
            Write-Log -LogLevel WHATIF -ConsoleOutput -Message "`$Case = New-ComplianceCase -CaseType eDiscovery -Name $($CaseName) -Description $($Description)"    
        }
    }
    catch
    {
        Write-Log -LogFile $Logfile -LogLevel ERROR -ConsoleOutput -Message $Error[0].Exception
    }
    
    If ($Case)
    {
        Write-Log -LogFile $Logfile -LogLevel SUCCESS -ConsoleOutput -Message " Successfully created case $($Case.Name)."
        $ExistingCases += $CaseName
    }
    
    # Add the 'CreatedBy' member to the Case Membership
    If (!$WhatIf) { [array]$ComplianceCaseMembers = (Get-ComplianceCaseMember -Case $Case.Identity).PrimarySmtpAddress }
    If ($SearchDetails.CreatedBy -match $ComplianceCaseMembers)
    {
        If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " User $($SearchDetails.CreatedBy) is already a member of the case." }
        Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "User $($SearchDetails.CreatedBy) is already a member of the case." } 
    }
    Else
    {
        If (!$WhatIf)
        {
            Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " Adding $($SearchDetails.CreatedBy) as case member."
            Add-ComplianceCaseMember -Case $Case.Identity -Member $SearchDetails.CreatedBy
        }
        Else
        {
            Write-Log -LogLevel WHATIF -ConsoleOutput -Message "The cmdlet that would be run is:"
            Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Add-ComplianceCaseMember -Case $($Case.Identity) -Member $($SearchDetails.CreatedBy)"
        }
    }
    
    # If the AddCreatedByToEDiscoveryManagers switch is set, add the user listed
    # in the CreatedBy property of the mailbox search to the eDiscoveryManager
    # RoleGroup
    If ($AddCreatedByToEDiscoveryManagers)
    {
        $eDiscoveryManagers = (Get-RolegroupMember -ResultSize Unlimited -Identity 'eDiscoveryManager').PrimarySmtpAddress
        $eDiscoveryCaseAdmins = (Get-EDiscoveryCaseAdmin -ResultSize Unlimited).PrimarySmtpAddress
        If (($eDiscoveryManagers -match $SearchDetails.CreatedBy) -or ($eDiscoveryCaseAdmins -match $SearchDetails.CreatedBy))
        {
            If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " $($SearchDetails.CreatedBy) is already a member of eDiscovery managers." }
            Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "$($SearchDetails.CreatedBy) is already a member of eDiscovery managers."}
        }
        Else
        {
            If (!$WhatIf)
            {
                Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " Adding $($SearchDetails.CreatedBy) to eDiscovery managers."
                Add-RoleGroupMember -Identity eDiscoveryManager -Member $($SearchDetails.CreatedBy) -ea SilentlyContinue
            }
            Else
            {
                Write-Log -LogLevel WHATIF -ConsoleOutput -Message "The cmdlet that would be run is:"
                Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Add-RoleGroupMember -Identity eDiscoveryManager -Member $($SearchDetails.CreatedBy)"
            }
        }
    }
    
    ## If InPlaceHold is applied, then create a case hold; otherwise, just create a search
    Switch ($SearchDetails.InPlaceHoldEnabled)
    {
        $true
        {
            If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " Mailbox search has hold applied. Creating case hold policy." }
            Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Mailbox search has hold applied." }
            
            # Create the Case Hold Policy
            ## Case Hold Policy Parameters
            $script:CaseHoldPolicyParams = @{ }
            
            # Case hold name can only be 50 characters long
            If (!$WhatIf)
            {
                If ($Case.Name.Length -gt 50)
                {
                    $CaseName = $Case.Name.Substring(0, 49)
                }
                Else
                {
                    $CaseName = $Case.Name
                }
            }
            else
            {
                $Case = New-Object PSObject
                
            }
            
            
            $CaseHoldPolicyParams.Add("Name", "$($CaseName)")
            If (!$WhatIf) { $CaseHoldPolicyParams.Add("Case", $($Case.Identity)) }
            $CaseHoldPolicyParams.Add("Enabled", $true)
            
            If ($SearchDetails.SourceMailboxes)
            {
                $CaseHoldPolicyParams.Add("ExchangeLocation", $SearchDetails.SourceMailboxes)
            }
            
            # If Get-MailboxSearch has a source mailbox but also specifies AllMailboxes, then assume all mailboxes for ExchangeLocation
            If ($SearchDetails.AllSourceMailboxes -eq $true)
            {
                $CaseHoldPolicyParams.Remove("ExchangeLocation")
                $CaseHoldPolicyParams.Add("ExchangeLocation", "All")
            }
            
            If ($SearchDetails.PublicFolderSources)
            {
                $CaseHoldPolicyParams.Add("PublicFolderLocation", $SearchDetails.PublicFolderSources)
            }
            
            # If Get-MailboxSearch has a source public folder location but also specifies AllPublicFolders, then assume all mailboxes for PublicFolderLocation
            If ($SearchDetails.AllPublicFolderSources -eq $true)
            {
                $CaseHoldPolicyParams.Remove("PublicFolderLocation")
                $CaseHoldPolicyParams.Add("PublicFolderLocation", "All")
            }
            
            Try
            {
                If (!$WhatIf) { $CaseHoldPolicy = New-CaseHoldPolicy @CaseHoldPolicyParams -ea stop }
                Else
                {
                    Write-Log -LogLevel WHATIF -ConsoleOutput -Message "The cmdlet that would be run is:"
                    Write-Log -LogLevel WHATIF -ConsoleOutput -Message "`$CaseHoldPolicy = New-CaseHoldPolicy @CaseHoldPolicyParams"
                    Write-Log -LogLevel WHATIF -ConsoleOutput -Message "The @CaseHoldPolicyParams splatting variable contains the following values:"
                    $CaseHoldPolicyParams.GetEnumerator() | % { Write-Log -LogLevel WHATIF -ConsoleOutput -Message " $($_.Name) : $($_.Value)"}                    
                }
            }
            Catch
            {
                Write-Log -LogFile $Logfile -LogLevel ERROR -ConsoleOutput -Message $Error[0].Exception
            }
            If ($CaseHoldPolicy)
            {
                Write-Log -LogFile $Logfile -LogLevel SUCCESS -ConsoleOutput -Message " Case hold policy successfully created."
                If ($Debug)
                {
                    Write-Log -LogFile $Logfile -LogLevel DEBUG -ConsoleOutput -Message " CaseHoldPolicy Name: $($CaseHoldPolicy.Name)"
                    Write-Log -LogFile $Logfile -LogLevel DEBUG -ConsoleOutput -Message " CaseHoldPolicy Guid: $($CaseHoldPolicy.Guid)"
                    Write-Log -LogFile $Logfile -LogLevel DEBUG -ConsoleOutput -Message " CaseHoldPolicy Identity: $($CaseHoldPolicy.Identity)"
                    $CaseHoldPolicyParams.GetEnumerator() | % { Write-Log -LogFile $Logfile -LogLevel DEBUG -Message " $($_.Name) : $($_.Value)"}
                }
            }
            
            # Case Hold Rule Parameters
            If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " Creating case hold policy rule." }
            Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Creating case hold policy rule." }
            $CaseHoldRuleParams = @{ }
            
            $CaseHoldRuleParams.Add("Name", "Migrated Search Query")
            # Content Match Query
            If ($SearchDetails.SearchQuery -or $SearchDetails.StartDate -or $SearchDetails.EndDate -or $SearchDetails.Senders -or $SearchDetails.Recipients)
            {
                If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " Processing content match query details." }
                Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Processing content match query details." }
                $ContentMatchQuery = $null
                # Content Match Builder
                # Check if the SearchQuery exists; if it does, use it as the base of the
                # ContentMatchQuery
                If ($SearchDetails.SearchQuery)
                {
                    [string]$ContentMatchQuery = "(" + $SearchDetails.SearchQuery + ")"
                    If (!$WhatIf)
                    {
                        If ($Debug)
                        {
                            Write-Log -LogFile $Logfile -LogLevel DEBUG -Message $ContentMatchQuery -ConsoleOutput
                        }
                    }
                    Else
                    {
                        Write-Log -LogLevel WHATIF -Message "Current content match query after processing SearchQuery parameter:" -ConsoleOutput
                        Write-Log -LogLevel WHATIF -Message "$($ContentMatchQuery)" -ConsoleOutput
                    }
                }
                
                # Check if MessageTypes exists
                If ($SearchDetails.MessageTypes)
                {
                    [array]$MessageTypes = $SearchDetails.MessageTypes
                    # Check to see if we already have content for the ContentMatchQuery.
                    # If so, create a temp var, prepend the ContentMatchQuery value with
                    # an open parenthesis, join the MessageTypes values together with
                    # "kind:<MessageTpye> OR" and then add a close parenthesis to the
                    # variable. Set the ContentMatchQuery variable with the temp variable.
                    If ($ContentMatchQuery)
                    {
                        [string]$ContentMatchQueryTemp = " AND (kind:"
                        $ContentMatchQueryTemp += [string]::Join(" OR kind:", [array]$SearchDetails.MessageTypes)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                    # If ContentMatchQuery doesn't exist, just start an open parenthesis
                    # and add join the MessageTypes values together, and then add a
                    # closing parenthesis
                    Else
                    {
                        [string]$ContentMatchQuery = "(kind:"
                        $ContentMatchQueryTemp += [string]::Join(" OR kind:", [array]$SearchDetails.MessageTypes)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery += ")"
                    }
                    If (!$WhatIf)
                    {
                        If ($Debug)
                        {
                            Write-Log -LogFile $Logfile -LogLevel DEBUG -Message $ContentMatchQuery -ConsoleOutput
                        }
                    }
                    Else
                    {
                        Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Current content match query after processing MessageTypes parameter:"
                        Write-Log -LogLevel WHATIF -ConsoleOutput -Message "$($ContentMatchQuery)"
                    }
                }
                
                # Check to see if date values exist
                If ($SearchDetails.StartDate -or $SearchDetails.EndDate)
                {
                    # Populate the StartDate and EndDate values
                    $StartDate = $SearchDetails.StartDate
                    $EndDate = $SearchDetails.EndDate
                    
                    # Build the appropriate search operator and property syntax, depending
                    # on which date values are available.
                    If ($StartDate -and $EndDate) { $SearchDate = "between:$($StartDate)..$($EndDate)" }
                    If ($StartDate -and !($EndDate)) { $SearchDate = "sent OR received>$($StartDate)" }
                    If (!($StartDate) -and $EndDate) { $SearchDate = "sent OR received<$($EndDate)" }
                    
                    # Check to see if ContentMatchQuery already exists. If so, add an
                    # AND operator, an open parenthesis, the $SearchDate variable, and a
                    # closing parenthesis.
                    If ($ContentMatchQuery)
                    {
                        [string]$ContentMatchQueryTemp = " AND ( $($SearchDate))"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                    Else
                    {
                        [string]$ContentMatchQuery = "($($SearchDate))"
                    }
                    If (!$WhatIf)
                    {
                        If ($Debug)
                        {
                            Write-Log -LogFile $Logfile -LogLevel DEBUG -Message $ContentMatchQuery -ConsoleOutput
                        }
                    }
                    Else
                    {
                        Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Current content match query after processing StartDate and EndDate parameters:"
                        Write-Log -LogLevel WHATIF -ConsoleOutput -Message "$($ContentMatchQuery)"
                    }
                }
                
                If ($SearchDetails.Senders)
                {
                    If ($ContentMatchQuery)
                    {
                        [string]$ContentMatchQueryTemp = " AND (from:"
                        $ContentMatchQueryTemp += [string]::Join(" OR from:", [array]$SearchDetails.Senders)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                    Else
                    {
                        [string]$ContentMatchQueryTemp = "(from:"
                        $ContentMatchQueryTemp += [string]::Join(" OR from:", [array]$SearchDetails.Senders)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery = $ContentMatchQueryTemp
                    }
                    If (!$WhatIf)
                    {
                        If ($Debug)
                        {
                            Write-Log -LogFile $Logfile -LogLevel DEBUG -Message $ContentMatchQuery -ConsoleOutput
                        }
                    }
                    Else
                    {
                        Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Current content match query after processing Senders parameter:"
                        Write-Log -LogLevel WHATIF -ConsoleOutput -Message "$($ContentMatchQuery)"
                    }
                }
                
                If ($SearchDetails.Recipients)
                {
                    If ($ContentMatchQuery)
                    {
                        $ContentMatchQueryTemp = " AND (to:"
                        $ContentMatchQueryTemp += [string]::Join(" OR to:", [array]$SearchDetails.Recipients)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                    Else
                    {
                        $ContentMatchQueryTemp = "(from:"
                        $ContentMatchQueryTemp += [string]::Join(" OR to:", [array]$SearchDetails.Recipients)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery = $ContentMatchQueryTemp
                    }
                    If (!$WhatIf)
                    {
                        If ($Debug)
                        {
                            Write-Log -LogFile $Logfile -LogLevel DEBUG -Message $ContentMatchQuery -ConsoleOutput
                        }
                    }
                    Else
                    {
                        Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Current content match query after processing Recipients parameter:"
                        Write-Log -LogLevel WHATIF -ConsoleOutput -Message "$($ContentMatchQuery)"
                    }
                }
            }
            If ($ContentMatchQuery)
            {
                $CaseHoldRuleParams.Add("ContentMatchQuery", $ContentMatchQuery)
                If (!$WhatIf)
                {
                    If ($Debug)
                    {
                        Write-Log -LogFile $Logfile -LogLevel DEBUG -Message "ContentMatchQuery DEBUG data"
                        Write-Log -LogFile $Logfile -LogLevel DEBUG -Message "$($ContentMatchQuery)"
                        Write-Log -LogFile $Logfile -LogLevel DEBUG -Message "ContentMatchQuery Length is $($ContentMatchQuery.Length)"
                    }
                }
                Else
                {
                    Write-Log -LogLevel WHATIF -ConsoleOutput -Message "ContentMatchQuery WHATIF data"
                    Write-Log -LogLevel WHATIF -ConsoleOutput -Message "$($ContentMatchQuery)"
                    Write-Log -LogLevel WHATIF -ConsoleOutput -Message "ContentMatchQuery Length is $($ContentMatchQuery.Length)"
                }
            }
            
            $CaseHoldRuleParams.Add("Policy", $CaseHoldPolicy.Guid)
            try
            {
                If (!$WhatIf) { $CaseHoldRule = New-CaseHoldRule @CaseHoldRuleParams -ea stop }
                Else
                {
                    Write-Log -LogLevel WHATIF -ConsoleOutput -Message "The cmdlet that would run is:"
                    Write-Log -LogLevel WHATIF -ConsoleOutput -Message "`$CaseHoldRule = New-CaseHoldRule @CaseHoldRuleParams"
                    Write-Log -LogLevel WHATIF -ConsoleOutput -Message "The @CaseHoldRuleParams splatting variable contains the following values:"
                    $CaseHoldRuleParams.GetEnumerator() | % { Write-Log -LogLevel WHATIF -ConsoleOutput -Message " $($_.Name) : $($_.Value)" }
                }
            }
            catch
            {
                Write-Log -LogFile $Logfile -LogLevel ERROR -ConsoleOutput -Message $Error[0].Exception
            }
            If ($CaseHoldRule)
            {
                Write-Log -LogFile $Logfile -LogLevel SUCCESS -ConsoleOutput -Message " Case hold rule successfully created. "
            }
            
        }
        $false
        {
            If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " Mailbox search has does not have hold applied. Creating case content search." }
            Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Mailbox search has does not have hold applied. Creating case content search." }
            
            # Create the Compliance Search
            $ComplianceSearchParams = @{ }
            $ComplianceSearchParams.Add("Name", "$($Case.Name) Search")
            $ComplianceSearchParams.Add("Case", "$($Case.Identity)")
            
            # Add the SourceMailboxes
            If ($SearchDetails.SourceMailboxes)
            {
                $ComplianceSearchParams.Add("ExchangeLocation", "$($SearchDetails.SourceMailboxes)")
            }
            
            # If Get-MailboxSearch has a source mailbox but also specifies AllMailboxes, then assume all mailboxes for ExchangeLocation
            If ($SearchDetails.AllSourceMailboxes -eq $true)
            {
                $ComplianceSearchParams.Remove("ExchangeLocation")
                $ComplianceSearchParams.Add("ExchangeLocation", "All")
            }
            
            # Add the Public Folders
            $ComplianceSearchParams.Add("PublicFolderLocation", "$($SearchDetails.PublicFolderSources)")
            
            # If Get-MailboxSearch has a source public folder location but also specifies AllPublicFolders, then assume all mailboxes for PublicFolderLocation
            If ($SearchDetails.AllPublicFolderSources -eq $true)
            {
                $ComplianceSearchParams.Remove("PublicFolderLocation")
                $ComplianceSearchParams.Add("PublicFolderLocation", "All")
            }
            
            If ($SearchDetails.SearchQuery -or $SearchDetails.StartDate -or $SearchDetails.EndDate -or $SearchDetails.Senders -or $SearchDetails.Recipients)
            {
                If (!$WhatIf) { Write-Log -LogFile $Logfile -LogLevel INFO -ConsoleOutput -Message " Processing content match query details." }
                Else { Write-Log -LogLevel WHATIF -ConsoleOutput -Message "Processing content match query details."}
                $ContentMatchQuery = $null
                # Content Match Builder
                # Check if the SearchQuery exists; if it does, use it as the base of the
                # ContentMatchQuery
                If ($SearchDetails.SearchQuery)
                {
                    [string]$ContentMatchQuery = "( " + $SearchDetails.SearchQuery + " )"
                }
                If (!$WhatIf)
                {
                    If ($Debug)
                    {
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " Current content match query after processing SearchQuery parameter:"
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " $($ContentMatchQuery)"
                    }
                }
                Else
                {
                    Write-Log -LogLevel WHATIF -Message "Current content match query after processing SearchQuery parameter:" -ConsoleOutput
                    Write-Log -LogLevel WHATIF -Message "$($ContentMatchQuery)" -ConsoleOutput
                }
                
                # Check if MessageTypes exists
                If ($SearchDetails.MessageTypes)
                {
                    # Check to see if we already have content for the ContentMatchQuery.
                    # If so, create a temp var, prepend the ContentMatchQuery value with
                    # an open parenthesis, join the MessageTypes values together with
                    # "kind:<MessageTpye> OR" and then add a close parenthesis to the
                    # variable. Set the ContentMatchQuery variable with the temp variable.
                    If ($ContentMatchQuery)
                    {
                        # $ContentMatchQueryTemp = "( " + $ContentMatchQuery + ") AND (kind:"
                        $ContentMatchQueryTemp = " AND (kind:"
                        $ContentMatchQueryTemp += [string]::Join(" OR kind:", [array]$SearchDetails.MessageTypes)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                    # If ContentMatchQuery doesn't exist, just start an open parenthesis
                    # and add join the MessageTypes values together, and then add a
                    # closing parenthesis
                    Else
                    {
                        $ContentMatchQuery = "(kind:"
                        $ContentMatchQuery += [string]::Join(" OR kind:", [array]$SearchDetails.MessageTypes)
                        $ContentMatchQuery += ")"
                    }
                }
                If (!$WhatIf)
                {
                    If ($Debug)
                    {
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " Current content match query after processing MessageTypes parameter:"
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " $($ContentMatchQuery)"
                    }
                }
                Else
                {
                    Write-Log -LogLevel WHATIF -Message "Current content match query after processing MessageTypes parameter:" -ConsoleOutput
                    Write-Log -LogLevel WHATIF -Message "$($ContentMatchQuery)" -ConsoleOutput
                }
                
                # Check to see if date values exist
                If ($SearchDetails.StartDate -or $SearchDetails.EndDate)
                {
                    # Popuylate the StartDate and EndDate values
                    $StartDate = $SearchDetails.StartDate
                    $EndDate = $SearchDetails.EndDate
                    
                    # Build the appropriate search operator and property syntax, depending
                    # on which date values are available.
                    If ($StartDate -and $EndDate) { $SearchDate = "between:$($StartDate)..$($EndDate)" }
                    If ($StartDate -and !($EndDate)) { $SearchDate = "sent OR received>$($StartDate)" }
                    If (!($StartDate) -and $EndDate) { $SearchDate = "sent OR received<$($EndDate)" }
                    
                    # Check to see if ContentMatchQuery already exists. If so, add an
                    # AND operator, an open parenthesis, the $SearchDate variable, and a
                    # closing parenthesis.
                    If ($ContentMatchQuery)
                    {
                        $ContentMatchQueryTemp = " AND ( $($SearchDate))"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                    Else
                    {
                        [string]$ContentMatchQuery = "($($SearchDate))"
                    }
                }
                If (!$WhatIf)
                {
                    If ($Debug)
                    {
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " Current content match query after processing StartDate and EndDate parameters:"
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " $($ContentMatchQuery)"
                    }
                }
                Else
                {
                    Write-Log -LogLevel WHATIF -Message "Current content match query after processing StartDate and EndDate parameters:" -ConsoleOutput
                    Write-Log -LogLevel WHATIF -Message "$($ContentMatchQuery)" -ConsoleOutput
                }
                
                If ($SearchDetails.Senders)
                {
                    If ($ContentMatchQuery)
                    {
                        [string]$ContentMatchQueryTemp = " AND (from:"
                        $ContentMatchQueryTemp += [string]::Join(" OR from:", [array]$SearchDetails.Senders)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                    Else
                    {
                        [string]$ContentMatchQueryTemp = "(from:"
                        $ContentMatchQueryTemp += [string]::Join(" OR from:", [array]$SearchDetails.Senders)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                }
                If (!$WhatIf)
                {
                    If ($Debug)
                    {
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " Current content match query after processing Sender parameter:"
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " $($ContentMatchQuery)"
                    }
                }
                Else
                {
                    Write-Log -LogLevel WHATIF -Message "Current content match query after processing Sender parameter:" -ConsoleOutput
                    Write-Log -LogLevel WHATIF -Message "$($ContentMatchQuery)" -ConsoleOutput
                }
                
                If ($SearchDetails.Recipients)
                {
                    If ($ContentMatchQuery)
                    {
                        [string]$ContentMatchQueryTemp = " AND (to:"
                        $ContentMatchQueryTemp += [string]::Join(" OR to:", [array]$SearchDetails.Recipients)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                    Else
                    {
                        [string]$ContentMatchQueryTemp = "(to:"
                        $ContentMatchQueryTemp += [string]::Join(" OR to:", [array]$SearchDetails.Recipients)
                        $ContentMatchQueryTemp += ")"
                        $ContentMatchQuery += $ContentMatchQueryTemp
                    }
                }
                If (!$WhatIf)
                {
                    If ($Debug)
                    {
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " Current content match query after processing Recipients parameter:"
                        Write-Log -Logfile $Logfile -LogLevel DEBUG -Message " $($ContentMatchQuery)"
                    }
                }
                Else
                {
                    Write-Log -LogLevel WHATIF -Message "Current content match query after processing Recipients parameter:" -ConsoleOutput
                    Write-Log -LogLevel WHATIF -Message "$($ContentMatchQuery)" -ConsoleOutput
                }
            }
            If ($ContentMatchQuery)
            {
                $ComplianceSearchParams.Add("ContentMatchQuery", $ContentMatchQuery)
            }
            
            If (!$WhatIf) { $ComplianceSearch = New-ComplianceSearch @ComplianceSearchParams }
            Else
            {
                Write-Log -LogLevel WHATIF -ConsoleOutput -Message "The cmdlet that would be run is:"
                Write-Log -LogLevel WHATIF -ConsoleOutput -Message "`$ComplianceSearch = New-ComplianceSearch @ComplianceSearchParams"
                Write-Log -LogLevel WHATIF -ConsoleOutput -Message "The @ComplianceSearchParams splatting variable contains the following values:"
                $ComplianceSearchParams.GetEnumerator() | % { Write-Log -LogLevel WHATIF -ConsoleOutput -Message " $($_.Name) : $($_.Value)" }
            }
            If ($ComplianceSearch)
            {
                If (!$WhatIf)
                {
                    Write-Log -LogFile $Logfile -LogLevel SUCCESS -ConsoleOutput -Message " Compliance Search for case $($Case.Name) successfully created. "
                    Start-ComplianceSearch $ComplianceSearch.Identity
                }
            }
        }
    }
}