Archive

Author Archive

[Quick Tip] Canvas App | Make circular profile picture

Its a common requirement to add an Image control to Canvas and display logged-in user’s profile image using User().Image formula, as shown below.

If you run the App, you will get the ‘Image’ in a square dimensions.

Tip to make image in circular dimensions:

To make the Image in a circular dimensions, here is the tip. Set the ‘Border Radius’ as half of the Width.

For example, if the Width of the ‘Image’ control is 75, set the ‘Border Radius’ as 75%2 (i.e., 37.5).

Play the App and you should see the image in circular dimensions.

🙂

Advertisement

Get help on Microsoft.Xrm.Data.Powershell module functions

Microsoft.Xrm.Data.PowerShell module is an open source library using which you can seamlessly connect to Datavesre API from PowerShell script and carry out Create, Read, Update, and Delete (CRUD) operations.

I’ve been using Microsoft.Xrm.Data.PowerShell module in my Azure DevOps pipelines to perform custom actions.

In this article, I will show you a quick way to get the list of all available functions in Microsoft.Xrm.Data.PowerShell module and the syntax of each function using PowerShell console.

What is Microsoft.Xrm.Data.PowerShell

  • Microsoft.Xrm.Data.PowerShell is an open source library.
  • Microsoft.Xrm.Data.PowerShell builds from Microsoft.Xrm.Tooling.CrmConnector.Powershell and provides common functions to create, delete, query, and update data.
  • This library also includes helpful functions for common tasks such as publishing, and manipulating System & CRM User Settings, etc.
  • The module will function for both Dynamics CRM Online and On-Premise environments. 

Use PowerShell console to fetch Microsoft.Xrm.Data.PowerShell functions:

We will be using PowerShell console to get the list of functions and their syntax.

  • Open the ‘PowerShell’ console
Import-Module Microsoft.Xrm.Data.PowerShell
Get-Command -Module Microsoft.Xrm.Data.PowerShell

Executing the above command fetches the list of all available functions.

  • Now to get help of any particular function, use the following command
Get-Help <function-name> -detailed

For example, to know the usage and syntax of Set-CrmRecord function, command is Get-Help Set-CrmRecord -detailed

These commands could literally save ton of time while either building the function or troubleshooting the syntax errors.

🙂

Azure DevOps | Visual Studio | TF200016: The following project does not exist

We have an Azure DevOps Project by name ‘ALMAccelerator-Dev‘ and the the project has been connected to Visual Studio. We were able to Push and Pull commits with no issues.

Recently while pushing one of the commits from Visual Studio, we got an error TF200016: The following project does not exist

Lets see the reason and how we fixed the issue.

Reason and Fix:

  • Azure DevOps Project has been renamed from ‘ALMAccelerator-Dev‘ to ‘ALMAccelerator Dev‘ hence Visual studio thrown error as its still trying to connect to the Project with old name.
  • To fix this, from ‘Visual Studio’ go to ‘Git -> Manage Remotes…’.
  • Select the ‘Remotes’ from the popup and edit the ‘Remote origin’ as below.
  • In my scenario, since a space was introduced to my project name (i.e., ALMAccelerator Dev), I have added %20 as highlighted below
    • You might want to change the api url as per the new Project name.
  • Save and sync the Repo and it should work now,

🙂

Dataverse | ‘App Opener’ security role

April 4, 2023 2 comments

App Opener is a new OOB security role comes with the minimum privileges for common tasks available on all the Dataverse Environments.

Its recommended to use the App Opener role for copy and creating new roles.

App Opener is protected and cannot be updated.

The min prv apps use role, available in the Microsoft Download Center to downland will soon be retired and you must use this new predefined security role App Opener.

🙂

(Preview) Use ‘Solution checker’ in Managed Environments

 Solution checker enforcement, is a new feature in Managed Environments that gives admins much more control over the customizations in their environments.

Solution checker enforcement allows you to block or warn on solution imports with critical severity violations, as defined in the solution checker rules.

These violations can have security, performance, reliability, and deprecation impact.

Modes:

