Exchange 2016 Compliance Search Deprecated
Deprecated. Use EWS V2 instead.
Messaging and Conferencing · Exchange 2016 Compliance Search
Details
| ID | Exchange 2016 Compliance Search |
|---|---|
| Provider | Microsoft |
| Category | Messaging and Conferencing |
| From Version | 5.0.0 |
| Docker Image | demisto/python:2.7.18.27799 |
| Supported Modules | Agentix |
README
Deprecated, use EWS V2 instead.
Use this integration to run and manage compliance searches on your Exchange 2016 Server.
This integration was integrated and tested with Exchange 2016 Server.
Use Cases
Exchange Server 2016 Compliance Search enables you to search for and delete an email message from all mailboxes in your organization. There are no limits to the number of target mailboxes in a single search.
Prerequisite
Install Cortex XSOAR Engine
- Cortex XSOAR Engine must be installed on a target window machine which is part of the domain of your Exchange 2016 server.
- Make sure you have Python 2.7 installed on the Engine machine.
- Add the necessary Python lbs to the Engine machine.
https://github.com/demisto/content/blob/master/Packs/Exchange2016_Compliance/Integrations/Exchange2016_Compliance/doc_files/requirements.txt
Run the pip install --no-cache-dir -r requirements.txt command. - Make sure the integration runs without docker image.
- For more information regarding Installing and Deploying Cortex XSOAR Engines, see the Engines Documentation (Cortex XSOAR 6.13) or Engines Documentation (Cortex XSOAR 8 Cloud) or Engines Documentation (Cortex XSOAR 8.7 On-prem).
Permissions
The user that you configure for the integration instance requires the Compliance Management role to run the integration commands. For more information, see the Microsoft Documentation.
Configure Exchange 2016 Compliance Search on Cortex XSOAR
- Navigate to Settings>Integrations>Servers & Services.
- Search for Exchange 2016 Compliance Search.
- Click Add instance to create and configure a new integration instance.
- Name: a textual name for the integration instance.
- DOMAIN\USERNAME (e.g., XSOAR.INT\admin)
- Exchange Server fully qualified domain name (FQDN)
- Use single engine: engine to run the integration on
- Note: the integration requires engine and there is no option to use it without engine.
- Trust any certificate (not secure)
- Click Test to validate the URLs, token, and connection.
Commands
You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
- Start a compliance search: exchange2016-start-compliance-search
- Get the results and status of a compliance search: exchange2016-get-compliance-search
- Remove a compliance search: exchange2016-remove-compliance-search
- Purge the results of a compliance search: exchange2016-purge-compliance-search-results
- Get the status of a purge operation: exchange2016-get-compliance-search-purge-status
1. Start a compliance search
Initiates a compliance search.
Base Command
exchange2016-start-compliance-search
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Query for finding mail messages | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| EWS.ComplianceSearch.Name | string | The name of the compliance search |
| EWS.ComplianceSearch.Status | string | The status of the compliance search |
Command Example
exchange2016-start-compliance-search query="subject:\"Email to be searched and deleted\""
Context Example
{
"EWS": {
"ComplianceSearch": {
"Status": "Starting",
"Name": "DemistoSearch939b54bcd2bb4848bb0885dc4071d366"
}
}
}
Human Readable Output

2. Get the results and status of a compliance search
Gets the status and results of a compliance search.
Base Command
exchange2016-get-compliance-search
Input
| Argument Name | Description | Required |
|---|---|---|
| search-name | Name of the compliance search | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| EWS.ComplianceSearch.Status | string | The status of the compliance search |
Command Example
exchange2016-get-compliance-search search-name=DemistoSearch939b54bcd2bb4848bb0885dc4071d366
Context Example
{
"EWS": {
"ComplianceSearch": {
"Status": "InProgress",
"Name": "DemistoSearch939b54bcd2bb4848bb0885dc4071d366"
}
}
}
Human Readable Output

3. Remove a compliance search
Removes the compliance search from the Exchange Server.
Base Command
exchange2016-remove-compliance-search
Input
| Argument Name | Description | Required |
|---|---|---|
| search-name | Name of the compliance search | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| EWS.ComplianceSearch.Status | string | The status of the compliance search |
Command Example
exchange2016-remove-compliance-search search-name="DemistoSearch939b54bcd2bb4848bb0885dc4071d366"
Context Example
{
"EWS": {
"ComplianceSearch": {
"Status": "Removed",
"Name": "DemistoSearch939b54bcd2bb4848bb0885dc4071d366"
}
}
}
Human Readable Output

