Skip to content

Category: Power Automation

How to delete a developer environment with Power Automate

Posted in Power Platform, Dynamics 365, and Power Automation

If you only understand the first and the last part of the title, you should click the button below to learn more about the “Power Apps Developer Plan” that includes a free Dataverse for developer (and for makers or course).

Normally Power Platform administrators can create, edit and delete Dataverse environments through the “Power Platform Admin Center” (https://admin.powerplatform.microsoft.com/environments), but developer environments from the “Power Apps Community Plan” differ here.

  • They can only be created through the “Power Apps Developer Plan” page at Microsoft (button above)
  • Everyone with Microsoft work or school account can create one personal development environment per tenant
  • They can not be edited (update name or URL) or deleted through the portal

How to delete a developer environment

I found out, that Nick Doelman already has perfectly described, how to delete a Power App Community Plan environment with PowerShell. Inspired by his blog post, I remembered that there is a “Power Platform for Admins” Connector for Power Automate (and Logic Apps) and I checked it out for you.

  • Open the the Maker Portal (https://make.powerapps.com) and select the default environment of your tenant on the right side of the header menu. Only there the Flow will be later reusable, because you don’t delete it with the environment it exists in.
  • Create a new instant Cloud Flow and give it a name, for example “Reset DevEnvironment”
  • Add an input parameter to the trigger action that will receive the environment ID
delete a developer environment
  • Search for the “Power Platform for Admins” connector and select it. I got the best search result by typing “PowerApp”.
the power platform for administrators connector
  • Now scroll down and select the “Delete Environment” action.
delete a developer environment with power automate
  • Select “Enter Custom Value” as environment input for the action and choose the ID that comes from the trigger action
delete a developer environment
  • Save your Flow

Usage of the flow

delete a developer environment

Now run the Flow and paste the Environment ID as parameter.

delete a developer environment

The flow run takes something between 30 and 120 seconds and ends with an 404 error, but at the end the environment has gone and you can create a new Power Apps Community Plan Environment again.

delete a developer environment

Bulk active Flows from a solution

Posted in Power Automation, Dynamics 365, and Power Platform

Scenario

We start our projects with our best practice solution and add further value over time to that solution. We also try to let benefit existing customers from the innovations and optimizations that get implemented in the solution over time, since their project has started.
Knowing our goal, you can imagine our setup. A source instance in our tenant and several target instances at different customers.
On top, some customers receive manual, an unmanaged version of the solution and other customers receive a managed version with an Azure Pipeline.

Issue

Flows can only be turned on if the user turning them on has permissions to connections being referenced by the connection reference.

Marc Schweigert: https://gist.github.com/devkeydet/f31554566b2e53ddd8e7e1db4af555a6

This causes no issues when importing manually, but as we use Application User to connect the Azure Pipeline, this ends with all Flows in the solution turned off after solution import.

Solution – Bulk active Flows

One solution would be to create a PowerShell script in the Azure Pipeline that impersonate the owner of a connection reference (Source).
I decided to create a Power Automated based solution to bulk active Flows, with an Environment Variable that contains Flows that should not be enabled automatically.

Step by step

Step 1 – Environment Variable:
Create an Environment Variable of type JSON to store the Flows that should not be activated automatically. Doing this as an Environment Variable enables you to define this per instance.

To enable our Flow to find the right Flows by name, workflowid or workflowuniqueid, the structure should be:

{
  "Flow 1": "worklowid",
  "Flow 2": "workflowidunique"
}

Step 2: The Trigger of the Flow

A managed solution only get modified when you import an update of it. Therefore, this is my trigger, filtered on my solution.

The dataverse flow trigger on table 'Solutions'.

Step 3: Some vars and const

Vars and const for the Flow.

Step 4: Get the exclusion list

I needed to put it in a compose action. Working directly with the environment variable did not work for me.

Load the exclusion list in a compose.

Step 5: Get inactive Flows from the solution

Get the inactive Flows from the solution with a fetch to bulk active flows later.

I found the FetchXml in the Dynamics Community, it was an answer from Scott Durow where he helped someone. By that way, thank you, Scott, that inspired me to my solution.

<fetch>
  <entity name="workflow">
    <attribute name="category" />
    <attribute name="name" />
    <attribute name="statecode" />
    <attribute name="workflowidunique" />
    <filter>
      <condition attribute="category" operator="eq" value="5" />
      <condition attribute="statecode" operator="eq" value="0" />
    </filter>
    <link-entity name="solutioncomponent" from="objectid" to="workflowid">
      <link-entity name="solution" from="solutionid" to="solutionid">
        <filter>
          <condition attribute="uniquename" operator="eq" value=@{outputs('Solution')} />
        </filter>
      </link-entity>
    </link-entity>
  </entity>
</fetch>

Step 6: Loop over fetched Flows

Loop to bulk active Flows.

Step 6.1 Check inside the loop if the current Flow is not excluded

Condition to excluded flows from the environment variable.
contains(string(outputs('Get_ExclusionList')), string(items('Loop_fetched_Processes_from_Solution')?['workflowid']))


contains(string(outputs('Get_ExclusionList')), string(items('Loop_fetched_Processes_from_Solution')?['workflowidunique']))


contains(string(outputs('Get_ExclusionList')), string(items('Loop_fetched_Processes_from_Solution')?['name']))

Step 6.1.1 Activate the current Flow in the TRUE path of the condition

Update the record in Dataverse to activate the flow.

Step 6.1.2 Log if an error happens after activating the current Flow

A counter and string for error logging.

Click the three dots on the “Counter++” action and choose “Configure run after”.

Open the 'run after' menu.
Configure the 'run after' option.

Step 7: Check if an error occurred, after the loop is completed

Condition to inform about errors.

Step 7.1 If an error occurred, get the URL of the CRM instance

Get the CRM URL from OData.Id.

I described how to get it in my post: Get CRM URL in Power Automate

Step 7.2 Send a notification

Send an email with Power Automate.

Let me a comment if you find this helpful or how you solved this or a similar problem.

EntitySetName Bookmarklet

Posted in Dynamics 365, Power Automation, and Power Platform

Almost six years after my last post about bookmarklets, I’m proud to present you a new bookmarklet for Dynamics 365 CE.

It can be used to retrieve the EntitySetName for for an entity (table).

In case you don’t know what the EntitySetName, here is what Microsoft writes about it.

This value is used in the resource path for this entity in the Web API. For custom entities, you can change the name of the entity set used. By default it is the same as the LogicalCollectionName.

Source: Microsoft Docs

In other words, you need when you use the WebApi or the Common Data Service (current environment) connector in PowerAutomate.

The EntitySetName Bookmarklet

Create a normal bookmark in you browser and replace its url with the following code:

javascript: etn=prompt("SchemaName?","account");var xhr=new XMLHttpRequest;xhr.open("GET","/api/data/v9.0/EntityDefinitions(LogicalName='"+etn+"')?$select=EntitySetName",!0),xhr.onload=function(t){4===xhr.readyState&&200===xhr.status&&prompt("EntitySetName:",JSON.parse(xhr.responseText).EntitySetName)},xhr.send();

You can use it at any place inside of D365 CE. You only need to write in the SchemaName of an entity (table) and it answers you with the EntitySetName from the EntityDefinitions.

Get CRM URL in Power Automate

Posted in Dynamics 365, Power Automation, and Power Platform

Sometimes you need to work with the URL of your CRM within Power Automate, for example:

  • to relate or unrelate two records with the Common Data Service (current environment) connector
    CRM URL in Power Automate
  • or writing an email with a hyperlink to a record.

If you have a multi-staged environment and you build your Flow solution aware, you don’t want to update your static URLs after each transport.

Solution

‘Recycle’ the OData Id from a previous CDS action.

CRM URL in Power Automate
  1. We need an previous CDS action that has an OData Id within its output (like shown above).
    If you have no action like this, consider to create a “List records” action which is limited to 1 by the “Top count” option.
  2. Create a “Compose” action and give it the OData_Id as input.
  3. Create an other “Compose” action and give it following expression to receive the CRM URL.
    concat(join(take(split(outputs('OData_Id'), '/'), 3), '/'), '/')
  4. Create an other “Compose” action and give it following expression to receive the OData URL.
    concat(join(take(split(outputs('OData_Id'), '/'), 6), '/'), '/')
Compose URL in Flow

How it works

  • concat(join(take(split(outputs('OData_Id'), '/'), 3), '/'), '/')
    Contains the OData Id we’ve stored in the first “Compose” action.
    "https://yourcrm.crm4.dynamics.com/api/data/v9.1/cdi_postedform(792189BA-BA04-E711-80F6-C4346BAC4DDC)"

  • concat(join(take(split(outputs('OData_Id'), '/'), 3), '/'), '/')
    Cuts the URL string in separate substring wherever a slash (‘/’) is.
    0: "https:"
    1: ""
    2: "yourcrm.crm4.dynamics.com"
    3: "api"
    4: "data"
    5: "v9.1"
    6: "cdi_postedform(792189BA-BA04-E711-80F6-C4346BAC4DDC)"

  • concat(join(take(split(outputs('OData_Id'), '/'), 3), '/'), '/')
    Merge the first 3 entries of the splitted URL to a new array.
    0: "https:"
    1: ""
    2: "yourcrm.crm4.dynamics.com"

  • concat(join(take(split(outputs('OData_Id'), '/'), 3), '/'), '/')
    Merge the new array into a string and separate the entries by a slash (‘/’).
    "https://yourcrm.crm4.dynamics.com" 

  • concat(join(take(split(outputs('OData_Id'), '/'), 3), '/'), '/')
    Create a new string with the merged URL and put a slash (‘/’) at its end.
    "https://yourcrm.crm4.dynamics.com/" 

In the same way you receive the OData URL when you “take” the first 6 elements instead of the first 3 elements.