Create Power Automate Cloud Flow Programmatically in MS Dataverse

Paul Nieuwelaar, 20 April 2021

When you create a new Power Automate Cloud Flow from within a Dataverse Solution, behind the scenes this Flow is being stored as a new row in the Process table for your Dataverse environment. If you’ve been using Dynamics 365 for a while, you’ll know this Process table is used for various types of processes in Dynamics 365, including Workflows, Business Rules, and Business Process Flows.

image

Since Cloud Flows are just a row in a table, we can interact with them using the Dataverse Web API just like any other table. This includes all the standard operations like Create, Read, and Update. As long as we have access to the Web API, like with the Common Data Service connector for Flow, or the Xrm.WebApi functions from JavaScript within Dynamics 365, we can use these to create Cloud Flows programmatically.

In order to create a Cloud Flow programmatically, we just need to add a new Process row, and make sure we’re setting all the correct columns. We can see what columns we need to be setting by creating a new Cloud Flow manually first, and then querying it to see what columns it has. For this demo, I’ve just created a super simple Flow.

image

Once we create it, we can query it through the Dataverse Web API to see what columns it has. I’m doing this with JavaScript within a Dynamics 365 form (e.g. an Account).

await Xrm.WebApi.retrieveMultipleRecords("workflow", "?$filter=name eq 'Cloud Flow I Created Manually!'");

image

Most of the columns we can ignore, but the ones of interest we need to be setting when creating a Flow are:

· Process Name (name) = the name of the Flow, whatever you want it to be

· Category (category) = Modern Flow (5)

· Xaml (xaml) = null (this is required when adding a Process from within another Cloud Flow, but you can set it to the null expression)

· Type (type) = Definition (1)

· Primary Entity (primaryentity) = "none" (the actual text has to be literally none)

· Client Data (clientdata) = The JSON string containing all the cloud flow data. Read on for how to get this.

The Client Data column is the interesting bit, as this describes what your Flow is doing, and how it is triggered. Instead of creating this from scratch, it’s easier to copy the Client Data from another Cloud Flow, like I’ve done with the one above.

The Client Data for my Cloud flow looks something like this:

{"properties" : {"connectionReferences" : {"shared_commondataserviceforapps" : {"runtimeSource" : "embedded","connection" : {"connectionReferenceLogicalName" : "mag_sharedcommondataserviceforapps_4edbe"},"api" : {"name" : "shared_commondataserviceforapps"}}},"definition" : {"$schema" : https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#","contentVersion" : "1.0.0.0","parameters" : {$connections" : {"defaultValue" : {},"type" : "Object"},"$authentication" : {"defaultValue" : {},"type":"SecureObject"}},"triggers" : {"When_a_row_is_added,_modified_or_deleted" : {"type":"OpenApiConnectionWebhook","inputs" : {"host" : {"connectionName" : "shared_commondataserviceforapps","operationId" : "SubscribeWebhookTrigger","apiId" : "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps"},"parameters" : {"subscriptionRequest/message" : 4,"subscriptionRequest/entityname" : "account","subscriptionRequest/scope" : 4,"subscriptionRequest/filteringattributes":"address1_city"},"authentication" : "@parameters('$authentication')"}}},"actions" : {"Update_a_row" : {"runAfter" : {},"type" : "OpenApiConnection","inputs" : {"host" : {"connectionName" : "shared_commondataserviceforapps","operationId" : "UpdateRecord","apiId" : "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps"},"parameters" : {"entityName" : "accounts","recordId" : "@triggerOutputs()?['body/accountid']","item/name" : "@{triggerOutputs()?['body/name']} - @{triggerOutputs()?['body/address1_city']}"},"authentication" : "@parameters('$authentication')"}}},"outputs" : {}}},"schemaVersion" : "1.0.0.0"}

This will look different depending on the types of triggers and actions you have. In my example I just have a simple ‘when a row is added, modified, or deleted’ trigger, and an ‘update a row’ action both from the Common Data Service connector. You can see in the client data where it references each of those steps, which we can modify when programmatically creating the Cloud Flow.

Finally, to create the Cloud Flow programmatically, we just need to take all those columns and values and create a new Process (workflow) row. I’ll show creating this from the Dynamics 365 JavaScript WebAPI, but it can be done from anywhere that has access to the Dataverse Web API.

image

Since it will be ‘Off’ by default, we can turn it on with a simple Update:

image

And we can now see our new Cloud Flow (currently not in any solution). You can also see I changed the address1_city to address1_line1 just to show we can update the client data before creating it:

image

That’s all there is to it. You can now create Cloud Flows programmatically or use an existing Flow as a template to help you get started.