Working with the Remote Execution Context in Power Automate

Here is my first post for the “Tips & Tricks” section of my blog, its entire purpose is to share some tricks or patterns that I encountered whilst working/playing with the Power Platform. Hopefully it is useful and practical!

This post is based on a great concept which Alex Shlega posted a few months ago, you can read his article here – “CDS Post Images and CDS Pre Images in PowerAutomate Flows”. In this write up we are going to build on the concept by extracting and consuming the remote execution context in a no-code approach.

Here is what we are going to cover in this post:

  • A brief explanation for the reason behind using the CDS service endpoint and Azure Service Bus
  • Extract remote execution context from the Azure Service Bus queue message
  • Demonstrate an efficient way to use flow variables to hold entity attribute values
  • Child flow pattern in Power Automate to make extraction of entity attribute values more reusable
The Reason for Using the CDS Service Endpoint and Azure Service Bus

There are often integration scenarios where an event triggered in the Common Data Service (CDS) must offload the business logic to an external service. Real-world requirements might be:

  • Adding and removing users from certain Microsoft 365 Azure AD groups using the Microsoft Graph API
  • Offloading auditing to an external store like Azure Storage
  • Copying SharePoint documents to a new location when the document location is updated

The CDS connector trigger – “When a record is created, updated or deleted”, does a great job of capturing CDS events, but unfortunately it doesn’t return the execution context of the caused event. Without the context we cannot access information such as the PreEntityImages or PostEntityImages collections.

By configuring the Azure Service Bus for integration with CDS Service Endpoint, the remote execution context is passed to the Azure Service Bus listener for those events raised by the entities that are configured as steps for the service endpoint. A way to read these messages from the Azure Service Bus queue, or via topic subscription, is to configure a flow with an Azure Service Bus connector trigger.

Let’s Get Started! Our Sample Scenario

Let’s build a flow that receives a message from an Azure Service Bus queue whenever a request (e.g. Create, Update, Delete) is executed on an Account record. From the message, we will extract the Pre Image and Post Image from their respective Entity Image Collection and filter through the image for specific attributes to use later in the flow actions.

Extract Execution Context From the Azure Service Bus Queue Message

The contextual information returned can be extracted and saved neatly in variables:

#Trigger/ActionDescription
1.[Azure Service Bus]
Trigger
Once the connection for the connector has been set, a list of queues accessible by the connection permission will be made available to select. For our case, the queue is called account.
2.[Compose]
Convert Base64 Message to JSON
Message from the queue must be 1) converted from base 64 to string, then 2) to JSON to access the message properties easier using the expressions

Value/Expression:
json(base64ToString(triggerOutputs()?[‘body/ContentData’]))
3.[Initialize Variable] Initialize Context Primary Entity NameContext Primary Entity Name

Value/Expression:
outputs(‘Convert_Base64_Message_to_JSON’)?[‘PrimaryEntityName’]
4.[Initialize Variable]
Initialize Context Primary Entity Id
Context Primary Entity Id

Value/Expression:
outputs(‘Convert_Base64_Message_to_JSON’)?[‘PrimaryEntityId’]
5.[Initialize Variable]
Initialize Context Message Name
Message Name – e.g. Create, Update or Delete

Value/Expression:
outputs(‘Convert_Base64_Message_to_JSON’)?[‘MessageName’]
Using Flow Variables to Store Attribute Values From the Entity Images

These variables will play a crucial part later in the flow:

#ActionDescription
6.[Initialize Variable]
Initialize Filtering Attributes
Filtering Attributes – an array of JSON objects that define the attributes to be extracted from the entity image

Schema:
[{
    "name": "internal attribute name", 
    "valueSelector": "path to the value property", 
    "defaultValue": "default value in the case where the value is null or undefined"
}, 
...]

Value: e.g.
[
    {
        "name": "ownerid",
        "valueSelector": "value/Id",
        "defaultValue": null
    },
    {
        "name": "modifiedby",
        "valueSelector": "value/Id",
        "defaultValue": null
    },
    {
        "name": "modifiedon",
        "valueSelector": "value",
        "defaultValue": null
    },
    {
        "name": "name",
        "valueSelector": "value",
        "defaultValue": null
    },
    {
        "name": "statecode",
        "valueSelector": "value/Value",
        "defaultValue": -1
    }
]
7.[Initialize Variable]
Initialize Pre Image Object
Pre Image Object – a JSON object to store attribute values from the pre image entity

Value:
No value set initially
8.[Initialize Variable]
Initialize Post Image Object
Post Image Object – a JSON object to store attribute values from the post image entity

Value:
No value set initially
9.[Initialize Variable]
Initialize Merged Image Object
Merged Image Object – a JSON object to store merged attribute values from the PreImageObject and PostImageObject variables

Value:
{}
Extracting Pre Image Attribute Values

We need to include some validation checks to make sure the message received by the queue is for the account entity and execute different actions depending on the context message:

Check if the execution context is for the Create message as the PreEntityImages property doesn’t exist for this event:

#ActionDescription
10.1[Filter Array]
Find PreImage in PreEntityImage
Iterate PreEntityImages array to find the pre image using the name specified at the image registration e.g. PreImage

