Archive

Archive for the ‘Power Platform’ Category

[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
}

:)
Advertisement

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 🙂

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.

Power Virtual Agent (PVA) | GPT | Boost conversations (preview)

In this article, I am going to give a quick demo on PVA Boost conversations GPT capability.

What is Boost conversations in PVA

  • By utilizing the boosted conversations in Power Virtual Agents, your bot can find and present information from an external source (i.e., Public facing website).
  • What is an External Source?
    • Pick a publicly accessible website, such as your primary company domain or customer support site.
    • Ensure that the site you select is accurate and up to date – the bot willl use it as the basis for its conversations.
    • Ensure the site is indexed or found by Bing
  • This feature runs on Azure OpenAI service. About OpenAI service.

Lets learn how to use Boost conversations capability.

Steps to use Boost conversations in PVA

  • Provide the details and complete the sign up.
  • In the next screen, provide the External Source website URL as the Boost conversations can find and present information from the website.
    • I’ve given ‘rajeevpentyala.com’ as the External Source.
  • Your text bot is ready to take questions with out the need of creating Topics.
  • Ask a question relevant to ‘rajeevpentyala.com’ which is our External Source and you will get answers in response as below.
  • Now, lets change the website url using ‘Change site’ option.
  • I’ve provided amazon.in as the url and clicked ‘Save’.
  • Ask about latest products and you will get response as below.
  • Try suggestions about products.

Publish the bot:
  • During this preview, you won’t be able to publish bots that have Boost conversations enabled.
  • Publish fails with You’ve boosted your conversational coverage, which is a feature that blocks publishing. Change your settings or contact your administrator to publish this bot error.
  • During the Preview of this feature you’ll need to contact Microsoft Support if you want to publish a bot that has Boost conversations enabled.

URL considerations:

There are some requirements on the type and structure of the External Source URL you use:

  • The URL can have up to two levels of depth (or “sub-paths”, indicated by forward slashes (/)). Your URL can have a trailing forward slash, and this won’t be included in the limit of two slashes.
  • Refer this link for more details.

🙂

[Beginners] Power Platform | Tenant vs Environment

Most of the beginners, gets confused between a Tenant and Environment in Power Platform. Lets understand the differences and learn how to manually fetch ‘Tenant Id’ and ‘Environment Id’.

What is Tenant:

  • A Tenant is the overall organization or instance of Power Platform that a user belongs to.
  • It can be thought of as a container for all the environments, users, and data associated with an organization.
  • A tenant has a unique domain name, such as myorganization.crm.dynamics.com.

What is an Environment:

  • Environment is a space to store, manage, and share your organization’s business data, apps, chatbots, and flows.

How an Environment is different than Tenant:

  • A Tenant is the overall organization or instance of Power Platform.
  • An Environment is a separate space within a Tenant.
  • Multiple environments can exist within a single tenant, and each environment can be customized independently of others.

How to manually fetch ‘Tenant ID’ and ‘Environment ID’:

The ‘Tenant ID’ is assigned to a tenant when it is created. It is generated by Microsoft and cannot be changed. To fetch ‘Tenant ID’ and ‘Environment ID’ in ‘Power Platform’

  • Login to Power Apps maker portal.
  • Select the desired ‘Environment’ from ‘Environment’ dropdown.
  • Select the Settings icon and click on ‘Session Details’.
  • From the ‘Power Apps session details’ popup, copy ‘Tenant ID’ and ‘Environment ID’.

🙂

[Quick Tip] Power Automate flow | Get current Environment ID

Lets learn how to fetch the current ‘Environment ID’ in Power Automate flows.

What is Environment Id:

  • In Power Platform, Environment is a space to store, manage, and share your organization’s business data, apps, chatbots, and flows.
  • Every Environment will be associated with an unique identifier.

In few scenarios, we would need ‘Environment ID’ to perform actions. Lets see how to fetch the current Environment ID in Power Automate Flow.

Power Automate Flow to fetch current Environment ID:

  • Create a ‘Manually trigger flow’ with a Compose action.
  • Write the expression workflow()[‘tags’][‘environmentName’]
  • Save and Test the flow.
  • You will find the ‘Environment ID’ in the Compose action ‘Outputs’.

😉

Pac cli | Install and launch Plugin Registration, Package Deployer and Configuration Migration tools

