Skip to content

Category: Power Platform

“Command Checker” bookmarklet

Posted in Dynamics 365, and Power Platform

Last week, I found out that Microsoft released a Command Checker for model-driven-app-ribbons – OVER 2 YEARS AGO! I totally missed that.
I especially love that it shows me the result of each single display rule and enable rule.

To enable the Command Checker as a button in the ribbon bar, you need to add the URL parameter “ribbondebug=true” to the current D365 CE URL and reload it. But who wants to remember ugly URL parameters…

javascript: (var _href = window.location.href; if (_href.includes("ribbondebug")){_href.replace("ribbondebug=false", "ribbondebug=true")} else {_href += "&ribbondebug=true"} window.location.href = _href)

Open these bookmarklet anywhere in model-driven-app, and it will reload the window with the activated Command Checker.

“Advanced Find” bookmarklet

Posted in Dynamics 365, and Power Platform

Since February 2022, Power Platform Admins can enable the “Modern advanced find in model driven apps“. After a decade of continuity, it is great to see a fresh, clean look and some new features in a unified user interface.

In case you are a CRM veteran like me and also miss the old advanced search, I have something for you.

javascript: (window.open(Xrm.Utility.getGlobalContext().getCurrentAppUrl() + "&pagetype=advancedfind"))

Open these bookmarklet anywhere in Dataverse, and it will open a new window with the classic advanced find in it.
Don’t forget to get used to the new advanced find.

“Get attribute by attribute ID” bookmarklet

Posted in Dynamics 365

Background information

Currently, I have a problem while applying a solution upgrade for our managed solution. The message in the solution history gives me the name of the attribute that blocks the uninstallation and its ID, but it did not tell me to which entity the attribute belongs.

Get attribute by attribute ID

To identify the right entity for the attribute professionally and not by trail and error, I looked into the “Query table definitions using the Web API” article on Microsoft Docs and build a browser bookmarklet for an easier use.

The “Get attribute by attribute ID” bookmarket

Copy and paste the following code as URL of a bookmark in your browser and execute it on any D365 page.

javascript:function getDet(){var r=JSON.parse(this.responseText);console.info("MetaData for Entity: " + r.LogicalName);console.dir(r);console.info("MetaData for Attribute: " + r.Attributes[0].LogicalName);console.dir(r.Attributes[0])};function getAtt(){var r=JSON.parse(this.responseText).value,etn,atn;for (let i=0; i < r.length; i++) {if (r[i].Attributes.length > 0) {Xrm.Navigation.openAlertDialog({confirmButtonLabel:"Close",text:"Entity: "+r[i].LogicalName+"\nAttribute: "+r[i].Attributes[0].LogicalName+"\n-\nOpen Browser Console for more MetaData Details (F12)",title:"Found Attribute"},{height:250,width:350});var oReq=new XMLHttpRequest();oReq.addEventListener("load", getDet);oReq.open("GET","/api/data/v9.0/EntityDefinitions(LogicalName='"+r[i].LogicalName+"')?$expand=Attributes($filter=MetadataId%20eq%20"+id+")");oReq.send();break;}}}id=prompt("Enter Attribute ID", "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");var oReq=new XMLHttpRequest();oReq.addEventListener("load", getAtt);oReq.open("GET","api/data/v9.0/EntityDefinitions()?$select=LogicalName&$expand=Attributes($select=LogicalName;$filter=MetadataId%20eq%20"+id+")");oReq.send();

You can paste the attribute ID and receive the logical name of the attribute and of its entity. On top, you can open the browser console to inspect the full output of the WebApi for the attribute.

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.

Best practices for ClickDimensions deployment

Posted in Dynamics 365, ClickDimensions, and Power Platform

Table of content

  1. Basics
  2. Deployment
  3. Customizing
  4. Transport
  5. Updates
  6. Redeployment

1. Basics