From/Expression:
outputs(‘Convert_Base64_Message_to_JSON’)?[‘PreEntityImages’]

Where/Expression – (Switch to edit in advance mode):
@equals(item()?[‘key’], ‘PreImage’)
10.2[Child Flow]
Extract Pre Image Attributes Values
The action of extracting the attribute values from the entity image has been abstracted away into a child flow. This child flow can be reused for any number of images and flows with similar scenarios. The request takes two properties:

EntityImage/Expression:
first(body(‘Find_PreImage_in_PreEntityImage’))

FilteringAttributes/Expression:
variables(‘FilteringAttributes’)
10.3[Set Variable]
Set Pre Image Object – Extracted Value
The result of the child flow will be set in PreImageObject variable

Value/Expression:
body(‘Extract_Pre_Image_Attributes_Values’)?[‘Body’]
Child Flow – Extract Attribute Values From the Entity Image

View the full overview of this child flow here.

Before we dive into the main section of this flow, let’s have a quick look at the JSON of an entity image (note: I’ve removed properties and attributes that are not relevant for this post to make it more readable). Highlighted are the values we are going to extract. Don’t these properties look familiar? These are what we’ve defined in the FilteringAttributes variable:

{
  "key": "PreImage",
  "value": {
    "Attributes": [
      {
        "key": "statecode",
        "value": {
          "__type": "OptionSetValue:http://schemas.microsoft.com/xrm/2011/Contracts",
          "Value": 0
        }
      },
      {
        "key": "ownerid",
        "value": {
          "__type": "EntityReference:http://schemas.microsoft.com/xrm/2011/Contracts",
          "Id": "0c7a4bce-d339-4467-8420-d22e15cbd374",
          "KeyAttributes": [],
          "LogicalName": "systemuser",
          "Name": "Tae Rim Han",
          "RowVersion": null
        }
      },
      {
        "key": "name",
        "value": "Oscorp"
      },
      {
        "key": "modifiedby",
        "value": {
          "__type": "EntityReference:http://schemas.microsoft.com/xrm/2011/Contracts",
          "Id": "0c7a4bce-d339-4467-8420-d22e15cbd374",
          "KeyAttributes": [],
          "LogicalName": "systemuser",
          "Name": "Tae Rim Han",
          "RowVersion": null
        }
      },
      {
        "key": "modifiedon",
        "value": "/Date(1603795983000)/"
      }
    ],
    "FormattedValues": [
      {
        "key": "statecode",
        "value": "Active"
      },
      {
        "key": "ownerid",
        "value": "Tae Rim Han"
      },
      {
        "key": "modifiedby",
        "value": "Tae Rim Han"
      },
      {
        "key": "modifiedon",
        "value": "2020-10-27T21:53:03+11:00"
      }
    ],
    "Id": "f2470e8e-fe5f-ea11-a811-000d3ad20d1d",
    "LogicalName": "account"
  }
}

The output of this flow is a JSON object with property names that match the filtering attribute names and the value set to the respective attribute values. Example of a resulting payload:

{
  "ownerid": "0c7a4bce-d339-4467-8420-d22e15cbd374",
  "ownerid_formattedvalue": "Tae Rim Han",
  "modifiedby": "0c7a4bce-d339-4467-8420-d22e15cbd374",
  "modifiedby_formattedvalue": "Tae Rim Han",
  "modifiedon": "/Date(1603795983000)/",
  "modifiedon_formattedvalue": "2020-10-27T21:53:03+11:00",
  "name": "Ozcorp",
  "statecode": 0,
  "statecode_formattedvalue": "Active"
}

The resulting value will be set in this flow variable:

Ok, with all that said let’s cover the main section. We iterate each attribute defined in the FilteringAttribute array:

#ActionDescription
A.[Apply to Each]
Apply to Filtering Attributes
Iterate each attribute definition

Input/Expression:
triggerBody()?[‘FilteringAttributes’]
A.1[Filter Array]
Find Attribute in Image
Find attribute by name e.g. ownerid

From/Expression:
triggerBody()?[‘EntityImage’]?[‘value’]?[‘Attributes’]

Where/Expression – (Switch to edit in advance mode):
@equals(item()?[‘key’], items(‘Apply_to_Filtering_Attributes’)?[‘name’])
A.2[Compose]
Compose Image Object Property Value
This compose expression may look intimidating at first but all it is doing is adding a new property to the JSON object where the name is the filtering attribute name and the value is the attribute value found in the path specified in the valueSelector property. If no value is found in that path, defaultValue will be used instead.

Inputs/Expression:
addProperty(variables(‘AttributeValuesObject’), items(‘Apply_to_Filtering_Attributes’)?[‘name’], coalesce(first(body(‘Find_Attribute_in_Image’))?[items(‘Apply_to_Filtering_Attributes’)?[‘valueSelector’]], items(‘Apply_to_Filtering_Attributes’)?[‘defaultValue’]))

Explanation:
addProperty("<Flow variable name>", "<Property name>", "<Value>")

