Agent Communication Restriction Detector - Flow Setup Guide¶
Overview¶
Step-by-step guide for building the ACRD Power Automate flows for automated agent communication restriction scanning and exception approval management.
This guide covers two flows:
- ACRD-Scanner -- Daily scheduled scan of agent-to-agent communication patterns across all environments
- ACRD-Exception-Approval -- Approval workflow triggered when a new communication exception is requested
Important: These are manual build instructions. This solution does not include exported flow JSON files. Build each flow in the Power Automate designer following the steps below.
Prerequisites¶
Before creating the flows, confirm you have:
- Azure Automation Account with:
Start-CommRestrictionValidationRunbook.ps1imported as a PowerShell 7.2 runbook- Certificate uploaded (Certificates blade)
- Modules installed: MSAL.PS, Microsoft.PowerApps.Administration.PowerShell
- Application permissions granted as required by Power Platform admin APIs
- Dataverse environment with ACRD schema deployed:
- 5 tables:
fsi_CommScanRun,fsi_AgentCommViolation,fsi_ApprovedCommRoute,fsi_CommException,fsi_AgentSkillRegistration - 9 environment variables configured
- 4 connection references created
- Microsoft Teams channel for alert notifications
- Email distribution list for compliance alerts
- Power Automate Premium license (required for Azure Automation connector)
- Connection references bound in Power Automate:
fsi_cr_dataverse_commrestrictiondetector(Dataverse)fsi_cr_teams_commrestrictiondetector(Microsoft Teams)fsi_cr_office365_commrestrictiondetector(Office 365 Outlook)fsi_cr_azureautomation_commrestrictiondetector(Azure Automation)
Flow 1: ACRD-Scanner¶
Purpose¶
Runs daily at 6:00 AM UTC, executes the Azure Automation runbook to scan agent-to-agent communication patterns, writes results to Dataverse, and routes alerts based on severity.
Step 1: Create the Flow¶
- Go to make.powerautomate.com
- Select your governance environment
- Click Create > Scheduled cloud flow
- Name:
ACRD - Communication Restriction Validation (Daily) - Set schedule:
- Start: Today
- Repeat every: 1 Day
- At: 6:00 AM
- Time zone: UTC
- Click Create
Step 2: Initialize Variables¶
Add these Initialize variable actions immediately after the trigger:
| Variable | Type | Default Value | Description |
|---|---|---|---|
DataverseUrl |
String | https://governance.crm.dynamics.com |
Your Dataverse environment URL |
TenantId |
String | {{TENANT_DOMAIN}} |
Microsoft Entra ID tenant identifier |
ClientId |
String | {{CLIENT_ID}} |
App registration client ID |
CertificateThumbprint |
String | {{CERTIFICATE_THUMBPRINT}} |
Certificate thumbprint in Azure Automation |
SubscriptionId |
String | {{AZURE_SUBSCRIPTION}} |
Azure subscription containing Automation Account |
ResourceGroup |
String | {{RESOURCE_GROUP}} |
Resource group with Automation Account |
AutomationAccount |
String | {{AUTOMATION_ACCOUNT}} |
Azure Automation Account name |
TeamsGroupId |
String | {{TEAMS_GROUP_ID}} |
Teams group (team) ID for alerts |
TeamsChannelId |
String | {{TEAMS_CHANNEL_ID}} |
Teams channel ID for alerts |
ComplianceDistributionList |
String | {{COMPLIANCE_EMAIL}} |
Email DL for all alerts |
Step 3: Execute Azure Automation Runbook¶
- Add action: Azure Automation > Create job
- Configure:
- Subscription:
SubscriptionIdvariable - Resource Group:
ResourceGroupvariable - Automation Account:
AutomationAccountvariable - Runbook Name:
Start-CommRestrictionValidationRunbook - Runbook Parameters:
TenantId:TenantIdvariableClientId:ClientIdvariableCertificateThumbprint:CertificateThumbprintvariableDataverseUrl:DataverseUrlvariable
- Rename action:
Create_Automation_Job
Step 4: Wait for Job Completion¶
- Add action: Azure Automation > Wait for job
- Configure:
- Job ID:
Create_Automation_Joboutput jobId - Timeout: 7200 seconds (2 hours)
- Polling interval: 30 seconds
- Rename action:
Wait_For_Job
Step 5: Get Job Output¶
- Add action: Azure Automation > Get job output
- Configure:
- Job ID: same jobId from Step 3
- Rename action:
Get_Job_Output
Step 6: Parse JSON Results¶
- Add action: Data Operations > Parse JSON
- Content:
Get_Job_Outputoutput - Schema: regenerate from a real runbook output sample (Power Automate "Generate from sample"). The runbook emits the following top-level shape:
{
"type": "object",
"properties": {
"RunType": { "type": "string" },
"RunId": { "type": "string" },
"Timestamp": { "type": "string" },
"TotalSkills": { "type": "integer" },
"TotalAgents": { "type": "integer" },
"TotalEnvironments": { "type": "integer" },
"EnvironmentNames": { "type": "string" },
"OverallStatus": { "type": "string" },
"Reason": { "type": ["string", "null"] },
"Control": { "type": "string" },
"ViolationCount": { "type": "integer" },
"AlertRequired": { "type": "boolean" },
"AlertSeverity": { "type": "string" },
"ZoneSummary": { "type": "object" },
"Drift": {
"type": "object",
"properties": {
"HasDrift": { "type": "boolean" },
"IsFirstRun": { "type": "boolean" },
"DriftedRoutes": { "type": "integer" },
"Details": { "type": "array" }
}
},
"SkillSnapshot": { "type": "array" },
"Violations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"AgentId": { "type": "string" },
"AgentName": { "type": "string" },
"TargetAgentId": { "type": "string" },
"TargetAgentName": { "type": "string" },
"SkillName": { "type": "string" },
"EnvironmentId": { "type": "string" },
"EnvironmentName": { "type": "string" },
"SourceZone": { "type": "string" },
"TargetZone": { "type": "string" },
"ViolationType": { "type": "string" },
"Severity": { "type": "string" },
"RegulatoryContext": { "type": "string" },
"IsCrossEnvironment": { "type": "boolean" },
"IsCrossTenant": { "type": "boolean" }
}
}
}
}
}
Note:
OverallStatusmay be any ofPassed,Failed,Critical,Review,Error. Downstream Switch/Condition actions must enumerate all five values;CriticalandRevieware not aliases ofFailed.
- Rename action:
Parse_Results
Step 7: Write Scan Run to Dataverse¶
Why this runs before alerting: The audit trail record is created regardless of whether alerting succeeds or fails. This supports compliance with FINRA 4511 and SEC 17a-3 audit trail requirements.
- Add action: Dataverse > Add a new row
- Table:
Comm Scan Run(fsi_CommScanRun) - Connection reference:
fsi_cr_dataverse_commrestrictiondetector - Column mapping:
| Flow Expression | Dataverse Column | Type | Description |
|---|---|---|---|
"ACRDRun-" + Timestamp |
fsi_name |
String | Display name with scan timestamp |
RunId |
fsi_runid |
String | Unique run identifier (also enables join to violations) |
OverallStatus |
fsi_overallstatus |
String | Passed / Failed / Critical / Review / Error |
ViolationCount |
fsi_violationcount |
Integer | Number of violations detected |
TotalAgents |
fsi_totalagents |
Integer | Total agents scanned |
TotalSkills |
fsi_totalskills |
Integer | Total skill registrations scanned |
EnvironmentNames |
fsi_environmentsscanned |
String | Comma-separated environment display names (NOT the count). The runbook emits this list as EnvironmentNames; the schema documents this column as "Comma-separated environments covered". Mapping string(TotalEnvironments) would persist "3" instead of "Contoso-Prod, Contoso-Dev, Contoso-Test" and destroy audit value. |
| Full JSON output | fsi_summaryjson |
Memo | Complete runbook output (includes SkillSnapshot required for next-run drift detection) |
Timestamp |
fsi_validationtime |
DateTime | Scan execution timestamp |
- Rename action:
Write_Scan_Run
Step 8: Check if Alert Required¶
- Add action: Condition
- Condition:
AlertRequiredis equal totrue - Configure Run after:
Write_Scan_Run-- set to run after Succeeded and Failed (so alerting proceeds even if the Dataverse write fails) - Rename action:
Check_Alert_Required
Step 9: If Yes -- Post Teams Adaptive Card¶
- In the Yes branch, add: Microsoft Teams > Post adaptive card in a chat or channel
- Connection reference:
fsi_cr_teams_commrestrictiondetector - Post in: Channel
- Team:
TeamsGroupIdvariable - Channel:
TeamsChannelIdvariable - Adaptive Card JSON (summary template):
{
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.4",
"body": [
{
"type": "TextBlock",
"text": "Agent Communication Restriction Alert",
"weight": "Bolder",
"size": "Large",
"color": "Attention"
},
{
"type": "FactSet",
"facts": [
{ "title": "Status", "value": "${OverallStatus}" },
{ "title": "Severity", "value": "${AlertSeverity}" },
{ "title": "Violations", "value": "${ViolationCount}" },
{ "title": "Agents Scanned", "value": "${TotalAgents}" },
{ "title": "Environments", "value": "${TotalEnvironments}" },
{ "title": "Scan Time", "value": "${Timestamp}" }
]
}
]
}
- Rename action:
Post_Teams_Card
Step 10: If Yes -- Send Email Alert¶
- Still in the Yes branch, add: Office 365 Outlook > Send an email (V2)
- Connection reference:
fsi_cr_office365_commrestrictiondetector - Configure:
- To:
ComplianceDistributionListvariable - Subject:
[ACRD Alert- @{AlertSeverity}] Agent Communication Violations Detected - Importance: High (for Critical/Failed/Error), Normal (for Warning)
- Body: HTML table with violation summary, zone breakdown, communication pattern details, and agent-level details
- Rename action:
Send_Alert_Email
Step 11: Error Handling (Scope_Catch)¶
- Wrap steps 3-10 in a Scope named
Scope_Main - Add a parallel Scope named
Scope_Catch - Configure
Scope_Catchto run afterScope_Mainhas Failed or Timed Out - Inside
Scope_Catch, add Send an email (V2): - To:
ComplianceDistributionListvariable - Subject:
[CRITICAL] ACRD Flow Execution Failed - Importance: High
- Body: Include error details from
Scope_Mainresult
Alert Routing Summary¶
| Severity | Teams Card | Email Importance | |
|---|---|---|---|
| Critical | Yes | Yes | High |
| Failed | Yes | Yes | High |
| Error | Yes | Yes | High |
| High | Yes | Yes | High |
| Warning | No | Yes | Normal |
| Passed/Info | No | No | -- |
Flow 2: ACRD-Exception-Approval¶
Purpose¶
Provides a structured approval workflow when agents require exceptions to blocked communication patterns. Triggered automatically when a new communication exception record is created in Dataverse, routes the request to the governance team for approval, and updates the exception status accordingly.
Step 1: Create the Flow¶
- Go to make.powerautomate.com
- Select your governance environment
- Click Create > Automated cloud flow
- Name:
ACRD - Communication Exception Approval - Choose trigger: Dataverse > When a row is added, modified or deleted
- Click Create
Step 2: Configure Trigger¶
- Change type: Create
- Table name:
Comm Exception(fsi_CommException) - Scope: Organization (all users)
- Connection reference:
fsi_cr_dataverse_commrestrictiondetector
Step 3: Get Exception Details¶
- Add action: Dataverse > Get a row by ID
- Table name:
Comm Exception(fsi_CommException) - Row ID: Trigger row ID
- Select columns:
fsi_name, fsi_callingagentid, fsi_calledagentid, fsi_sourcezone, fsi_targetzone, fsi_justification - Connection reference:
fsi_cr_dataverse_commrestrictiondetector - Rename action:
Get_Exception_Details
Step 4: Send Approval Email¶
- Add action: Approvals > Start and wait for an approval
- Configure:
- Approval type: Approve/Reject - First to respond
- Title:
[ACRD Exception] @{fsi_callingagentid} -> @{fsi_calledagentid} - Assigned to:
{{COMPLIANCE_EMAIL}} - Details (HTML):
<h3>Communication Exception Request</h3> <table> <tr><td><b>Calling Agent:</b></td><td>@{fsi_callingagentid}</td></tr> <tr><td><b>Called Agent:</b></td><td>@{fsi_calledagentid}</td></tr> <tr><td><b>Source Zone:</b></td><td>@{fsi_sourcezone}</td></tr> <tr><td><b>Target Zone:</b></td><td>@{fsi_targetzone}</td></tr> <tr><td><b>Justification:</b></td><td>@{fsi_justification}</td></tr> </table> - Item link: Link to the Dataverse record
- Rename action:
Wait_For_Approval
Step 5: Check Approval Response¶
- Add action: Condition
- Condition:
Outcomeis equal toApprove - Rename action:
Check_Approval_Outcome
Step 6: If Approved -- Update Exception Status¶
- In the Yes branch, add: Dataverse > Update a row
- Table name:
Comm Exception(fsi_CommException) - Row ID: Trigger row ID
- Column mapping:
fsi_exceptionstatus:100000001(option set integer for Approved — values: 100000000=Pending, 100000001=Approved, 100000002=Denied, 100000003=Expired). Power Automate's Dataverse "Update a row" connector requires the integer option set value, not the label.fsi_approvedby: Approver display name from approval responsefsi_approvedat:utcNow()- Connection reference:
fsi_cr_dataverse_commrestrictiondetector - Rename action:
Update_Exception_Approved
Step 7: If Denied -- Update Exception Status¶
- In the No branch, add: Dataverse > Update a row
- Table name:
Comm Exception(fsi_CommException) - Row ID: Trigger row ID
- Column mapping:
fsi_exceptionstatus:100000002(option set integer for Denied)fsi_approvedby: Responder display name from approval responsefsi_approvedat:utcNow()- Connection reference:
fsi_cr_dataverse_commrestrictiondetector - Rename action:
Update_Exception_Denied
Step 8: Log to Audit Trail¶
After either branch (use a common action after the condition):
- Add action: Dataverse > Add a new row
- Table:
Comm Scan Run(fsi_CommScanRun) - Column mapping:
fsi_name:"ExceptionDecision-" + utcNow()fsi_overallstatus:"Info"fsi_summaryjson: JSON object with exception ID, decision (Approved/Denied), approver, comments, source/target agent detailsfsi_validationtime:utcNow()- Rename:
Log_Exception_Decision
Step 9: Send Notification to Requester¶
- Add action: Office 365 Outlook > Send an email (V2)
- Connection reference:
fsi_cr_office365_commrestrictiondetector - Configure:
- To: Exception requester (from
createdbysystem field or distribution list) - Subject:
[ACRD Exception @{Outcome}] @{fsi_callingagentid} -> @{fsi_calledagentid} - Body: HTML with decision details, approver comments, and next steps
- Importance: Normal
- Rename action:
Send_Requester_Notification
Step 10: Test the Flow¶
- Click Test > Manually
- In another browser tab, open the Dataverse
fsi_CommExceptiontable - Add a test record with:
- Source and target agent names
- Communication pattern (e.g., "Cross-Zone")
- Justification text
- Verify:
- Approval email arrives at the compliance DL
- Approve or deny the request
- Exception record status is updated in Dataverse
- Audit trail record is written to
fsi_CommScanRun - Requester receives notification email
- Flow run completes without errors
Troubleshooting¶
Azure Automation Job Failures¶
- Job stuck in "Running": Check Azure Automation job logs; may be waiting for module install
- Job completes but output is empty: Verify runbook parameters, check Write-Verbose output
- Authentication errors: Verify certificate thumbprint, check certificate expiration
- Module not found: Install MSAL.PS in Automation Account (Modules blade)
- Timeout (2-hour limit): The Wait_For_Job loop times out after 2 hours; increase if scanning many agents
Dataverse Write Failures¶
| Error Code | Cause | Resolution |
|---|---|---|
| 403 Forbidden | Identity lacks Create permission on ACRD tables | Assign security role with Organization-level Create |
| 404 Not Found | Table not deployed to environment | Deploy Dataverse schema (scripts/deploy.py) |
| 400 Bad Request | Schema mismatch (column names do not match) | Verify column names match the schema deployed |
Teams Channel Not Found¶
- Verify
TeamsGroupIdandTeamsChannelIdvariables match your target channel - Confirm the Teams connection has permissions to post to the channel
- Check that
fsi_cr_teams_commrestrictiondetectorconnection reference is properly bound - Test channel posting manually in Power Automate to isolate permissions issues
Parse JSON Schema Mismatch¶
- The Parse_Results schema must match the runbook output structure exactly
- If the runbook output changes (e.g., new fields added), update the schema in the flow
- Key ACRD schema differences from other solutions:
SourceZone/TargetZonefields per violation,TargetAgentId/TargetAgentNamefor communication target,CommunicationPatternfor the detected pattern type
Approval Flow Issues¶
- Approval not received: Verify the
{{COMPLIANCE_EMAIL}}distribution list is correct and members have Power Automate licenses - Approval times out: The default approval timeout is 30 days; configure a custom timeout if needed
- Exception status not updating: Check Dataverse permissions for the flow connection identity
Flow Errors (Scope_Catch)¶
- If you receive a "[CRITICAL] ACRD Flow Execution Failed" email, the flow itself encountered an error
- Check the flow run history for the specific action that failed
- Common causes: expired connections, permission changes, Azure Automation account unavailable
Agent Communication Restriction Detector -- Flow Setup Guide v1.1.0