4. Purge the results of a compliance search
Purges the results found during the compliance search.
Base Command
exchange2016-purge-compliance-search-results
Input
| Argument Name | Description | Required |
|---|---|---|
| search-name | Name of the compliance search | Required |
Context Output
There is no context output for this command.
Command Example
exchange2016-purge-compliance-search-results search-name="DemistoSearch939b54bcd2bb4848bb0885dc4071d366"
Context Example
{
"EWS": {
"ComplianceSearch": {
"Status": "Purging",
"Name": "DemistoSearch939b54bcd2bb4848bb0885dc4071d366"
}
}
}
Human Readable Output

5. Get the status of a purge operation
Checks the status of the purge operation on the compliance search.
Base Command
exchange2016-get-compliance-search-purge-status
Input
| Argument Name | Description | Required |
|---|---|---|
| search-name | Name of the compliance search | Required |
Context Output
There is no context output for this command.
Command Example
exchange2016-get-compliance-search-purge-status search-name="DemistoSearch939b54bcd2bb4848bb0885dc4071d366"
Context Example
{
"EWS": {
"ComplianceSearch": {
"Status": "Purging",
"Name": "DemistoSearch939b54bcd2bb4848bb0885dc4071d366"
}
}
}
Human Readable Output

Configuration parameters
credentials— DOMAIN\USERNAME (e.g., DEMISTO.INT\admin) (required)exchangeFQDN— Exchange Server fully qualified domain name (FQDN) (required)insecure— Trust any certificate (not secure)
Commands (5)
-
exchange2016-get-compliance-searchGets the status and results of a compliance search.
-
exchange2016-get-compliance-search-purge-statusChecks the status of the purge operation on the compliance search.
-
exchange2016-purge-compliance-search-resultsPurges the results found during the compliance search.
-
exchange2016-remove-compliance-searchRemoves the compliance search from the Exchange Server.
-
exchange2016-start-compliance-searchInitiates a compliance search.
import demistomock as demisto from CommonServerPython import * import subprocess import uuid USERNAME = demisto.params()['credentials']['identifier'].replace("'", "''") PASSWORD = demisto.params()['credentials']['password'].replace("'", "''") EXCHANGE_FQDN = demisto.params()['exchangeFQDN'].replace("'", "''") UNSECURE = demisto.params()['insecure'] STARTCS = ''' [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string]$username, [Parameter(Mandatory=$True)] [string]$query, [Parameter(Mandatory=$True)] [string]$server, [Parameter(Mandatory=$True)] [bool]$unsecure ) $WarningPreference = "silentlyContinue" $password = Read-Host $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force $UserCredential = New-Object System.Management.Automation.PSCredential ($username, $secpasswd) $searchName = [guid]::NewGuid().ToString() -replace '[-]' $searchName = "DemistoSearch" + $searchName if($unsecure){ $url = "http://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Kerberos }else{ $url = "https://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Basic -AllowRedirection } if (!$session) { "Failed to create remote PS session" return } Import-PSSession $session -CommandName *Compliance* -AllowClobber -DisableNameChecking -Verbose:$false | Out-Null $compliance = New-ComplianceSearch -Name $searchName -ExchangeLocation All -ContentMatchQuery $query -Confirm:$false Start-ComplianceSearch -Identity $searchName $complianceSearchName = "Action status: " + $searchName $complianceSearchName | ConvertTo-Json Remove-PSSession $session ''' GETCS = ''' [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string]$username, [Parameter(Mandatory=$True)] [string]$searchName, [Parameter(Mandatory=$True)] [string]$server, [Parameter(Mandatory=$True)] [bool]$unsecure ) $WarningPreference = "silentlyContinue" $password = Read-Host $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force $UserCredential = New-Object System.Management.Automation.PSCredential ($username, $secpasswd) if($unsecure){ $url = "http://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Kerberos }else{ $url = "https://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Basic -AllowRedirection } if (!$session) { "Failed to create remote PS session" return } Import-PSSession $session -CommandName Get-ComplianceSearch -AllowClobber ` -DisableNameChecking -Verbose:$false | Out-Null $searchStatus = Get-ComplianceSearch $searchName $searchStatus.Status if ($searchStatus.Status -eq "Completed") { $searchStatus.SuccessResults | ConvertTo-Json } Remove-PSSession $session ''' REMOVECS = ''' [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string]$username, [Parameter(Mandatory=$True)] [string]$searchName, [Parameter(Mandatory=$True)] [string]$server, [Parameter(Mandatory=$True)] [bool]$unsecure ) $WarningPreference = "silentlyContinue" $password = Read-Host $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force $UserCredential = New-Object System.Management.Automation.PSCredential ($username, $secpasswd) if($unsecure){ $url = "http://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Kerberos }else{ $url = "https://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Basic -AllowRedirection } if (!$session) { "Failed to create remote PS session" return } Import-PSSession $session -CommandName *Compliance* -AllowClobber -DisableNameChecking -Verbose:$false | Out-Null Remove-ComplianceSearch $searchName -Confirm:$false Remove-PSSession $session ''' STARTPURGE = ''' [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string]$username, [Parameter(Mandatory=$True)] [string]$searchName, [Parameter(Mandatory=$True)] [string]$server, [Parameter(Mandatory=$True)] [bool]$unsecure ) $WarningPreference = "silentlyContinue" $password = Read-Host $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force $UserCredential = New-Object System.Management.Automation.PSCredential ($username, $secpasswd) if($unsecure){ $url = "http://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Kerberos }else{ $url = "https://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Basic -AllowRedirection } if (!$session) { "Failed to create remote PS session" return } Import-PSSession $session -CommandName *Compliance* -AllowClobber -DisableNameChecking -Verbose:$false | Out-Null $newActionResult = New-ComplianceSearchAction -SearchName $searchName -Purge -PurgeType SoftDelete -Confirm:$false if (!$newActionResult) { "No action was created" } Remove-PSSession $session return ''' CHECKPURGE = ''' [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string]$username, [Parameter(Mandatory=$True)] [string]$searchName, [Parameter(Mandatory=$True)] [string]$server, [Parameter(Mandatory=$True)] [bool]$unsecure ) $WarningPreference = "silentlyContinue" $password = Read-Host $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force $UserCredential = New-Object System.Management.Automation.PSCredential ($username, $secpasswd) if($unsecure){ $url = "http://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Kerberos }else{ $url = "https://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Basic -AllowRedirection } if (!$session) { "Failed to create remote PS session" return } Import-PSSession $session -CommandName *Compliance* -AllowClobber -DisableNameChecking -Verbose:$false | Out-Null $actionName = $searchName + "_Purge" $actionStatus = Get-ComplianceSearchAction $actionName "" $actionStatus.Status Remove-PSSession $session ''' TESTCON = ''' [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string]$username, [Parameter(Mandatory=$True)] [string]$server, [Parameter(Mandatory=$True)] [bool]$unsecure ) $errorActionPreference = 'Stop' $WarningPreference = "silentlyContinue" $password = Read-Host $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force $UserCredential = New-Object System.Management.Automation.PSCredential ($username, $secpasswd) try{ if($unsecure){ $url = "http://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Kerberos }else{ $url = "https://" + $server + "/PowerShell" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url ` -Credential $UserCredential -Authentication Basic -AllowRedirection } echo "successful connection" } catch { $e = $_.Exception echo $e.Message } finally { Remove-PSSession $session } ''' def prepare_args(d): return dict((k.replace("-", "_"), v) for k, v in d.items()) def str_to_unicode(obj): if isinstance(obj, dict): obj = {k: str_to_unicode(v) for k, v in obj.iteritems()} elif isinstance(obj, list): obj = map(str_to_unicode, obj) elif isinstance(obj, str): obj = unicode(obj, "utf-8") return obj def encode_and_submit_results(obj): demisto.results(str_to_unicode(obj)) def get_cs_status(search_name, status): return { 'Type': entryTypes['note'], 'ContentsFormat': formats['text'], 'Contents': 'Search {} status: {}'.format(search_name, status), 'EntryContext': { 'EWS.ComplianceSearch(val.Name === obj.Name)': {'Name': search_name, 'Status': status} } } def create_ps_file(ps_name, ps_content): temp_path = os.getenv('TEMP') if not temp_path: return_error("Check that the integration is using single engine without docker." " If so, add TEMP variable to the enviroment varibes.") ps_path = temp_path + '\\' + ps_name # type: ignore with open(ps_path, 'w+') as file: file.write(ps_content) return ps_path def delete_ps_file(ps_path): if os.path.exists(ps_path): os.remove(ps_path) def start_compliance_search(query): try: ps_path = create_ps_file('startcs_' + str(uuid.uuid4()).replace('-', '') + '.ps1', STARTCS) output = subprocess.Popen(["powershell.exe", ps_path, "'" + USERNAME + "'", "'" + str(query).replace("'", "''") + "'", "'" + EXCHANGE_FQDN + "'", "$" + str(UNSECURE)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = output.communicate(input=PASSWORD.encode()) finally: delete_ps_file(ps_path) if stderr: return_error(stderr) prefix = '"Action status: ' pref_ind = stdout.find(prefix) sub_start = pref_ind + len(prefix) sub_end = sub_start + 45 search_name = stdout[sub_start:sub_end] return { 'Type': entryTypes['note'], 'ContentsFormat': formats['text'], 'Contents': 'Search started: {}'.format(search_name), 'EntryContext': { 'EWS.ComplianceSearch': {'Name': search_name, 'Status': 'Starting'} } } def get_compliance_search(search_name): try: ps_path = create_ps_file('getcs_' + search_name + '.ps1', GETCS) output = subprocess.Popen(["powershell.exe", ps_path, "'" + USERNAME + "'", "'" + search_name + "'", "'" + EXCHANGE_FQDN + "'", "$" + str(UNSECURE)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = output.communicate(input=PASSWORD.encode()) finally: delete_ps_file(ps_path) stdout = stdout[len(PASSWORD):] if stderr: return_error(stderr) stdsplit = stdout.split('\n', 1) status = stdsplit[0].strip() results = [get_cs_status(search_name, status)] if status == 'Completed' and len(stdsplit[1].strip()) > 4: res = list(r[:-1].split(', ') if r[-1] == ',' else r.split(', ') for r in stdsplit[1][2:-4].split(r'\r\n')) res = map(lambda x: {k: v for k, v in (s.split(': ') for s in x)}, res) results.append( { 'Type': entryTypes['note'], 'ContentsFormat': formats['text'], 'Contents': stdout, 'ReadableContentsFormat': formats['markdown'], 'HumanReadable': tableToMarkdown('Exchange 2016 Compliance search results', res, ['Location', 'Item count', 'Total size']) } ) return results def remove_compliance_search(search_name): try: ps_path = create_ps_file('removecs_' + search_name + '.ps1', REMOVECS) output = subprocess.Popen(["powershell.exe", ps_path, "'" + USERNAME + "'", "'" + search_name + "'", "'" + EXCHANGE_FQDN + "'", "$" + str(UNSECURE)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = output.communicate(input=PASSWORD.encode()) finally: delete_ps_file(ps_path) return return_error(stderr) if stderr else get_cs_status(search_name, 'Removed') def purge_compliance_search(search_name): try: ps_path = create_ps_file('startpurge_' + search_name + '.ps1', STARTPURGE) output = subprocess.Popen(["powershell.exe", ps_path, "'" + USERNAME + "'", "'" + search_name + "'", "'" + EXCHANGE_FQDN + "'", "$" + str(UNSECURE)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = output.communicate(input=PASSWORD.encode()) finally: delete_ps_file(ps_path) return return_error(stderr) if stderr else get_cs_status(search_name, 'Purging') def check_purge_compliance_search(search_name): try: ps_path = create_ps_file('checkpurge_' + search_name + '.ps1', CHECKPURGE) output = subprocess.Popen(["powershell.exe", ps_path, "'" + USERNAME + "'", "'" + search_name + "'", "'" + EXCHANGE_FQDN + "'", "$" + str(UNSECURE)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = output.communicate(input=PASSWORD.encode()) finally: delete_ps_file(ps_path) return return_error(stderr) if stderr else get_cs_status(search_name, 'Purged' if stdout.strip() == 'Completed' else 'Purging') def test_module(): try: ps_path = create_ps_file('testcon_' + str(uuid.uuid4()).replace('-', '') + '.ps1', TESTCON) output = subprocess.Popen(["powershell.exe", ps_path, "'" + USERNAME + "'", "'" + EXCHANGE_FQDN + "'", "$" + str(UNSECURE)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = output.communicate(input=PASSWORD.encode())[0].strip() finally: delete_ps_file(ps_path) stdout = stdout[len(PASSWORD):] if stdout == "successful connection": demisto.results('ok') else: return_error(stdout) args = prepare_args(demisto.args()) try: if demisto.command() == 'exchange2016-start-compliance-search': encode_and_submit_results(start_compliance_search(**args)) elif demisto.command() == 'exchange2016-get-compliance-search': encode_and_submit_results(get_compliance_search(**args)) elif demisto.command() == 'exchange2016-remove-compliance-search': encode_and_submit_results(remove_compliance_search(**args)) elif demisto.command() == 'exchange2016-purge-compliance-search-results': encode_and_submit_results(purge_compliance_search(**args)) elif demisto.command() == 'exchange2016-get-compliance-search-purge-status': encode_and_submit_results(check_purge_compliance_search(**args)) elif demisto.command() == 'test-module': test_module() except Exception as e: if isinstance(e, WindowsError): # pylint: disable=undefined-variable return_error("Could not open powershell on the target engine.") else: return_error(e)