Archive for the ‘CRM’ Category

Dynamics CRM | Microsoft Power Apps | Legacy OData v2.0 Service removal date

November 12, 2021 Leave a comment

OData v2.0 endpoint:

  • The Organization Data Service (Also known as the OData endpoint or the REST endpoint when it was released, the Organization Data Service offers limited capabilities to only create, retrieve, update, or delete table data) is an OData v2.0 endpoint introduced with Dynamics CRM 2011.
  • The Organization Data Service was deprecated with Dynamics 365 Customer Engagement v8.0 in favor of the Web API, an OData v4.0 service.
  • Organization Data Service is planned to remove on November 11, 2022. Any code that uses the Organization Data Service should be migrated to use the Web API before that time.
  • Its recommended to Use the Microsoft Dataverse Web API.

Action Required:

  1. Use the Solution Checker to detect any JavaScript web resource code. The rule web-avoid-crm2011-service-odata should detect use in client-side code.
  2. Check any other code, including PowerShell scripts, that send requests to this endpoint: /xrmservices/2011/organizationdata.svc.
  3. Check any Power BI reports or Excel Data sources that may be using this endpoint.

Refer this link for more details.


Categories: CRM Tags: ,

Dataverse | New Text Formats | json, richtext

September 16, 2021 Leave a comment

Text in Dataverse is a data type that can store a max of 4000 characters. Text has multiple formats that instruct the UI to treat it differently.

As an example, Email is a text format tells the client to treat the contents of the field as an email. It can display the data as a link that, when clicked, launches your default email client and inserts the address in the To: field.

There are 2 new formats, json and richtext have been introduced.


  • json format will store text strings in a json format.
  • This format will not perform any validations on the correctness of the json. It simply allows you to store, view, and retrieve the content with json markup.
  • This is currently limited for use on non-SQL tables (like Data Lake).


  • richtext format will allow the use of markup tags to format your text when viewed in a compatible control.
  • By setting this value you can enable richtext for any other text or multiline text column.
  • A control is coming soon in the Canvas and Model Driven space that will be used whenever a column indicates it is richtext.

Please refer this article for more details.


Categories: CRM

Azure DevOps (ADO) | Pipeline failure | Could not get the latest source version

September 15, 2021 1 comment

I’ve created a new ADO project and configured a Pipeline to export Power Apps solution. While running the Pipeline it failed in immediately with following exception.

The pipeline is not valid. Could not get the latest source version for repository…


  • Under the ‘Get sources’ step of the Pipeline, ‘Default branch for manual and scheduled builds’ was auto selected as master.
  • However my existing Branch Name was main.
What is the difference between master and main branches:
  • In ADO, default ‘Branch Name’ used to be master until October 2020. Post that default ‘Branch Name’ changed to main.
  • This Branch name change was not taken affect in Pipelines. New Pipeline defaults the Branch Name to master which is invalid. It has to be main.
  • Refer this ADF product blog for more details.


  • In the ‘Get sources’ step of the pipeline, change the Default Branch from master to main.
  • Save and Rerun the pipeline.


Categories: Azure, CRM Tags: , , ,

Power Platform Tools | Developer Toolkit for Visual Studio 2019

September 1, 2021 4 comments

Power Platform Tools for Visual Studio supports the rapid creation, debugging, and deployment of plug-ins.

You may note that Power Platform Tools for Visual Studio is similar in appearance and function to the Developer Toolkit for Microsoft Dynamics CRM 2013.

While Power Platform Tools for Visual Studio is similar in appearance and function to the Developer Toolkit for Microsoft Dynamics CRM 2013, Power Platform Tools is a new product and completely independent of the Developer Toolkit.

Power Platform Tools is not directly compatible with any templates or projects from the Developer Toolkit and vice versa.

Steps to enable ‘Power Platform Tools’ extension in VS 2019:

  • From the Visual Studio 2019, click on ‘Extensions -> Manage Extensions’.
  • Expand the left navigation panel node Online > Visual Studio Marketplace. Search for “Power Platform Tools”, then click on ‘Download’.
  • Post Download, close all the Visual Studio instances and wait for few seconds, you would get below installer screen.
  • Click ‘Modify’ and complete the installation.
  • Post installation, open the Visual Studio and initiate ‘Create New Project’.
  • You should find ‘New Visual Studio Solution Template for Dynamics 365’ solution template.
  • Provide Project Name and click ‘Create’ which will open up the familiar ‘Developer Toolkit’.
  • After installing Power Platform Tools, you will not find any Power Platform Tools related menu items or views in the Visual Studio user interface until you create or load a Visual Studio solution that contains at least one project created from a Power Platform Tools template.

Refer Microsoft docs for detailed steps to install Power Platform Tools on Visual Studio.


