Universal Cloud REST API connector workflow for Microsoft Sentinel

You can customize your workflow and workflow parameters based on the default workflow.

A workflow is an XML document that describes the event retrieval process. The workflow defines one or more parameters, which can be explicitly assigned values in the workflow XML or can derive values from the workflow parameter values XML document. The workflow consists of multiple actions that run sequentially.

Important: You need to obtain the Client ID, Client Secret, Tenant ID, and Workspace ID from Microsoft Azure. For more information, see Configuring Microsoft Sentinel to communicate with the QRadar product.

Microsoft Sentinel workflow

Use the following XML to populate the Workflow field in the Universal Cloud REST API connector parameters section.

Click the Copy to clipboard icon at the upper right of the code block, and then paste the content into the Workflow field.

<?xml version="1.0" encoding="UTF-8" ?>
<Workflow name="MicrosoftSentinel" version="1.0" xmlns="http://qradar.ibm.com/UniversalCloudRESTAPI/Workflow/V2">

    <Parameters>
        <Parameter name="workspaceid"   label="Workspace"       required="true" />
        <Parameter name="tenantid"      label="Tenant ID"       required="true" />
        <Parameter name="clientid"      label="Client ID"       required="true" />
        <Parameter name="clientsecret"  label="Client Secret"   required="true" secret="true" />
    </Parameters>

    <Actions>
        <ClearStatus />

        <Initialize path="/urls/loginUrl" value="login.microsoftonline.com" />
        <Initialize path="/urls/logAnalytics" value="api.loganalytics.io" />

        <CallEndpoint url="https://${/urls/loginUrl}/${/tenantid}/oauth2/token" method="POST" savePath="/analytics/auth">
            <RequestHeader name="Accept" value="application/json" />
            <UrlEncodedFormRequestBody>
                <Parameter name="grant_type" value="client_credentials" />
                <Parameter name="client_id" value="${/clientid}" />
                <Parameter name="client_secret" value="${/clientsecret}" />
                <Parameter name="resource" value="https://${/urls/logAnalytics}" />
            </UrlEncodedFormRequestBody>
        </CallEndpoint>

        <If condition="/analytics/auth/status_code != 200">
            <Abort reason="Failed to obtain access token. Server returned status code ${/analytics/auth/status_code}" />
        </If>
        <Else>
            <SetStatus type="INFO" message="Successfully obtained access token." />
        </Else>

        <Initialize path="/alerts/pageSize" value="100" />

        <Initialize path="/alerts/from" value="${time() - (60000 * 60 * 24 * 7)}" />
        <FormatDate pattern="yyyy-MM-dd'T'HH:mm:ss" time="${/alerts/from}" savePath="/alerts/fromFormatted"/>

        <Set path="/alerts/to" value="${time()}" />
        <FormatDate pattern="yyyy-MM-dd'T'HH:mm:ss" time="${/alerts/to}" savePath="/alerts/toFormatted"/>

        <Log type="DEBUG" message="Retrieving alerts between ${/alerts/fromFormatted} and now" />
        <Log type="DEBUG" message="Getting first ${/alerts/pageSize} alerts" />

        <Set path="/alerts/pageStartNum" value="1" />
        <Set path="/alerts/pageEndNum" value="${/alerts/pageSize}" />

        <Set path="/alerts/totalResults" value="0" />

        <DoWhile condition="count(/alerts/response/body/tables[0]/rows) > 0">
            <CallEndpoint url="https://${/urls/logAnalytics}/v1/workspaces/${/workspaceid}/query" method="GET" savePath="/alerts/response">
                <QueryParameter name="query" value="SecurityAlert | where StartTime between (datetime(${/alerts/fromFormatted}) .. datetime(${/alerts/toFormatted})) | summarize arg_max(TimeGenerated, *) by SystemAlertId | sort by StartTime asc | extend RowNum=row_number() | where RowNum between (${/alerts/pageStartNum} .. ${/alerts/pageEndNum})"/>
                <RequestHeader name="Authorization" value="Bearer ${/analytics/auth/body/access_token}" />
                <RequestHeader name="Accept" value="application/json" />
            </CallEndpoint>

            <If condition="/alerts/response/status_code != 200">
                <Log type="DEBUG" message="${/alerts/response/status/code}: ${/alerts/response/status/message}"/>
                <Log type="DEBUG" message="${/alerts/response/body/error/message/code} : ${/alerts/response/body/error/message}"/>
                <Log type="DEBUG" message="${/alerts/response/body/error/message/innererror/code} : ${/alerts/response/body/error/message/innererror/message}"/>
                <Log type="DEBUG" message="${/alerts/response/body/error/message/innererror/innererror/code} : ${/alerts/response/body/error/message/innererror/innererror/message}"/>
                <Abort reason="${/alerts/response/status/code}: ${/alerts/response/status/message}" />
            </If>
            <Else>
                <SetStatus type="INFO" message="Successfully Queried for alerts." />
            </Else>

            <Log type="DEBUG" message="Response contains ${count(/alerts/response/body/tables[0]/rows)} alerts" />
            <Set path="/alerts/totalResults" value="${/alerts/totalResults + count(/alerts/response/body/tables[0]/rows)}" />

            <Set path="/rowIndex" value="0"/>
            <While condition="exists /alerts/response/body/tables[0]/rows[${/rowIndex}]">
                <Set path="/index" value="0"/>
                <Set path="/row" value="${/alerts/response/body/tables[0]/rows[${/rowIndex}]}"/>

                <While condition="exists /alerts/response/body/tables[0]/columns[${/index}]">
                    <Set path="/col" value="${/alerts/response/body/tables[0]/columns[${/index}]}"/>
                    <If condition="${count(/rowSplit)} - 1 > ${/index}">
                        <Set path="/payload/${/col/name}" value="${/row[${/index}]},"/>
                    </If>
                    <Else>
                        <Set path="/payload/${/col/name}" value="${/row[${/index}]}"/>
                    </Else>
                    <Set path="/index" value="${/index + 1}"/>
                </While>

                <PostEvent path="/payload" source="${/clientid}"/>
                <Delete path="/payload"/>

                <Set path="/rowIndex" value="${/rowIndex + 1}"/>
            </While>
            <Set path="/alerts/pageStartNum" value="${/alerts/pageStartNum + /alerts/pageSize}" />
            <Set path="/alerts/pageEndNum" value="${/alerts/pageEndNum + /alerts/pageSize}" />
        </DoWhile>
        <ParseDate pattern="yyyy-MM-dd'T'HH:mm:ss" date="${/alerts/toFormatted}" timeZone="UTC" savePath="/alerts/to"/>
        <Set path="/alerts/from" value="${/alerts/to + 1}" />
        <Log type="DEBUG" message="Total alerts pulled this iteration: ${/alerts/totalResults}" />
        <Delete path="/alerts/response" />
        <Delete path="/analytics/auth" />
    </Actions>
    <Tests>
        <DNSResolutionTest host="${/urls/loginUrl}"/>
        <DNSResolutionTest host="${/urls/logAnalytics}"/>
        <TCPConnectionTest host="${/urls/loginUrl}"/>
        <TCPConnectionTest host="${/urls/logAnalytics}"/>
        <HTTPConnectionThroughProxyTest url="https://${/urls/loginUrl}"/>
        <HTTPConnectionThroughProxyTest url="https://${/urls/logAnalytics}"/>
        <SSLHandshakeTest host="${/urls/loginUrl}" />
        <SSLHandshakeTest host="${/urls/logAnalytics}" />
    </Tests>
</Workflow>

Microsoft Sentinel workflow parameters

Use the following XML to populate the Workflow Parameter Values field in the Universal Cloud REST API connector parameters section.

Click the Copy to clipboard icon at the upper right of the code block, and then paste the content to a text file. Replace the values for <your-workspaceid>, <your-tenantid>, <your-clientid> and <your-clientsecret> with your own values. Then copy the updated content into the Workflow Parameter Values field.

<?xml version="1.0" encoding="UTF-8" ?>
<WorkflowParameterValues xmlns="http://qradar.ibm.com/UniversalCloudRESTAPI/WorkflowParameterValues/V2">
	<Value name="workspaceid" 	value="<your-workspaceid>"/>
	<Value name="tenantid" 		value="<your-tenantid>"/>
	<Value name="clientid" 		value="<your-clientid>"/>
	<Value name="clientsecret" 	value="<your-clientsecret>"/>
</WorkflowParameterValues>