There are two modes you can choose for solution checker enforcement:

  • Block mode, solutions can only be imported if they were checked with solution checker and they contain no critical violations. Solutions containing non-critical violations won’t be blocked.
    Admins of the environment (and the recipients of the Managed Environment weekly digest emails) will receive an email with a summary of the solution quality and whether the solution was blocked or not.
  • Warn mode, solutions can be imported even if they weren’t checked with solution checker or if they contain critical violations.

After enabling, all custom solution imports will warn or block unless a valid solution checker result within the last 90 days is found.

Refer this link for more details.

🙂

[Code Snippet] Xrm.Data.Powershell | Get-CrmRecordsByFetch

In this article lets see how to execute the Get-CrmRecordsByFetch operation in PowerShell using Microsoft.Xrm.Data.PowerShell library.

What is Microsoft.Xrm.Data.PowerShell

  • The Microsoft.Xrm.Data.Powershell library is a PowerShell module that provides cmdlets for working with Microsoft Dynamics 365 and Dataverse data.
  • The library provides cmdlets for performing CRUD operations (Create, Retrieve, Update, and Delete) on entities in Dynamics 365 and Dataverse.
  • It also provides cmdlets for working with metadata, running FetchXML queries, and executing custom actions and workflows.

In this article, I will provide the code snippet for Get-CrmRecordsByFetch operation. Get-CrmRecordsByFetch operation retrieves CRM records by using FetchXML query.

Scenario:

I need to fetch ‘User’ table records, if either a ‘Domain Name’ or ‘Primary Email’ matches with the passed value.

Following is the FetchXML.

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="systemuser">
    <attribute name="systemuserid" />
    <filter type="and">
      <filter type="or">
        <condition attribute="internalemailaddress" operator="eq" value="user@email.com" />
        <condition attribute="domainname" operator="eq" value="user@uname.com" />
      </filter>
    </filter>
  </entity>
</fetch>

Now lets see how to execute the Fetchxml using Get-CrmRecordsByFetch operation.

Code Snippet:

Following code executes the FetchXML and read the response.

function Get-User-By-Email-or-DomainName{
 param(
    [Parameter()] [String] [AllowEmptyString()]$filterValue,
    [Parameter(Mandatory)] [Microsoft.Xrm.Tooling.Connector.CrmServiceClient]$conn
    )

    $matchedUser = $null
    $fetchxml = @"
    <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
      <entity name='systemuser'>
        <attribute name='systemuserid' />
        <filter type='and'>
          <filter type='or'>
            <condition attribute='internalemailaddress' operator='eq' value='$filterValue' />
            <condition attribute='domainname' operator='eq' value='$filterValue' />
          </filter>
        </filter>
      </entity>
    </fetch>
"@

    Write-Host "Request XML - "$fetchxml
    $records = Get-CrmRecordsByFetch -Fetch $fetchxml-conn $conn
    try{
        $json = ConvertTo-Json $records # Optional step to print the Response in json format
        Write-Host "Response - $json"        
        
        # Loop through the matching records and gets the first record.
        if($records -and $records.CrmRecords){  
            $matchedUser = $records.CrmRecords[0]
            # Read the column value

            $systemUserId = $matchedUser.systemuserid
        }
    }
    catch {
        Write-Host "An error occurred in Get-User-By-Email-or-DomainName: $($_.Exception.Message)"
    }

    return $matchedUser
}

:)

Xrm.Data.Powershell | Get-CrmRecordsByFetch | White space is not allowed before the string terminator.PowerShell

While executing Get-CrmRecordsByFetch operation in PowerShell using Microsoft.Xrm.Data.PowerShell library, I encountered

White space is not allowed before the string terminator.PowerShell error.

Reason:

  • Issue was with the format of ‘FetchXML’ being passed to Get-CrmRecordsByFetch operation.
  • There should not be a space before closure “@ tag.
  • Following does not work as there is space before the closure “@ tag of $fetch variable.

Fix:

  • Fix is simple, remove the space before the “@ tag of $fetch variable.
  • Following works.

Sharing this trivial Issue as it was annoying and took sometime to fix 🙂