February 21, 2023 1 comment

Conventionally tools like Plugin Registration Tool (PRT) can be download from NuGet. Downloading and installing from NuGet is tedious because of following reasons:

  • Difficult to launch the tools. Because the downloaded PRT gets stored in your local directory, to launch the tool, you have to go that folder and look for the .exe file to open.
  • Difficult to upgrade the version. To upgrade the version of the tools, you have to download latest version form NuGet to your local storage.

Using Power Platform CLI, the tools download and launch process has been super simplified. Let me walk you through the process of installing and launching the tools using Power Platform CLI.

Lets first start with the basics.

What is Power Platform CLI

  • Microsoft Power Platform CLI is a simple, one-stop developer CLI that empowers developers and ISVs to perform various operations in Microsoft Power Platform.
  • Follow these steps to install.
  • Once you install, run pac in the command prompt and you should see screen as below.

Steps to install the tools using Power Platform CLI

Once you install the Power Platform CLI in your machine, open the Visual Studio Command Prompt (You can also use VSCode).

  • Run pac tool list command which lists the tool installation details.
  • If you notice the above screen, ‘Installed’ value is ‘No’, which means I don’t have tools installed yet.
Install/Uninstall Plugin Registration Tool (PRT):
  • Now, lets install Plugin Registration Tool (PRT). Its super simple.
  • Execute pac tool prt command. PRT tool gets installed and launched in a blink.
  • If you run the pac tool list command again, you should see the PRT installed status as Yes.
Launch the Plugin Registration Tool

Once you install the PRT to launch from the next time, you have 2 options.

  • Open the PRT App from the ‘Start’.
  • Open the Visual Studio Command Prompt and run pac tool prt command

Steps to install Package Deployer and Configuration Migration tools:

To install the Package Deployer (PD) and Configuration Migration (CMT) tools, follow the same steps we used for PRT. We just need to change the commands.

That’s how tools can be seamlessly downloaded and launched using the Power Platform CLI.

🙂

Categories: Power Platform Tags: , ,

[Step by Step] Create and call Global Custom API from Canvas App using Power Automate with Error Handling

February 15, 2023 4 comments

In this article, lets learn how to create a Custom API and trigger using Power Automate Cloud Flow along with Error Handling from a Canvas App.

What is a Custom API:

  • Using Custom APIs we can create our own APIs in Dataverse.
  • We can consolidate one or more operations into a Custom API which can called from either code or from Power Automate.
  • For example, you can create a Custom API called “OnBoardNewCustomer’, where you can have following operations.
    • Create a new ‘Account’ record.
    • Create a new ‘Appointment’ record scheduled a week from now.
    • Send an Email notification.

Now lets get started with Custom API creation. I am going to use ‘Onboard Customer’ scenario to explain the Custom API creation. I will be using 2 operation in my Custom API.

  • Create an Account record by reading ‘Name’ as input parameter.
  • Create an Appointment record for the newly created Account and schedule at 7 days from now.

Create a Custom API:

There are several ways you can create a custom API documented here. In this article, I will be taking 2 step approach.

  • Write a C# plugin class file with logic and register using Plugin Registration Tool (PRT).
  • Create a Custom API using forms from Power Apps Maker portal and link the plugin created in previous step.

Steps to create Custom API in plugin class and register using PRT:
  • Open Visual Studio and create a plug-in project as detailed in this document here.
  • Add an .snk file to the project.
  • Create a new plugin class file with logic to create Account and Customer.

  • Final code in the class file looks as below.
        public void Execute(IServiceProvider serviceProvider)
        {
            var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            if (context.MessageName.Equals("cat_onboardcustomer") && context.Stage.Equals(30))
            {
                try
                {
                    // Read the input parameter
                    string inputParamCustomerName = (string)context.InputParameters["cat_customername"];

                    if (!string.IsNullOrEmpty(inputParamCustomerName))
                    {
                        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                        IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

                        // Create Account Record
                        var entAccount = new Entity("account");
                        entAccount["name"] = inputParamCustomerName;
                        var accountId = service.Create(entAccount);

                        // Create Appointment Record
                        var entAppointment = new Entity("appointment");
                        entAppointment["subject"] = $"Meeting with Customer {inputParamCustomerName}";
                        // Set the start and end times for the entAppointment 7 days fro now
                        entAppointment["scheduledstart"] = DateTime.Now.AddDays(7).AddHours(1);
                        entAppointment["scheduledend"] = DateTime.Now.AddDays(7).AddHours(2);
                        // Set the related account for the entAppointment
                        entAppointment["regardingobjectid"] = new EntityReference("account", accountId);
                        var appointmentId = service.Create(entAppointment);
                    }
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException("An error occurred in cat_onboardcustomer.", ex);
                }
            }
        }
  • Build the project and register the plugin assembly using PRT.
  • Post registration it should look as below from PRT.

Now that we completed the step 1 of creating and registering plug-in class file. Lets proceed with step 2 where we will create a Custom API entry.

Create a Custom API using forms from Power Apps Maker portal:
  • Connect to Power Apps maker portal.
  • Create a new solution or open any existing solution.
  • Click on New -> More -> Other -> Custom API
  • It opens up a new ‘Custom API’ form and fill the details.
    • To understand the columns in depth, refer here.
    • What is important for this example are:
      • Unique Name : Unique name for the custom API. (Its cat_onboardcustomer we used in our plug-in class)
      • Name : The primary name of the custom API.
      • Plugin Type : Plugin we registered in previous section.
  • Save and Close.
  • As we need to pass a parameter to our ‘Custom API’, next add a new ‘Custom API Request Parameter’.
  • Fill the details by selecting ‘Custom API’ we created in previous step and ‘Unique Name’ as cat_customername, which we used in our plugin class.
  • Save and Close.

With this we successfully created ‘Custom API’ along with an input parameter. Lets see how to trigger API using Power Automate Cloud Flow from a Canvas App.

Steps to trigger Custom API from Canvas App:

  • Create a new Canvas App.
  • Go to Flows tab and click on ‘Create new flow’ and choose ‘Create from blank’.
  • In the flow designer, add ‘Initialize Variable’ action and rename to ‘varCustomerName’. In the ‘Value’ select ‘Ask in PowerApps’.
  • Next add Dataverse ‘Perform an unbound action‘ action which helps us to trigger our ‘Global’ custom API.
    • Select ‘Action Name’ as our Custom API name cat_onboardcustomer
    • In the cat_customername pass ‘Customer Name’ which was the variable declared in above step.
  • If you dont want exception handling, you can save the flow which can trigger the cat_onboardcustomer.

Exception Handling:

Lets learn a basic error handling. Please note that you can use ‘Scope’ for more complex scenarios but for basic exception handling following process should suffice.

  • Add another ‘Initialize Variable’ action and rename it to ‘varExceptionDetails’ and set Type as ‘String’.
  • Rename the ‘Perform an unbound action’ to ‘InvokeOnboardAPI’
  • Add a ‘Set Variable’ action ‘setExceptionDetails’ to capture the exception.
  • Select the Name as ‘ExceptionDetails‘ and click on ‘Configure run after’. (This is needed as we want this ‘setExceptionDetails’ to execute even the above ‘InvokeOnboardAPI’ action fails or timeout.
  • Select following options.
  • In the ‘Value’ select ‘Expression’ and paste following expression.
    • actions(‘InvokeOnboardAPI’)?[‘outputs’]?[‘body’]?[‘error’]
  • Finally to send the response from flow to Canvas app, add ‘Respond to a PowerApp of flow’ action and click on ‘Configure run after’, select following options and click ‘Done’.
  • and define an output variable OnboardflowResponse and set the value as ExceptionDetails.
  • Save the flow and you should see the flow in your Canvas App.
  • To trigger the flow, add a button to the screen and OnSelect write following formula.
Notify("Triggering User Onboard...");
UpdateContext({ResponseOnBoardFlow: CustomerOnboardFlow.Run("Rajeev Pentyala").onboardflowresponse});
If(
    ResponseOnBoardFlow = "Success",
    Notify("Customer onboarded successfully."),
    Notify("Error while onboarding. Details - " & ResponseOnBoardFlow)
)

  • Run the App and click the button.
  • Open Dataverse and you should see the new Account and Appointment records. You can also check the flow run history.

🙂

[Step by Step] Sign up for Power Apps Developer Plan

February 7, 2023 Leave a comment

As we know, Power Apps Plan Trial gives you the Power Apps per user plan for 30 days. This duration is meant for trying out production Power Apps applications. Once your trial expires, you can purchase a plan.

In this article lets explore the new Power Apps Developer Plan.

What is Power Apps Developer Plan:

  • Power Apps Developer Plan gives you access to the same Power Apps functionality available in paid plans (aligned with Trials), including Dataverse and Power Automate.
  • What we get is a developer environment meant for development and test use only.
  • A paid plan is required to deploy or run solutions in a production environment for production use.

Lets me explain the options to sign up for Power Apps Developer Plan.

[Option 1] Get the Developer Plan with Visual Studio Dev Essentials:

  • If you’re a Visual Studio Dev Essentials user, the Power Apps Developer Plan is included in your benefits.
  • Visit My benefits and select the Power Apps tile to sign up for the Power Apps Developer Plan.

[Option 2] Sign up for Power Apps Developer Plan:

Follow these steps to sign up for Developer Plan if you’re not a Visual Studio Dev Essentials user.

  • Connect to Developer Plan portal.
  • Click on ‘Get started free’.
  • On the next screen, you’ll need to enter either a work or school email address to proceed. Which means, you can’t sign up using your personal email account like gmail.com, live.com, yahoo.com, etc.
  • If you don’t have work of school email address already, we have an option to create one for free by using the Microsoft 365 Developer Program.
  • Join the Microsoft 365 Developer Program by clicking here.
  • Click on ‘Join now’ and sign in using your personal Microsoft account.
  • Once signed-in you will be redirected to the Dashboard as below.
  • Provide information and click ‘Next’.
  • In the last screen, provide the areas you are interested in and click on ‘Save’.
  • Now complete the subscription by clicking on ‘Set up E5 subscription’.
  • On the popup, choose one of the options. I’ve chosen ‘Instant sandbox’.
  • In the next screen provide, Admin account details and click ‘Continue’.
    • Save the ‘Admin username‘, you will need in next steps.
  • Complete the Phone Number verification and you should see following screen up on successful subscription.
    • Save the ‘Domain name‘ which you will need in next steps.
  • Sign in using the admin account, which you’ve used to join the Microsoft 365 Developer Program. Which will be {Admin username}@{Domain name}.
  • Upon successful ‘Sign In’, You will be redirected to post sign-in. Choose country and click ‘Accept’.

Important points about Power Apps Developer Plan:

  • Power Apps Developer Plan gives you access to the same Power Apps functionality available in paid plans (aligned with Trials), including Dataverse and Power Automate.
  • A paid plan is required to deploy or run solutions in a production environment for production use.
  • You should be able to export the resources from this environment to other environments using Solutions.
  • There’s a limited capacity provided because this environment is meant for development and test purposes, not for production use. The capacity limits are:
  • You can’t Create and use dataflows.
  • Dynamics 365 apps can’t be installed in a developer environment
  • Power Apps Developer plan does not include Power Automate RPA.
  • You can continue using your Power Apps Developer Plan for free as long as there’s active usage. Environments that are inactive for the last 90 days will be deleted.
  • To prevent users from creating developer environments, go to Control environment creation.

🙂

Dataverse | Solution Import Error | Environment variable value cannot be an empty string

If you are unversed with ‘Environment Variables’, first understand by going through the Environment Variables Overview.

Coming to the intent of the article, I’ve encountered Environment variable value cannot be an empty string error while importing a Solution using pac solution import command along with a Settings file.

Reason and Fix:

  • Reason for the issue is straightforward. In my settings-file , I’ve an ‘Environment Variable’ with a ‘SchemaName’ ‘cat_CompanyName’ which has a blank value in the ‘Value’ field..
  • When used this Settings file in pac solution import , import failed with Environment variable value cannot be an empty string error.
  • Fix is that, you can’t pass empty string in the ‘Value’ tag of ‘EnvironmentVariables’ in settings-file.
  • Update the Settings file by providing a value in ‘Value’ tag.
  • Retry the import and it should work now.

Note:

  • I did not face this issue, while setting a blank ‘Environment Variable Value’ from Maker portal and imported to my target environment.
  • Below is my DEV environment, where the ‘Environment Variable Value’ is blank.
  • I’ve exported the Solution and imported to target with no errors. Below is how ‘Environment Variable Value’ looks in Target environment post import.

🙂