Automating Power Automate: How to Ensure Cloud Flows Are Active After Every Pipeline Deployment
Automate Power Platform deployments by resolving connection references and activating cloud flows after import, so every environment is ready when the pipeline finishes.
Join the DZone community and get the full member experience.
Join For FreeYou've spent hours — maybe days — building and testing a Dynamics 365 Power Platform solution. Your Azure DevOps pipeline runs clean. The managed solution imports successfully into the target environment. All green.
Then the business calls. Nothing is working. The automations aren't firing.
You log into Power Automate in the target environment and find the same scene every time: every single cloud flow is turned off. Not broken. Not errored. Just off. And every connection reference is sitting there unresolved, pointing at nothing, waiting for someone to manually wire it up.
If your solution has 5 flows, that's annoying. If your solution has 50 or 100 flows, that's a half-day of manual work — clicking into each flow, assigning the connection, saving, turning it on, and moving to the next one. In a team doing frequent releases across multiple environments (Test, UAT, Production), this compounds quickly. It turns what should be a 10-minute deployment into an hours-long chore, introduces human error, and makes your pipeline feel like it only does half the job.
This is one of the most common pain points in Power Platform DevOps, and it's almost never solved cleanly out of the box. This article explains exactly why it happens and how to fix it so that flows are on, connections are wired, and the environment is fully operational the moment the pipeline finishes.
Why This Happens
Understanding the root cause is important because there are actually three separate things that go wrong, and you need to address all three.
1. Flows Are Exported in Whatever State They Were In
When a Power Platform solution is exported from a source environment, every cloud flow is embedded in the solution package in its current state. If a flow was turned off in the source environment at the time of export — even briefly, for testing or debugging — it ships in that state. When the managed solution is imported into the target environment, the flow arrives and stays off. There is no automatic activation step built into the standard import process.
2. Connection References and Actual Connections Are Different Things
This is the conceptual point that trips up most teams new to Power Platform ALM.
A connection is the actual authenticated link to a service — a specific Dataverse instance, an Outlook mailbox, a SharePoint site. Connections are environment-specific, created manually or via admin tools, and they live outside any solution. They should never be part of a solution package.
A connection reference is a pointer. It's a solution component that says "this flow uses a connection of type X." The connection reference lives inside the solution, travels with it across environments, and is what the flow binds to at runtime. The connection reference itself has no credentials — it just points to whichever actual connection in the environment is assigned to it.
The correct setup is:
-
In the source environment (DEV): The actual connections exist and are assigned to the connection references. The solution contains only the connection references, not the connections themselves.
-
In the target environment (Test, UAT, Production): The actual connections are pre-created by an administrator and given appropriate access. The service principal used by the pipeline to deploy the solution must have read/write access to these connections. When the solution is imported, the deployment settings file maps each connection reference in the solution to the correct pre-existing connection in that environment.
If this mapping is not done correctly, flows that depend on unresolved connection references will remain in a draft state after import, regardless of any other settings.
3. The Standard Import Task Does Not Activate Flows
Power Platform Build Tools for Azure DevOps includes an ActivatePlugins flag on the import task. Despite what the name implies, this activates Dataverse plugins and custom workflow activities only — it has no effect on Power Automate cloud flows. There is no built-in flag on the standard import task that activates cloud flows. This means that even a perfectly configured import, with all connection references resolved and all tokens substituted, will still leave flows in a deactivated state unless you add an explicit activation step.
Prerequisites: What Must Be in Place Before the Pipeline Runs
Before the pipeline can solve this problem end-to-end, two things must be true in every target environment.
First, the actual connections must already exist. For every service your flows connect to — Dataverse, Outlook, SharePoint, Teams, or any other connector — an administrator must have already created a connection in the target environment. These connections are not part of the solution and should never be included in the solution export. They are environmental infrastructure, created once and maintained independently of deployments.
Second, the service principal must have access. The Azure Active Directory app registration used as the service principal for the pipeline (the account that authenticates the import) must be granted access to read and write in the target environment. This includes having sufficient Dataverse security roles and, where applicable, being designated as an owner or co-owner of the connections so that the deployment settings file can map connection references to those connections during import.
Once these are in place, the pipeline can take over the rest automatically.
The Pipeline Approach
The pipeline is split into two phases: a build phase that runs against the source environment and packages the solution, and a release phase that deploys the packaged solution to each target environment.
Build Phase
The build phase exports the managed solution from the source environment and generates a DeploymentSettings.json file. This file is the key to automating connection reference mapping. It is generated by the PAC CLI from the solution ZIP and contains a structured list of every connection reference and environment variable in the solution.
Out of the box, the generated file has empty ConnectionId fields. The build pipeline post-processes this file by replacing those empty fields with placeholder tokens in the format @@token_name@@. For example, a connection reference with the logical name shared_commondataserviceforapps becomes @@shared_commondataserviceforapps@@ in the deployment settings file. The file is then published as part of the build artifact.
The critical point is that connection reference logical names often include a random trailing suffix added by the platform (e.g., shared_commondataserviceforapps_8ca1f). The build script normalizes these by stripping the suffix, so the token is deterministic and consistent across builds.
Release Phase
The release pipeline picks up the build artifact for each environment stage and runs the following sequence:
Step 1: Replace Tokens
A token replacement task reads DeploymentSettings.json and substitutes each @@token@@ with the corresponding pipeline variable for that stage. The pipeline variables for each stage hold the actual connection IDs of the pre-existing connections in that environment. For example, the Test stage has a variable shared_commondataserviceforapps with the value of the Dataverse connection ID in the Test environment. After this step, the deployment settings file is fully resolved with no remaining placeholders.
Step 2: Import Solution
The Power Platform Import Solution task imports the managed solution ZIP using the resolved DeploymentSettings.json. This wires up every connection reference to its corresponding connection in the environment automatically, with no manual intervention.
Step 3: Activate Flows
This is the step that closes the gap. A PowerShell task runs after the import and queries the Dataverse API for all cloud flows in the solution that are not currently active. It then activates each one programmatically.
The Activation Script
This PowerShell script uses the Dataverse Web API, authenticated with the same service principal credentials used by the rest of the pipeline. It queries specifically for Modern Flow entities (category eq 5) in the target solution and activates any that are in a stopped or draft state.
# Activate all Power Automate cloud flows in the solution post-import
$tenantId = "$(TenantId)"
$clientId = "$(CRMClientId)"
$clientSecret = "$(CRMClientSecret)"
$environmentUrl = "$(CRMEnvironmentUrl)"
$solutionName = "$(CRMSolutionName)"
# Obtain an OAuth token for the Dataverse API
$tokenUrl = ""
$tokenBody = @{
grant_type = "client_credentials"
client_id = $clientId
client_secret = $clientSecret
resource = $environmentUrl
}
$tokenResponse = Invoke-RestMethod -Method Post -Uri $tokenUrl -Body $tokenBody
$token = $tokenResponse.access_token
$headers = @{
"Authorization" = "Bearer $token"
"OData-MaxVersion" = "4.0"
"OData-Version" = "4.0"
"Content-Type" = "application/json"
}
$apiBase = "$environmentUrl/api/data/v9.2"
# Query for cloud flows (category = 5) in this solution that are not Active (statecode != 1)
$queryUrl = "$apiBase/workflows?`$filter=category eq 5 and statecode ne 1" +
" and _solutionid_value eq (select solutionid from solutions where uniquename eq '$solutionName')" +
"&`$select=workflowid,name,statecode,statuscode"
$flows = (Invoke-RestMethod -Uri $queryUrl -Headers $headers).value
if ($flows.Count -eq 0) {
Write-Host "All flows are already active. Nothing to do."
} else {
Write-Host "Found $($flows.Count) flow(s) to activate."
foreach ($flow in $flows) {
$patchUrl = "$apiBase/workflows($($flow.workflowid))"
$payload = @{ statecode = 1; statuscode = 2 } | ConvertTo-Json
Invoke-RestMethod -Method Patch -Uri $patchUrl -Headers $headers -Body $payload
Write-Host "Activated: $($flow.name)"
}
Write-Host "Done. $($flows.Count) flow(s) activated successfully."
}
Note on category eq 5: Power Platform stores multiple automation types in the same workflow entity. Category 0 is classic workflows, category 4 is business process flows, and category 5 is Modern Flow (Power Automate cloud flows). The filter ensures only cloud flows are touched.
Guarding Against Unresolved Connections
A common failure mode is a new connection reference being added to the solution in DEV, the build generating a new @@token@@ for it, but the corresponding pipeline variable not being added to the release stage yet. The import will succeed, but the flow that depends on that connection will remain inactive — and the activation script will fail to activate it because the connection reference is still unresolved.
To catch this early, add a validation step before the import that checks for any remaining @@token@@ placeholders in the deployment settings file and fails the pipeline immediately if any are found:
$settingsPath = "$(System.DefaultWorkingDirectory)/$(Build.DefinitionName)/$(Build.BuildNumber)/DeploymentSettings.json"
$content = Get-Content $settingsPath -Raw
$unresolved = [regex]::Matches($content, '@@[^@]+@@') | Select-Object -ExpandProperty Value
if ($unresolved.Count -gt 0) {
Write-Error "Unresolved connection tokens found in DeploymentSettings.json:`n$($unresolved -join "`n")"
Write-Error "Add the missing pipeline variables for this stage and re-run."
exit 1
}
Write-Host "All connection tokens resolved. Proceeding with import."
Failing fast here is far better than a silent partial deployment where some flows activate, and others don't.
The Result
Once this is in place, the deployment experience changes completely. A pipeline run that previously required a human to log into each target environment, open Power Automate, navigate to each flow, assign connections, and manually toggle flows on — a process that scales linearly with the number of flows — becomes fully automated.
For a solution with 100 cloud flows deploying across three environments, that might be 300 individual manual actions eliminated per release cycle. The environment is fully operational the moment the pipeline is completed. No follow-up tickets. No forgotten flows. No production incidents because someone missed one.
The key insight is that the platform gives you all the pieces — connection references for portability, deployment settings for environment-specific mapping, and the Dataverse API for programmatic activation — but it does not wire them together for you automatically. Once you do, your Power Platform deployments become as reliable and hands-off as any other enterprise application deployment.
Opinions expressed by DZone contributors are their own.
Comments