Tip | Model Driven Apps | Client API | setSharedVariable and getSharedVariable

As we know Client-side scripting using JavaScript is one of the ways to apply custom business process logic for displaying data on a form in a model-driven app, In this article lets understand how to pass variables between event handlers (i.e., Different jScript functions registered as event handlers).

Lets understand this by first understanding the Form event pipeline.

Form event pipeline:

  • We can define up to 50 event handlers for each event. Each event handler is executed in the order that it is displayed in the Event Handlers section in the Events tab of the Form Properties dialog box.


  • Sets the value of a variable to be used by a handler after the current handler completes.
  • Syntax : ExecutionContextObj.setSharedVariable(key, value);
    • Ex : ExecutionContextObj.setSharedVariable(“sharedAccountName“, formContext.getAttribute(“name”).getValue());


  • Retrieves a variable set using the setSharedVariable method.
  • Syntax: var sharedVariable = ExecutionContextObj.getSharedVariable(key);
    • Xrm.Navigation.openAlertDialog({ text: ExecutionContextObj.getSharedVariable(“sharedAccountName“) });


[Step by Step] Dataverse | Connect Cloud flow with Service Principal (Application User)

August 25, 2021 4 comments

By default, Cloud flow Dataverse connectors run under the Owner (i.e., User who created the flow) context. When the flows move to different environment via solutions, connectors run under the user account who imported the Solution.

Making the flows run under interactive user accounts is not recommended as they cause confusion when we check the record’s audit for who updated the record. Its recommended to make the flow run under ‘Application User’, if the calling user can be a fixed account.

In this article lets see how to make the flow run under Application User using Connect the flow using Service Principal option.

High level design:

Following are the steps we gonna go through.

  • App registration in Azure Active Directory (AAD)
  • Create an Application User in Environment.
  • Create a Cloud Flow and connect with Application User.

App registration in Azure Active Directory (AAD)

  • Add a Secret and save the Secret.
  • Copy the Application ID and Tenant ID.
  • Refer this article for the detailed ‘App Registration’ steps.

Create an Application User in Environment

  • Click on ‘New app user’ and select ‘Business Unit’ and ‘Security Role(s)’.
  • Click on ‘Add an app’ and select the App registered in previous section.
  • You should see the ‘Application user’ listed as below.

Create a Cloud Flow and connect with Application User:

  • Connect to Maker portal and create a new Solution.
  • Click on New -> Cloud flow.
  • Click on ‘Connect with Service Principle’.
  • Provide the details captured in Azure Active Directory ‘App Registration’ section and click ‘Create’.
  • Now you should see that in ‘Connection references’ as below.
  • If you go back to the ‘Solution’, you would see a new entry ‘Connection Reference (preview)’ along with the flow.
  • With the ‘Connection Reference (preview)’, we can conveniently move flow to different environment using Solution export and import.
  • Lets proceed and complete the flow, which creates a ‘Contact’ record upon the creation of an ‘Account’.
  • Create an ‘Account’ from the ‘Customer Service Hub’ App.
  • A ‘Contact’ gets created triggered from the flow and Owner would the ‘Application User’.

  • You can use ‘Run as’ option and make the ‘Dataverse’ run under one of the highlighted User contexts.


Canvas Apps | Optimization | Quick way to find and clean unused variables

Many a times, in Canvas Apps we would have declared variables but no longer used them. In a complex App with substantial screens, its tedious to identify and clean up the unused variables.

In this article, lets learn how to identify unused variables and clean up. If you are unversed with ‘Variables’, refer this article.

On a high level, Set() is used to define Global variable and UpdateContext() or Navigate() are used to define Context variable (i.e., Scope limited to a screen).

To understand unused variables and clean better, I’ve built a simple Canvas App using below steps.

  • Create a new Canvas App from Power Apps portal.
  • On App ‘OnStart’ event, declared 4 Global variables using Set().
  • Add a new Screen with 3 buttons. As buttons Text, used the one of the global variables(i.e.,btnLabel1) declared in App ‘OnStart’. Repeated the same for other 2 buttons.
  • To understand Context variables, on “btn1’s” OnSelect declared 2 context variables using UpdateContext().
  • Now that we got both Global and Context variables, lets understand about variables in-depth.
  • Go to File -> Variables, you will find 2 tabs ‘Global’ and ‘Screen1’ (this is for Screen1 Context variables).
  • Now click on one of the Variables, and you will find 3 tabs:
    • Definitions : Statement where this variable was declared. In our case its App ‘OnStart’.
    • Uses : Where this Variable used.
    • Indirect uses :  Any control indirectly refers the variable. Lets see this in detail in next step.

  • Click on ‘Uses‘, you will find where ‘btnLabel3’ directly referred (i.e., Text of button 3).
  • To understand ‘Indirect uses‘, lets add a new Label and set the Text as “This is indirect label of a Button : ” & btn3.Text“.
  • In the above statement, ‘Button 3’ text was ‘Directly’ set to ‘btnLabel3’ variable, here new Label’s text was set to ‘Button 3’ text, which indirectly referring ‘btnLabel3’ variable.
  • Now, click on ‘Indirect uses‘ of “btnLabel3” variable and you would see the new Label’s text statement.
  • Coming back to the crux of this article, to identify a Unused variable, click on Variable and go to ‘Uses‘ tab. If its blank, you can navigate to the declaration statement from ‘Uses‘ and remove the statement.


Categories: CRM, PowerApps Tags: ,

Dataverse | Bypass Custom Business Logic

There are times when you want to be able to perform data operations without having custom business logic applied. Especially during complex data migration scenarios, we would not want our custom business logic (i.e., Sync Plug-ins/Real time Workflows) to be triggered.

The manual option to disable custom logic is,

  • We have to locate and disable the custom plug-ins. But this means that the logic will be disabled for all users while those plug-ins are disabled. It also means that you have to take care to only disable the right plug-ins and remember to re-enable them when you are done.

Now using BypassCustomPluginExecution option we can disable custom business logic programmatically.

About BypassCustomPluginExecution:

When you send requests that bypass custom business logic, all synchronous plug-ins and real-time workflows are disabled except:

  • Plug-ins which are part of the core Microsoft Dataverse system or part of a solution where Microsoft is the publisher.
  • Workflows included in a solution where Microsoft is the publisher.

There are two requirements:

  • You must send the API requests using the BypassCustomPluginExecution option.
  • The user sending the requests must have the prvBypassCustomPlugins privilege. By default, only System administrator’s have this privilege
    • The prvBypassCustomPlugins is not available to be assigned in the UI at this time. We can add a privilege to a security role using the API.

Using BypassCustomPluginExecution:

  • Web API:
    • Pass MSCRM.BypassCustomPluginExecution : true as a header in the request.
MSCRM.BypassCustomPluginExecution: true
Authorization: Bearer [REDACTED]
Content-Type: application/json
Accept: */*

  "name":"Test Account"
  • Organization Service:
    • Set BypassPluginExecution to true at the service, it will remain set for all requests sent using the service until it is set to false.
var svc = new CrmServiceClient(conn);

svc.BypassPluginExecution = true;

var account = new Entity("account")
    Attributes = {
        { "name", "Test Account" }

  • At Request class level:
    • BypassPluginExecution parameter, which is Optional, must be applied to each request individually.
    • You cannot use this with the 7 other IOrganizationService Methods, such as Create, Update, Delete.
    • You can use this method for data operations you initiate in your plug-ins.
var svc = new CrmServiceClient(conn);

var account = new Entity("account")
    Attributes = {
        { "name", "Test Account" }

var createRequest = new CreateRequest
    Target = account

createRequest.Parameters.Add("BypassCustomPluginExecution", true);


Adding the prvBypassCustomPlugins privilege to another role:

  • Because the prvBypassCustomPlugins is not available in the UI to set for different security roles, if you need to grant this privilege to another security role you must use the API.
  • The prvBypassCustomPlugins privilege has the id 148a9eaf-d0c4-4196-9852-c3a38e35f6a1 in every organization.
  • Code Snippet:
var roleId = new Guid(<id of role>);

    new Relationship("roleprivileges_association"),
    new EntityReferenceCollection {
            new EntityReference("privilege", new Guid("148a9eaf-d0c4-4196-9852-c3a38e35f6a1"))

Refer Docs article for more details.


Power Apps | Microsoft Dataverse

November 17, 2020 4 comments

Microsoft Dataverse

Common Data Service (CDS), the sophisticated and secure backbone that powers Dynamics 365 and Power Platform, has been renamed to Microsoft Dataverse

Some terminology in Microsoft Dataverse has been updated. For example, entity is now ‘Table’ and field is now ‘Column’. Learn more.

Microsoft Dataverse for Teams

Microsoft Dataverse for Teams (formerly known as Project Oakdale), a low code built-in data platform for Teams, is generally available now.

Microsoft Dataverse for Teams follows existing data governance rules established by the Power Platform and enables access control in the Teams Admin Center like any other Teams feature. Within the Teams Admin center, you can allow or block apps created by users at the individual level, group level, or org level.

Refer my article on Project Oakdale to know more.

Power BI Teams App

Licensed Microsoft Power BI users can enjoy the full capabilities of Power BI in Teams with the Power BI Teams App.

Power Automate App for Teams

Power Automate App for Teams lets you automate your Microsoft Teams activities or and connect Microsoft Teams to other apps and services.

Click here to know more on Dataverse.


Categories: CRM

Canvas Apps | Useful formulas and functions

November 15, 2020 1 comment

In this article, I am collating the useful formulas which are frequently used in Canvas Apps.

For all functions, I am going to use a Textbox control ‘txtInput’ as reference.


Validates User inputs based on predefined or custom patterns. For example, you can confirm whether the user has entered a valid email address, SSN, etc…

Validate Email:
  • IsMatch(txtInput.Text,Email)
Validate SSN:
  • IsMatch( txtInput.Text, Digit & Digit & Digit & Hyphen & Digit & Digit & Hyphen & Digit & Digit & Digit & Digit )
Validate SSN using Regular Expression (RegEx)
  • IsMatch( txtInput.Text, “\d{3}-\d{2}-\d{4}” )
Check presence of string
  • IsMatch( txtInput.Text, “hello”, Contains & IgnoreCase)
    • Check if ‘hello’ exists in the Text input.


Get Current User Email
  • User().Email
Get Current User Fullname
  • User().FullName
Get Profile Image
  • User().Image
    • Add an Image control and set ‘Image’ property with User().Image.

Date functions

  • Returns the current date as a date/time value.
  • The time portion is always midnight (i.e., 12:00:00). 
  • Returns the current date and time as a date/time value
  • Checks whether a date/time value is between midnight today and midnight tomorrow. Returns a Boolean (true or false) value.
  • Weekday(Date)
    • Returns between 1-7 and Sunday is ‘1’.
  • DateDiff(Date1.SelectedDate, Date2.SelectedDate, Days)
    • ‘Date1’ and ‘Date2’ are ‘Date Picker’ controls.


  • Notify function displays a banner message to the user at the top of the screen. The notification will remain until the user dismisses it, another notification replaces it, or the timeout expires which defaults to 10 seconds.
    • Syntax: Notify(“This is error and disappears in 2 seconds”,NotificationType.Error,2000);


  • Resets a control to its Default property value. Any user changes are discarded.
    • Syntax:
      • Reset(TextInput1); // Reset control
      • Reset(Form); // Reset Form


  • Split function breaks a text string into a table of substrings.
    • Syntax: Split( “Apples, Oranges, Bananas”, “,” )
    • Get the last word from Split results.
      • Last(Split(“Apples, Oranges, Bananas”, “,”)).Result // Returns ‘Bananas’

Error Handling

  • To display custom validation message on ‘Form’ submit, use ‘OnFailure’ event of Form and specify the message using ‘Notify’.
  • To check all validations are passed or not, use Form’s Valid property. Following is the condition to disable button until validations are passed.

Get the ‘Security Roles’ of current User (Data Verse)

// Get the User record by 'Email' and Set to 'currUser' variable.
            'User Name' = User().Email

// Read the 'Security Roles' from 'currUser' and Set it to 'userRoles' collection.
// Security roles will be assigned to 'userRoles' variable.
        First(currUser).'Security Roles (systemuserroles_association)'.Name,

Check whether logged in User has specific roles

// Option - I (Check multiple roles)
// Configure the 'Roles' you want to check in 'requiredRoles' variable.
        "System Administrator",
        "Sales Person"
// Get the Logged in user roles in to 'userRoles' variable as mentioned in above section.
// Loop through 'requiredRoles' using 'ForAll' and compare with 'userRoles'. If matched store in 'matchedRoles' variable.

                nm = Value
        ) > 0,

// Check if 'matchedRoles' count greater than 0 and set the 'doesRolesMatched' variable.
    CountRows(matchedRoles) > 0

// Option - II (Check single role)
// If User has "System Administrator" role, variable 'doesRoleMatched' will be set to true.
    "System Administrator" in (LookUp(
        'User Name' = User().Email
    ).'Security Roles (systemuserroles_association)').Name,
    Set(doesRoleMatched, true),
    Set(doesRoleMatched, false)


  • IsBlank(txtInput)
    • Checks for a blank value or an empty string.
  • Coalesce
    • Evaluates its arguments in order and returns the first value that isn’t blank or an empty string.
    • Use this function to replace a blank value or empty string with a different value but leave non-blank and non-empty string values unchanged.
  • GUID
    • GUID() – Returns a new Guid.
      • Set( NewGUID, GUID() )
    • To generate 5 new GUIDs and set to Collection
      • ClearCollect( NewGUIDs, ForAll( Sequence(5), GUID() ) )
  • Set() vs UpdateContext()
    • Both functions are used to create variables.
    • Set() – Creates a ‘Global Variable’ and can be consumed throughout entire App.
    • UpdateContext() – Creates a ‘Local Variable’ and can only be consumed in Screen.
  • Copy/Clone an existing Canvas App
    • Open Canvas App using ‘Edit’ option.
    • From the menu, select File -> Save as


Categories: CRM