C# | Parse Json using System.Text.Json (instead of Json.NET)

In this post lets see how to parse a complex Json content without using Json.NET library and by using the native System.Text.Json namespace.

What and why cant I use Json.NET library?

  • Json.NET (also known as Newtonsoft.Json) is a popular third-party JSON library for .NET.
  • Flexible Serialization, Better Performance, LINQ to JSON, JSON Path, and JSON Schema validation are some of the standout features of Json.NET library.
  • I was unable to utilize the Json.NET library solely due to the fact that it is a third-party tool, and we are obligated not to use it.

Scenario:

Coming to our scenario we have following json content and we need to parse and read the inputs and outputs collection from the actions array.

{
  "actions": [
    {
      "name": "Display select file dialog",
      "status": "Failed",
      "inputs": {
        "allowMultiple": {
          "localizedName": "Allow multiple selection",
          "value": "False",
          "variableName": ""
        },
        "title": {
          "localizedName": "Dialog title",
          "value": "Select the excel file to extract table from...",
          "variableName": ""
        }
      },
      "outputs": {
        "selectedFile": {
          "localizedName": "Selected file",
          "value": "",
          "variableName": "SelectedFile"
        },
        "buttonPressed": {
          "localizedName": "Button pressed",
          "value": "Cancel",
          "variableName": "ButtonPressed"
        }
      }
    },
    {
      "name": "If",
      "status": "Succeeded",
      "inputs": {
        "expression": {
          "localizedName": "Condition",
          "value": "False",
          "variableName": ""
        }
      },
      "outputs": {}
    }
  ],
  "childFlowsLogStatus": "Default"
}

C# Code Snippet:

Following is the C# code snippet , which parses the json content and flattens the inputs and outputs collection json using native System.Text.Json namespace.

using System;
using System.Text;
using System.Text.Json;

namespace ParseJson
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var jsonContent = "{\"actions\":[{\"name\":\"Display select file dialog\",\"status\":\"Failed\",\"inputs\":{\"allowMultiple\":{\"localizedName\":\"Allow multiple selection\",\"value\":\"False\",\"variableName\":\"\"},\"title\":{\"localizedName\":\"Dialog title\",\"value\":\"Select the excel file to extract table from...\",\"variableName\":\"\"}},\"outputs\":{\"selectedFile\":{\"localizedName\":\"Selected file\",\"value\":\"\",\"variableName\":\"SelectedFile\"},\"buttonPressed\":{\"localizedName\":\"Button pressed\",\"value\":\"Cancel\",\"variableName\":\"ButtonPressed\"}}},{\"name\":\"If\",\"status\":\"Succeeded\",\"inputs\":{\"expression\":{\"localizedName\":\"Condition\",\"value\":\"False\",\"variableName\":\"\"}},\"outputs\":{}}],\"childFlowsLogStatus\":\"Default\"}";

                string strInputXML = ParseInputandOutput(jsonContent, "inputs");
                string strOutputXML = ParseInputandOutput(jsonContent, "outputs");
                Console.WriteLine($"Input content : {strInputXML}");
                Console.WriteLine($"Output content : {strOutputXML}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error {ex.Message}");
            }
            finally
            {
                Console.ReadLine();
            }
        }

        private static string ParseInputandOutput(string flowContextDetails, string propertyName)
        {
            StringBuilder sbrRawText = new StringBuilder();
            JsonDocument doc = JsonDocument.Parse(flowContextDetails);
            JsonElement actions = doc.RootElement.GetProperty("actions");

            foreach (JsonElement action in actions.EnumerateArray())
            {
                if (action.GetProperty("status").GetString() == "Failed")
                {
                    JsonElement propertyNodes = action.GetProperty(propertyName);
                    sbrRawText.AppendLine(propertyNodes.ToString());
                }
            }

            return sbrRawText.ToString();
        }
    }
}

Run the console app and you will get the flattened json of inputs and outputs collection.

Hope this blog post gives the idea of how to parse json using native System.Text.Json namespace.

Categories: C# Tags:

Request a Power Apps premium license from org admins

In ‘Power Apps’ users can now request a license from their admin – directly in product.

If a user is trying to run an app that requires a license, they will see the option to ‘Request a license’, in addition to the buy a license or start a trial option (if eligible).

Once a request is submitted, a confirmation message will appear at the top of the page saying the request was successfully sent to their admin.

Read this blog post for more details.

🙂

Categories: PowerApps Tags: ,

Power automate | Child flows | ‘NestedWorkflowDoesNotContainResponseAction’ error

While running a Power automate Child Flows scenario, encountered the following exception.


NestedWorkflowDoesNotContainResponseAction
. To wait on nested workflow ‘xxx-xx-xxxx-xxxx’, it must contain a response action.

Flow Error

To explain the cause of the error and the fix, let me explain my Power automate Child Flows scenario.

  • I’ve 2 Dataverse tables Students and Enrollments.
  • Enrollments table has look up column of Students table.
  • In my flow, I receive interested students ‘EmailIds’ for enrollment in the comma separated format. I read the emails and create Enrollments records.
  • To read the email id’s and create Enrollments records, i’ve created 2 flows,
    • Parent – Enrollment Process – Triggers the child flow ‘Child – Complete Enrollment’ by passing comma separated Email Ids.
    • Child – Complete Enrollment – Reads the comma separated Email Ids passed by ‘Parent – Enrollment Process‘ flow and create rows in Enrollments table.

Following is the step by step process, to create my above Power automate Child Flows scenario.

Lets create the ‘Child flow (Child – Complete Enrollment)’ first.

Create Child flow (Child – Complete Enrollment):

As the ‘Child – Complete Enrollment flow’ reads the comma separated email id’s and creates records in Enrollment table, following are actions.

  • Create an Instant Flow (Child flow should be a Instant Flow).
  • Add 2 input parameters to read the EmailId’s passed from Parent flow.
    • InterestedEmails : Comma separated Email of interested Students to enroll.
    • UninterestedEmails : Comma separated Email of uninterested Students to enroll.
  • Use Split function with Apply to each to read the comma delimited Email ids to array.
    • Below I am splitting InterestedEmails parameter using comma(,) delimiter.
  • Now we will have array of interested Student ‘Email Ids’ after applying the Split function.
  • As a next step, we need to fetch the matching Student record by ‘Email Id’ from Dataverse, use the List Rows action.
    • We need the ‘Student’ because to create the ‘Enrollment’ record, we need to set the ‘Student’ lookup.
  • I’ve renamed the List Rows action to ‘GetStudentbyEmail’ and in ‘Filter rows’, I am passing the ‘Email Id’ from Split function.
  • ‘GetStudentbyEmail’ would return the matching ‘Student’ which will help us to create ‘Enrollment’ record.
  • So add a Add a new row action to create ‘Enrollment’ record.
    • Notice, I set the ‘Student’ lookup with ‘StudentId’ returned from previous ‘GetStudentbyEmail’ action.
  • Save the flow.

Now that we have the Child flow (Child – Complete Enrollment), lets create a Parent flow (Parent – Enrollment Process).

Create Parent flow (Parent – Enrollment Process):

Parent flow can be of any type (i.e., Automated/Instant/Scheduled). For this example, I am taking Instant flow.

  • Create an Instant flow with 2 input parameters.
  • Add a ‘Run a Child Flow‘ action and select our ‘Child – Complete Enrollment‘ flow.
  • Pass the required parameters to the ‘Child – Complete Enrollment‘ by reading parameters of ‘Parent – Enrollment Process‘.

Reason and Fix for ‘NestedWorkflowDoesNotContainResponseAction’ error:

  • If you open the ‘Flow Checker’ of the ‘Parent – Enrollment Process‘ you will notice “Update the child flow for action ‘Run_a_Child_Flow’ to end with a response action.” error.
  • The reason for the error is, Child flow must have one of the 2 following actions.
    • Respond to a Power App or flow (under the Power Apps connector).
    •  Response (on the premium HTTP request/response connector).
  • Save the ‘Child – Complete Enrollment‘ flow and ‘NestedWorkflowDoesNotContainResponseAction’ error should be fixed.