ClickDimensions is only accessible and configurable through Dynamics 365 Customer Engagement. This is achieved through CRM records (forms, templates, emails, etc.) that are linked by their GUID and the CRM instance specific ClickDimensions account key to an ClickDimensions editor/designer that stores its content in the ClickDimensions cloud infrastructure on Azure.

Like Microsoft, ClickDimensions provides its customers sandboxes and additional production instances for their Dynamics 365 CE environment.
A sandbox instance is hereby fully functional and can send out an email blast to your CRM records like any production instance. It’s not a safe playground if your test environment is a copy of the productive data.

2. Deployment

After purchase, you register for a ClickDimensions cloud instance(s) with your CRM instance(s). Afterwards, you will receive an email with a download link for a Dynamics 365 solution for each of your registered ClickDimensions instances. Make sure not to mix up them with your CRM instances, because the ClickDimensions account key fix embedded in the ClickDimensions solution. The same applies later to updates.

Create a backup solution in Dynamics 365 save ribbon customizations on account, campaign, contact, lead, list, opportunity, team and systemuser. Add only the required entities with their metadata to keep the solution as clean as possible.

If you have Dynamics 365 CE instances that will have no ClickDimensions Instance – like a development environment, you can import any of the ClickDimenions solutions to have the same customizing for all Dynamics 365 instances

3. Customizing

The CRM parts of ClickDimensions can be customized like any other CRM elements. Avoid customizing of views and form sections, they could be overwritten during an update.

Don’t forget to publish the metadata to the ClickDimensions cloud if you created fields that should be accessible through ClickDimensions.

Processes that you build on top of ClickDimensions processes, will have no influence on the ClickDimensions cloud. A campaign automation instance that has a posted form as an entry point, will still run with the same contact from the start, even if you updated it on the posted form in CRM.

4. Transport

The ClickDimensions Export and Import let you transport Domains, Email Templates, Form Fields, Landing Pages and Survey Questions.

All other configuration records must be transported manually. I prefer the XrmToolBoxDataTransporter to create records across all CRM instances. Pay attention to only transport the fields that you can edit in CRM. Exclude the CRM GUID and any other ID/Key from ClickDimensions (except for redeployment).
Web content and campaign automations must be rebuilt manually.
Check also the linked web content in email templates to prevent submissions to wrong CRM instance.

Those of you who are willing to experiment can try to capture and modify the body of the web request that is submitted when you save a web content.

5. Updates

ClickDimensions has a 4-week release cycle.
In the Release Notes, you find detailed information of what has changed and if a solution update is required to receive new features or bug fixes.
Most of the changes take place on the server, and a solution update is recommended by ClickDimensions once a quarter.

I prefer the manual update of the ClickDimensions solution, because I can determine when the system changes.
As the release cycle is really short, I advise to download the solutions for all instances at once. Otherwise, it could happen that you download different versions. Don’t forget your backup solution and the import in your CRM instances without ClickDimensions the have the same customizing over all.

During the update, you have to choose the settings that are “not recommended” by Microsoft to overwrite the existing ClickDimensions customizations.

It makes sense again to have a backup solution in with ribbon customizations from account, campaign, contact, lead, list, opportunity, team, systemuser and additional customizations on ClickDimensions entities.

ClickDimensions deployment

6. Redeployment

Make sure to have a ClickDimensions solution of the system that you overwrite and a backup of the ClickDimensions records with all attributes from that system.

The redeployed CRM instance will still try to connect to ClickDimensions environment of the source CRM.

ClickDimensions deployment


Disable all the ClickDimensions plugins, the redeployed CRM instance will still try to connect to ClickDimensions environment of the source CRM and could delete your productive data in the ClickDimensions cloud.

Delete the copied ClickDimensions records from the redeployed system. Delete also the records in the “Execute Send” table through the advanced find.

To restore the ClickDimensions records, you can import the backup of these records, with all keys and the original GUID of the records.

Reconnect the CRM instance to the correct ClickDimensions cloud instance, by importing the ClickDimensions solution from the first redeployment step.
This will restore the account key, enable the plugins, and you are able again to create new records and open the restored records in the redeployed system.