Where:
"<Property name>" = attribute name
"<Value>" = coalesce(“JSON attribute object[Path to value]”, “Default value”)
A.3[Set Variable]
Set Attribute Values Object – Value
Set AttributeValuesObject with the added property.

Value/Expression:
outputs(‘Compose_Image_Object_Property_Value’)

We are going to do something very similar but for formatted values (if they exist). This way we don’t have to make additional requests to CDS to get either the name of an entity reference or option-set metadata:

#ActionDescription
A.4[Filter Array]
Find Formatted Value in Image
Continuing on, in the context of our apply-each loop for filtering attributes, find the formatted value for the attribute by name.

From/Expression:
triggerBody()?[‘EntityImage’]?[‘value’]?[‘FormattedValues’]

Where/Expression – (Switch to edit in advance mode):
@equals(item()?[‘key’], items(‘Apply_to_Filtering_Attributes’)?[‘name’])
A.5[Condition]
Check Formatted Value Exists in Image
Check if a formatted value exists.

Condition Expression:
length(body(‘Find_Formatted_Value_in_Image’)) equals 1
A.6[Compose]
Compose Image Object Property Formatted Value
If one exists, compose a new property to add to AttributeValuesObject variable. The property name is in this the format – “<attribute name>_formattedvalue”

Inputs/Expression:
addProperty(variables(‘AttributeValuesObject’), concat(items(‘Apply_to_Filtering_Attributes’)?[‘name’], ‘_formattedvalue’), first(body(‘Find_Formatted_Value_in_Image’))?[‘value’])

Explanation:
addProperty("<Flow variable name>", "<Property name>", "<Value>")

Where:
"<Property name>" = concat(“attribute name”, “_formattedvalue”)
"<Value>" = “Value if one exists”)
A.7[Set Variable]
Set Attribute Values Object – Formatted Value
Set AttributeValuesObject with the added property.

Value/Expression:
outputs(‘Compose_Image_Object_Property_Formatted_Value’)

As a flow response, the AttributeValuesObject variable value will be returned as JSON payload:

Reuse the Child Flow to Extract Attribute Values From the Post Entity Image

We’ve covered how we can extract values from the pre entity image. This same logic is applied when extracting values for the post entity image. Hence child flow will be used again, but this time we will pass the post entity image to the child flow. The resulting value will be stored in the PostImageObject variable.

Merge Pre and Post Image Objects

We won’t go over this section in detail as the concept is largely similar. The benefit of merging the PreImageObject and PostImageObject variable values into one variable is for ease of access in later flow actions. Key expressions would be:

ExpressionDescription
addProperty(variables(‘MergedImageObject’), items(‘Apply_to_Filtering_Attributes’)?[‘name’], coalesce(variables(‘PostImageObject’)?[items(‘Apply_to_Filtering_Attributes’)?[‘name’]], variables(‘PreImageObject’)?[items(‘Apply_to_Filtering_Attributes’)?[‘name’]]))Add a property to MergedImageObject with the filtering attribute name, checking first the post image value then the pre image value.
addProperty(variables(‘MergedImageObject’), outputs(‘Formatted_Value_Attribute_Name’), coalesce(variables(‘PostImageObject’)?[outputs(‘Formatted_Value_Attribute_Name’)], variables(‘PreImageObject’)?[outputs(‘Formatted_Value_Attribute_Name’)]))Add a property to MergedImageObject with the filtering attribute name + “_formattedvalue”, checking first the post image value then the pre image value.
Simple Usage Example

Nothing fancy, but to illustrate the benefit of using these variables:

  • Account Name = variables(‘MergedImageObject’)?[‘name’]
  • Modified by = variables(‘PostImageObject’)?[‘modifiedby_formattedvalue’]
  • Previous Owner = variables(‘PreImageObject’)?[‘ownerid_formattedvalue’]
  • Current Owner = variables(‘PostImageObject’)?[‘ownerid_formattedvalue’]
  • Modified On = variables(‘PostImageObject’)?[‘modifiedon_formattedvalue’]
  • Status = variables(‘MergedImageObject’)?[‘statecode_formattedvalue’]

Having these variables make it super easy to use in the flow actions that follow.

Hope you enjoyed the post, let me know your thoughts in the comments below or any of my contact channels 

About the Author:

Hi, my name is Tae Rim Han, but most people know me as Tae. I’ve worked with Microsoft Technology for more than a decade as a developer and consultant. I am currently living and working in Sydney, Australia. I love coding, working through hard problems and creating elegant solutions. In a nutshell, I’m passionate about learning, both tech and non-tech things.

My tech journey has been fascinating so far where there has never been a dull moment! That is why I decided to start a developer journal to write down things that I’ve learnt along the way and share it with others who are also passionate about what they do.

In my spare time I love spending time with my husband, drawing, cooking, bush walking and reading. Feel free to connect with me on LinkedIn.

Reference:

Han Rim, T. (2020). Working with the Remote Execution Context in Power Automate. Available at: https://taerimhan.com/working-with-the-remote-execution-context-in-power-automate/ [Accessed: 21st January 2020].

Share this on...

Rate this Post:

Share: