<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kinga</title>
    <description>The latest articles on Forem by Kinga (@kkazala).</description>
    <link>https://forem.com/kkazala</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F584954%2Fb880f1b3-24fd-4878-8362-a332a824bdc7.jpg</url>
      <title>Forem: Kinga</title>
      <link>https://forem.com/kkazala</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kkazala"/>
    <language>en</language>
    <item>
      <title>XPath in Power Automate - diagrams</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Fri, 11 Jul 2025 08:50:33 +0000</pubDate>
      <link>https://forem.com/kkazala/xpath-in-power-automate-diagrams-4he7</link>
      <guid>https://forem.com/kkazala/xpath-in-power-automate-diagrams-4he7</guid>
      <description>&lt;p&gt;Visual examples available via GitHub Pages &lt;a href="https://kkazala.github.io/xpath-powerautomate/index.html" rel="noopener noreferrer"&gt;XPath in Power Automate - diagrams&lt;/a&gt; illustrate &lt;code&gt;xpath&lt;/code&gt; transformation in Power Automate, focusing on syntax, node targeting, and transformation logic.&lt;/p&gt;

&lt;p&gt;They are based on the concepts introduced in the original post &lt;a href="https://dev.to/kkazala/xpath-in-power-automate-d37"&gt;XPath in Power Automate&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Display XML Nodes
&lt;/h2&gt;

&lt;p&gt;When processing structured content in Power Automate, combining the &lt;code&gt;Select&lt;/code&gt; action with &lt;code&gt;xpath&lt;/code&gt; expressions provides a performant and scalable way to extract and reshape data.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://kkazala.github.io/xpath-powerautomate/index.html" rel="noopener noreferrer"&gt;Display XML Nodes&lt;/a&gt; page demonstrates three different ways of displaying results of xpath queries. Usage of &lt;code&gt;Apply to each&lt;/code&gt; and &lt;code&gt;Create HTML table&lt;/code&gt; is purely for demonstration purposes. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzlt6jot65cv5pfrr8mb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzlt6jot65cv5pfrr8mb.png" alt=" " width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Whenever possible, use &lt;code&gt;Select&lt;/code&gt; actions, as they have a number of advantages when compared with &lt;code&gt;Apply to each&lt;/code&gt;. They are much faster, especially when processing large volume of data, and reduce complexity in flow design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Select nodes
&lt;/h2&gt;

&lt;p&gt;"Select nodes" examples present results of &lt;code&gt;xpath&lt;/code&gt; transformations using &lt;code&gt;Apply to each&lt;/code&gt; action, with &lt;code&gt;Compose&lt;/code&gt; using simple &lt;code&gt;xml(item())&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fitw41cfe3dr33i0l2xzc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fitw41cfe3dr33i0l2xzc.png" alt=" " width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typically, the results of &lt;code&gt;xpath&lt;/code&gt; transformations would be provided as a source for &lt;code&gt;Select&lt;/code&gt; action, to aggregate necessary information&lt;/p&gt;

&lt;h2&gt;
  
  
  Select: nodes information, attributes, transformations
&lt;/h2&gt;

&lt;p&gt;These examples  are using &lt;code&gt;Select&lt;/code&gt; actions. Nodes selected using &lt;code&gt;xpath&lt;/code&gt; (&lt;code&gt;From&lt;/code&gt; property) are further transformed using &lt;code&gt;xpath&lt;/code&gt; expressions for each returned node. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rh1408r0gyq6imjrvzq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rh1408r0gyq6imjrvzq.png" alt=" " width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Pages: &lt;a href="https://kkazala.github.io/xpath-powerautomate/index.html" rel="noopener noreferrer"&gt;XPath in Power Automate - diagrams&lt;/a&gt; &lt;/p&gt;

</description>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>xpath</category>
      <category>xml</category>
    </item>
    <item>
      <title>Add-PnPApp: Unable to connect to the SharePoint Online Admin Center</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Fri, 30 May 2025 13:15:17 +0000</pubDate>
      <link>https://forem.com/kkazala/add-pnpapp-unable-to-connect-to-the-sharepoint-online-admin-center-58l5</link>
      <guid>https://forem.com/kkazala/add-pnpapp-unable-to-connect-to-the-sharepoint-online-admin-center-58l5</guid>
      <description>&lt;p&gt;Following our code freeze, I enjoyed a long moment of blissful ignorance =) &lt;/p&gt;

&lt;p&gt;But last Wednesday, I was abruptly confronted by harsh reality... My deployment pipeline failed (?!)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3d5uq19ytpal9l4r1v6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3d5uq19ytpal9l4r1v6e.png" alt="Unable to connect to the SharePoint Online Admin Center" width="711" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not you, it's M..?
&lt;/h2&gt;

&lt;p&gt;Of course I assumed I broke something. Perhaps I removed permissions that my pipeline is using?&lt;/p&gt;

&lt;p&gt;But... I tested deployment in my development environment with &lt;code&gt;Sites.FullControl.All&lt;/code&gt; for &lt;code&gt;Microsoft Graph&lt;/code&gt; and &lt;code&gt;Office 365 SharePoint Online&lt;/code&gt; APIs. Yes, &lt;code&gt;Sites.FullControl.All&lt;/code&gt;. I still got an error. &lt;/p&gt;

&lt;p&gt;And what does "admin center" have to do with deploying an app to a site-level app catalog? My guess would be... nothing (?)&lt;/p&gt;

&lt;p&gt;And then I came across the &lt;a href="https://github.com/pnp/powershell/issues/4750" rel="noopener noreferrer"&gt;[BUG] In Add-PnPApp overwrite is not working throws error The current user does not have the permission to access the App Catalog&lt;/a&gt; and realized that I'm not the only one. Moreover, it seems the command was not working 3 months ago, then got fixed a week later (💪) and 3 weeks ago another issue appeared, with the PnP PowerShell trying to access the Admin Center. It's been malfunctioning ever since. &lt;/p&gt;

&lt;h2&gt;
  
  
  I think I've had enough
&lt;/h2&gt;

&lt;p&gt;Did you know that PnP PowerShell is basically a wrapper for a set of SharePoint REST and Graph APIs? The code for the &lt;code&gt;Add-PnPAPp&lt;/code&gt; is &lt;a href="https://github.com/pnp/pnpframework/blob/dev/src/lib/PnP.Framework/ALM/AppManager.cs#L843" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All I had to do is to write my own PowerShell functions that would make the SharePoint REST API requests. &lt;/p&gt;

&lt;p&gt;You will find them here: &lt;a href="https://gist.github.com/kkazala/6b82fb11fc46f371016e2824d4fb4ffb" rel="noopener noreferrer"&gt;Gist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://gist.github.com/kkazala/6b82fb11fc46f371016e2824d4fb4ffb#file-spfx-deployapps-ps1" rel="noopener noreferrer"&gt;&lt;code&gt;SPFx-DeployApps.ps1&lt;/code&gt;&lt;/a&gt; file is called from the pipeline, from the &lt;code&gt;AzurePowerShell@5&lt;/code&gt; task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AzurePowerShell@5&lt;/span&gt;
          &lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploySPFxSolution&lt;/span&gt;
          &lt;span class="s"&gt;inputs&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;azureSubscription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{parameters.serviceConnection}}&lt;/span&gt;
            &lt;span class="na"&gt;azurePowerShellVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LatestVersion&lt;/span&gt;
            &lt;span class="na"&gt;ScriptType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FilePath&lt;/span&gt;
            &lt;span class="na"&gt;ScriptPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(scriptsDir)/SPFx-DeployApps.ps1&lt;/span&gt;
            &lt;span class="na"&gt;ScriptArguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="s"&gt;-tenantName '$(Az_TenantName)'&lt;/span&gt;
              &lt;span class="s"&gt;-siteName '$(SPO_SiteName)'&lt;/span&gt;
              &lt;span class="s"&gt;-folderPath '$(artifactsLocation)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It calls functions defined in &lt;a href="https://gist.github.com/kkazala/6b82fb11fc46f371016e2824d4fb4ffb#file-spfx-deploysolutions-ps1" rel="noopener noreferrer"&gt;&lt;code&gt;SPFX-deploysolutions.ps1&lt;/code&gt;&lt;/a&gt; to upload and deploy the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;I'm not providing &lt;code&gt;client ids&lt;/code&gt;, &lt;code&gt;secrets&lt;/code&gt;, or &lt;code&gt;certificates&lt;/code&gt;, because I'm using ServiceConnection with &lt;a href="https://dev.to/kkazala/series/26443"&gt;Workload Identity Federation&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;The Service Principal used as the Pipeline Identity has &lt;code&gt;Sites.Selected&lt;/code&gt; API Permissions on the target SharePoint site, with  &lt;code&gt;fullControl&lt;/code&gt; granted to the site to be able to "Manage Web" (=add an app). &lt;br&gt;
You may use the &lt;a href="https://gist.github.com/kkazala/6b82fb11fc46f371016e2824d4fb4ffb#file-grant-apipermissions-serviceprincipal-ps1" rel="noopener noreferrer"&gt;Grant-APIPermissions-ServicePrincipal.ps1&lt;/a&gt; to grant all the required permissions.&lt;/p&gt;

</description>
      <category>sharepoint</category>
      <category>sharepointframework</category>
      <category>pnppowershell</category>
    </item>
    <item>
      <title>Client-script in Model-driven apps: do it right from the start</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Wed, 14 May 2025 07:34:37 +0000</pubDate>
      <link>https://forem.com/kkazala/client-script-in-model-driven-apps-do-it-right-from-the-start-19c5</link>
      <guid>https://forem.com/kkazala/client-script-in-model-driven-apps-do-it-right-from-the-start-19c5</guid>
      <description>&lt;p&gt;One of the selling points of Power Platform is the "No code/low code" approach, which makes it easy for citizen developers to build apps without needing deep technical skills. &lt;br&gt;
But if you ask anyone who was around Power Platform long enough, they'll tell you that the "no code/low code" ends pretty quickly.&lt;/p&gt;

&lt;p&gt;I find it especially true when building Model-driven apps. Sure, the platform automatically generates the user interface based on the data model, and the modern UI lets app makers customize forms and views with ease. CRUD (Create, Read, Update, Delete) operations are handled by the platform, so makers can focus on what really matters. However, when it comes to adding more complex logic, things get tricky. The built-in business rules are quite limited, and for anything beyond basic functionality, app makers often need &lt;a href="https://learn.microsoft.com/en-us/power-apps/developer/model-driven-apps/client-scripting" rel="noopener noreferrer"&gt;client scripts&lt;/a&gt; (JavaScript), custom &lt;a href="https://learn.microsoft.com/en-us/power-apps/developer/component-framework/overview" rel="noopener noreferrer"&gt;PCF Components&lt;/a&gt; (TypeScript) , &lt;a href="https://learn.microsoft.com/en-us/power-apps/maker/data-platform/functions-overview" rel="noopener noreferrer"&gt;functions&lt;/a&gt; in Dataverse (PowerFx, today still in Preview), &lt;a href="https://learn.microsoft.com/en-us/power-apps/maker/data-platform/low-code-plug-ins?tabs=instant" rel="noopener noreferrer"&gt;low-code plug-ins&lt;/a&gt; in Dataverse (PowerFx. still in Preview) or even &lt;a href="https://learn.microsoft.com/en-us/power-apps/developer/data-platform/write-plug-in?tabs=pluginbase" rel="noopener noreferrer"&gt;Plug-ins&lt;/a&gt; (C#) .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This post focuses on extending forms in Model-driven apps with client script.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;If you haven't written any client scripts yet, I recommend the &lt;a href="https://learn.microsoft.com/en-us/training/modules/actions-client-script-power-platform/" rel="noopener noreferrer"&gt; Perform common actions with client script in Power Platform - Training | Microsoft Learn&lt;/a&gt; guide on performing common actions with client scripts in Power Platform. This resource will provide you with a solid foundation and practical examples.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 Remember to add .js at the end of the client script resource. This will help you with debugging.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Reference other .js files
&lt;/h3&gt;

&lt;p&gt;If you have external dependencies, such as other JS files, make sure to &lt;a href="https://learn.microsoft.com/en-us/power-apps/developer/model-driven-apps/web-resource-dependencies" rel="noopener noreferrer"&gt;configure them as dependencies&lt;/a&gt; to the web resource so they are loaded with the form.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 Web resource dependencies do not provide any control over the order in which the web resources are loaded.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Forcing refresh of your client-side script
&lt;/h3&gt;

&lt;p&gt;To ensure that the new version of your script is loaded to the user's browser, use the approach described in &lt;a href="https://dev.to/kkazala/force-refresh-of-custom-scripts-in-model-driven-1i8a"&gt;Force refresh of custom scripts in Power Platform model-driven apps&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use TypeScript instead of JavaScript
&lt;/h3&gt;

&lt;p&gt;I'm sure I don't have to convince you that TypeScript is better than JavaScript.  It offers better tooling, type safety, and catches bugs early, which is a big win when building complex apps on the Power Platform.&lt;/p&gt;

&lt;p&gt;If you're working with Dataverse and want a solid developer experience, the &lt;a href="https://marketplace.visualstudio.com/items?itemName=danish-naglekar.dataverse-devtools" rel="noopener noreferrer"&gt;Dataverse DevTools&lt;/a&gt; extension for Visual Studio Code is a great choice. It helps you set up your project quickly, connect to your environment, and generate strongly-typed TypeScript classes for tables and columns. This makes it easier to write clean, maintainable code when working with client scripts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉If you don't see the "add typescript" after installing the extension, restart Visual Studio. &lt;/p&gt;

&lt;p&gt;👉 The connection seems active even if it isn't. Always check if your scripts got deployed, or make a habit to reconnect in the morning.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Keep in mind that there are two build modes: &lt;code&gt;build-dev&lt;/code&gt; for debugging and &lt;code&gt;build&lt;/code&gt; for production deployment. When deploying production version (&lt;code&gt;build&lt;/code&gt;), all your files will be bundled into a single JavaScript file to avoid external dependencies.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 If you import just one method from a class, the entire class (including unused methods) gets included in the build. To keep the final file size smaller, it’s better to export only the functions you actually need.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Debugging
&lt;/h2&gt;

&lt;p&gt;Debugging locally can save you a lot of time since you don’t have to wait for the file to be deployed and published every time you make a change. To make this easier, check out &lt;a href="https://learn.microsoft.com/en-us/power-apps/developer/model-driven-apps/streamline-javascript-development-fiddler-autoresponder" rel="noopener noreferrer"&gt;Microsoft’s guide on using Fiddler Auto Responder&lt;/a&gt; for script web resource development in model-driven apps. &lt;/p&gt;

&lt;h3&gt;
  
  
  Build in dev mode
&lt;/h3&gt;

&lt;p&gt;Be sure to rebuild your project using the &lt;code&gt;build-dev&lt;/code&gt; mode for local testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Auto-responder working?
&lt;/h3&gt;

&lt;p&gt;Ensure that capturing is enabled. If it’s active, and the mapping is configured correctly, the file information will be displayed in green.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filf71yh5dao9v1lihu1r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filf71yh5dao9v1lihu1r.png" alt="Image description" width="674" height="42"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Clear the cache
&lt;/h3&gt;

&lt;p&gt;If your form was already open, the JavaScript might be cached. To clear it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press F12 to open DevTools&lt;/li&gt;
&lt;li&gt;Go to Application &amp;gt; Cache Storage &amp;gt; &lt;strong&gt;WebResources&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete&lt;/strong&gt; the folder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesr5u7jbc5w6nb0kpj96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesr5u7jbc5w6nb0kpj96.png" alt="Image description" width="329" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;still with DevTools open, use "Empty cache and hard refresh"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59wiv2ics35d58sdndok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59wiv2ics35d58sdndok.png" alt="Image description" width="329" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit tests
&lt;/h2&gt;

&lt;p&gt;Once your codebase becomes more stable, it's a good idea to start writing unit tests. This helps ensure your logic works as expected and makes it easier to catch bugs when making future changes.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://marketplace.visualstudio.com/items?itemName=danish-naglekar.dataverse-devtools" rel="noopener noreferrer"&gt;Dataverse DevTools&lt;/a&gt; project installs &lt;code&gt;@types/xrm&lt;/code&gt; to provide type definitions, but keep in mind that the actual XRM context isn’t available in the test environment - it’s only present when the app is running in the browser.&lt;/p&gt;

&lt;p&gt;When writing unit tests, you may choose to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mock the Xrm object manually&lt;/strong&gt;: This is a simple and lightweight approach that works well for small or straightforward apps. You'll need to manually mock every method your code calls, which can get tedious as complexity grows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use the &lt;a href="https://github.com/davidjbclark/xrm-mock" rel="noopener noreferrer"&gt;xrm-mock&lt;/a&gt; library&lt;/strong&gt;: This provides a more structured way to simulate the XRM environment. It covers many common methods, though some of them throw "Not implemented". If something’s missing, you can still use &lt;code&gt;jest.spyOn&lt;/code&gt; (or a similar method in your test framework) to mock specific return values or behaviors.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both methods have their place. Choose based on your project’s complexity and testing needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated testing
&lt;/h2&gt;

&lt;p&gt;👉 It's funny how some of the most useful tools seem buried, isn't it? One great example is the &lt;a href="https://microsoft.github.io/PowerApps-TestEngine/" rel="noopener noreferrer"&gt;Power Apps Test Engine&lt;/a&gt; - a powerful but often overlooked resource. It’s packed with tools, guides, and best practices to help you apply low-code testing effectively in your Power Apps projects. Whether you're just getting started or looking to level up your testing strategy, it's definitely worth exploring.&lt;/p&gt;

</description>
      <category>powerplatform</category>
      <category>modeldriven</category>
      <category>typescript</category>
      <category>xrm</category>
    </item>
    <item>
      <title>Business Rules vs Client Script</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Tue, 13 May 2025 13:33:20 +0000</pubDate>
      <link>https://forem.com/kkazala/business-rules-vs-client-script-6bf</link>
      <guid>https://forem.com/kkazala/business-rules-vs-client-script-6bf</guid>
      <description>&lt;p&gt;Although Microsoft recommends implementing custom logic using configuration (such as Business Rules), it quickly becomes apparent that this approach has its limitations. &lt;/p&gt;

&lt;p&gt;Business Rules &lt;strong&gt;can&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Set field values&lt;/strong&gt; and &lt;strong&gt;default&lt;/strong&gt; values (triggered only on "create"). The value can be &lt;strong&gt;static&lt;/strong&gt; or based on &lt;strong&gt;another field's value&lt;/strong&gt;, but no additional data transformations are supported (e.g. string concatenation).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lock or hide controls&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set "&lt;strong&gt;business required&lt;/strong&gt;" to either "Business required" or "Not business required," with &lt;strong&gt;no option for "Business recommended"&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Display &lt;strong&gt;error messages&lt;/strong&gt; next to specific fields.&lt;/li&gt;
&lt;li&gt;Provide &lt;strong&gt;recommendations&lt;/strong&gt;: display business rationale and, if the user accepts the recommendation, set the field's value to a static value, another field's value, or leave it empty.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Business Rules are enforced either at the entity or form level, so you don't have to worry about your script failing. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure that users have a security role that includes, at a minimum, user scope read privileges on the &lt;strong&gt;Process&lt;/strong&gt; table. Otherwise Business Rules may not be executed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Business Rules have certain &lt;strong&gt;limitations&lt;/strong&gt; that need to be considered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They cannot &lt;strong&gt;read&lt;/strong&gt; if he field is &lt;strong&gt;disabled or hidden&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;They can only be &lt;strong&gt;applied&lt;/strong&gt; to fields, &lt;strong&gt;not to grids, sections, or tabs&lt;/strong&gt;. To hide a whole section, each control within the section must be hidden separately.&lt;/li&gt;
&lt;li&gt;They do not work with &lt;strong&gt;Multi-select&lt;/strong&gt; choices 😢, unique identifier and rollup columns.&lt;/li&gt;
&lt;li&gt;They cannot retrieve related records. This must be done using client script (JavaScript) and &lt;strong&gt;Web API&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;They do not &lt;strong&gt;bubble events&lt;/strong&gt;. If a control is changed by a Business Rule, it will not trigger its own Business Rule until the form is saved (or autosaved). It will also not trigger JavaScript events.&lt;/li&gt;
&lt;li&gt;They cannot check &lt;strong&gt;user's roles&lt;/strong&gt;, or &lt;strong&gt;global settings&lt;/strong&gt; like user's preferences (e.g., language), &lt;strong&gt;organization settings, or client&lt;/strong&gt; information.&lt;/li&gt;
&lt;li&gt;There is &lt;strong&gt;no exception handling or debugging&lt;/strong&gt;. You can see which Business Rules are loaded and in which order using &lt;strong&gt;Monitor&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Only &lt;strong&gt;up to 10 if-else&lt;/strong&gt; conditions are supported in a Business Rule. According to my experience, it maximum &lt;strong&gt;9&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actions/conditions cannot be copied&lt;/strong&gt;, which requires a lot of manual effort if your form is complex. However, you can copy Business Rules.&lt;/li&gt;
&lt;li&gt;Business Rules cannot &lt;strong&gt;call JavaScript&lt;/strong&gt;, so there is no way to perform string/date operations like concatenating strings or getting timestamps.&lt;/li&gt;
&lt;li&gt;They won't fire on an editable grid when the editable grid is configured on a dashboard page. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another issue is (probably an edge) scenario that I encountered creating a demo involved creating the following two Business Rules:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F752hjbcwj9zk4sloz7ks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F752hjbcwj9zk4sloz7ks.png" alt="Image description" width="638" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n15xalilcsv0w198dw7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n15xalilcsv0w198dw7.png" alt="Image description" width="622" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which results in a "cyclical reference" error once the second business rule is activated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F42gokru00kuxy9j8jmk5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F42gokru00kuxy9j8jmk5.png" alt="Image description" width="489" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What runs first? Business rule or JavaScript?
&lt;/h2&gt;

&lt;p&gt;Let's assume you have a Business Rule, and a client-script event handler defined for the same field.&lt;/p&gt;

&lt;p&gt;JavaScript will execute first when it is attached to form events such as &lt;code&gt;onLoad&lt;/code&gt;, &lt;code&gt;onSave&lt;/code&gt;, or &lt;code&gt;onChange&lt;/code&gt;. This is because JavaScript runs on the client side and can react immediately to user interactions on the form. &lt;/p&gt;

&lt;p&gt;Business rules, on the other hand, are processed on the server side and are executed asynchronously. &lt;/p&gt;

&lt;p&gt;Fields changed by a business rule will only trigger their own Business Rules once the form is saved (or auto saved). Field changes performed by Business Rules will not trigger JavaScript &lt;code&gt;onChange&lt;/code&gt; event handler.&lt;/p&gt;

&lt;p&gt;The demo below is configured as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;F.BR&lt;/code&gt; is set by a Business Rule based on the value the a &lt;code&gt;START&lt;/code&gt; field,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;F.JS&lt;/code&gt; is set by an &lt;code&gt;onChange&lt;/code&gt; event handler associated with the &lt;code&gt;START&lt;/code&gt; field,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;F.BR.BR&lt;/code&gt; is set by a Business Rule based on the &lt;code&gt;F.BR&lt;/code&gt; field's value,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;F.BR.JS&lt;/code&gt; is set by an &lt;code&gt;onChange&lt;/code&gt; event handler associated with the &lt;code&gt;F.BR&lt;/code&gt; field,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;F.JS.BR&lt;/code&gt; is set by a Business Rule based on the &lt;code&gt;F.JS&lt;/code&gt; field's vlaue&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;F.JS.JS&lt;/code&gt; is set by an &lt;code&gt;onChange&lt;/code&gt; event handler associated with the &lt;code&gt;F.JS&lt;/code&gt; field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljnu6ss6kn6p1ztxhypf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljnu6ss6kn6p1ztxhypf.png" alt="Image description" width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0t39plfiegml7jtumfqq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0t39plfiegml7jtumfqq.gif" alt="Image description" width="1000" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fields changed by an &lt;code&gt;onChange&lt;/code&gt; event handler will trigger Business Rules and client-side event handlers. Remember to call &lt;code&gt;fireOnChange()&lt;/code&gt;, though.&lt;/li&gt;
&lt;li&gt;fields changed using Business Rules will not trigger client-side event handlers, and their own Business Rules will be executed once the form is saved. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Business rules execution sequence
&lt;/h2&gt;

&lt;p&gt;The execution order of business rules can be managed based on their &lt;strong&gt;activation sequence&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;To change the execution order: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deactivate all business rules.&lt;/li&gt;
&lt;li&gt;activate them one by one in the desired order. The first activated rule will run first, and the last activated rule will run last. Yupp... 😶&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you find the sequence then?&lt;/p&gt;

&lt;p&gt;You can use &lt;a href="https://learn.microsoft.com/en-us/power-apps/maker/monitor-modelapps" rel="noopener noreferrer"&gt;Live Monitor&lt;/a&gt; to detect the execution order. Play your app, and filter the entries using  &lt;code&gt;Operation equals FormEvents.businessrule&lt;/code&gt;. Open the &lt;strong&gt;FormEvents.businessrule&lt;/strong&gt; side panel and expand &lt;code&gt;data&lt;/code&gt;, &lt;code&gt;FormEvents&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For business rules activated in alphabetical order:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjcqlm0v7n401xdkoo1z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjcqlm0v7n401xdkoo1z.png" alt="Image description" width="482" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And once the rules are activate in descending order:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyva4z6mitc3ldvc35ztm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyva4z6mitc3ldvc35ztm.png" alt="Image description" width="498" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, remember that they execute asynchronously. Even if you change the execution order, you cannot count on the first business rule completing before the next one is triggered.&lt;/p&gt;

</description>
      <category>powerplatform</category>
      <category>modeldriven</category>
      <category>businessrules</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Business Process Flow With Custom Buttons</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Thu, 17 Apr 2025 13:20:39 +0000</pubDate>
      <link>https://forem.com/kkazala/business-process-flow-with-custom-buttons-3o71</link>
      <guid>https://forem.com/kkazala/business-process-flow-with-custom-buttons-3o71</guid>
      <description>&lt;p&gt;&lt;strong&gt;TLDR&lt;/strong&gt;: I made a &lt;strong&gt;reusable script for model-driven apps&lt;/strong&gt; that allows you to &lt;strong&gt;use custom buttons to move between business process flow stages&lt;/strong&gt;. It also &lt;strong&gt;prevents&lt;/strong&gt; user from using the &lt;strong&gt;default buttons&lt;/strong&gt;. The unmanaged solution is here: &lt;a href="https://github.com/kkazala/Business-Process-Flow-With-Custom-Buttons/releases" rel="noopener noreferrer"&gt;GitHub/Releases&lt;/a&gt; and the code is here: &lt;a href="https://github.com/kkazala/Business-Process-Flow-With-Custom-Buttons" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business Process Flow&lt;/strong&gt; in Power Platform guides app users through a sequence of predefined steps, ensuring that all the required fields are completed before progressing to the next stage.&lt;/p&gt;

&lt;p&gt;The buttons allowing users to move to the next stage are.. well... &lt;strong&gt;well hidden&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falge8887h8mznp7r7d9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falge8887h8mznp7r7d9k.png" alt="bpf buttons" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Good choice? Bad choice?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexs4f6jmvd80zki3clbt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexs4f6jmvd80zki3clbt.png" alt="user experience" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perhaps when working with a small group of users, it's manageable to show each person where to find the &lt;strong&gt;Next Stage&lt;/strong&gt; / &lt;strong&gt;Previous Stage&lt;/strong&gt; buttons. But when you're building an app intended for company-wide use, it becomes an obstacle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom buttons
&lt;/h2&gt;

&lt;p&gt;That's why it's common to add custom buttons to the toolbar (and to &lt;a href="https://www.xrmtoolbox.com/plugins/RibbonWorkbench2016/" rel="noopener noreferrer"&gt;declutter&lt;/a&gt; it while you're at it).&lt;/p&gt;

&lt;p&gt;These custom buttons can be shown or hidden (or enabled/disabled) based on specific conditions, such as whether the user has a certain role, the form is completed, or an approver has made a decision.&lt;/p&gt;

&lt;p&gt;You may also use these buttons to trigger additional logic, like updating the "Status Reason" field, showing notifications, or even preventing the user from moving to the next stage based on custom conditions.&lt;/p&gt;

&lt;p&gt;However, if you take this approach, make sure the &lt;strong&gt;default buttons&lt;/strong&gt; cannot be used to bypass this additional logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disabling / hiding BPF buttons?
&lt;/h3&gt;

&lt;p&gt;It is of course possible to manipulate the DOM of your model-driven apps, but... it's &lt;a href="https://learn.microsoft.com/en-us/power-apps/developer/model-driven-apps/clientapi/reference" rel="noopener noreferrer"&gt;not supported&lt;/a&gt;. The supported approach is to use the &lt;a href="https://learn.microsoft.com/en-us/power-apps/developer/model-driven-apps/clientapi/reference/events/onprestagechange" rel="noopener noreferrer"&gt;onPreStageChange&lt;/a&gt; event to call the &lt;code&gt;executionContext.getEventArgs().preventDefault()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This event runs before the stage changes - whether triggered by a user clicking one of the standard Business Process Flow buttons (i.e. &lt;strong&gt;Next Stage&lt;/strong&gt;, &lt;strong&gt;Previous Stage&lt;/strong&gt;, or &lt;strong&gt;Set Active Stage&lt;/strong&gt;), or by programmatic calls such as &lt;code&gt;formContext.data.process.moveNext&lt;/code&gt;, &lt;code&gt;formContext.data.process.movePrevious&lt;/code&gt;, or &lt;code&gt;formContext.data.process.setActiveStage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This means that when implementing custom logic, we need to make sure the custom buttons are allowed to perform the stage transition, while blocking all other requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gotcha: the "Finish" action
&lt;/h3&gt;

&lt;p&gt;Unfortunately, according to my tests, calling &lt;code&gt;preventDefault()&lt;/code&gt; in either the &lt;code&gt;OnPreStageChange&lt;/code&gt; or the &lt;code&gt;OnProcessStatusChange&lt;/code&gt; will not stop the &lt;strong&gt;Finish&lt;/strong&gt; action in Business Process Flow.&lt;/p&gt;

&lt;p&gt;I worked around this issue by adding an additional, final stage and immediately completing the flow as soon as that stage is reached.&lt;br&gt;
This stage wouldn’t be used by users - it is there to help finalize the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;I made a "plan minimum" solution that covers the most important parts of the process. It consists of two custom buttons and a reusable script that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ensures that only custom buttons can move business process flow between stages,&lt;/li&gt;
&lt;li&gt;updates the record's &lt;strong&gt;Status Reason&lt;/strong&gt; and &lt;strong&gt;Status&lt;/strong&gt; fields according to the current stage,&lt;/li&gt;
&lt;li&gt;calls &lt;strong&gt;rollback&lt;/strong&gt; function if required,&lt;/li&gt;
&lt;li&gt;displays notifications,&lt;/li&gt;
&lt;li&gt;automatically &lt;strong&gt;finalizes the last stage&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;restarts&lt;/strong&gt; the business process flow if &lt;strong&gt;Previous Stage&lt;/strong&gt; button is clicked in &lt;strong&gt;Finalized&lt;/strong&gt; stgae&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Move to the next stage
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjkgfwwcw03rruwjt32y4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjkgfwwcw03rruwjt32y4.gif" alt="Move Next" width="600" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Move to the previous stage
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feebec63scfzvj4s61w6v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feebec63scfzvj4s61w6v.gif" alt="Move Previou" width="600" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This logic is supported by a client-side script used by the form and the custom buttons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the form's &lt;code&gt;OnLoad&lt;/code&gt;, an event handler is added for the &lt;code&gt;onPreStageChange&lt;/code&gt; event.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;onPreStageChange&lt;/code&gt; event handler ensures the request came from the custom buttons. Otherwise the navigation is cancelled using &lt;code&gt;executionContext.getEventArgs().preventDefault()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The custom buttons set a &lt;code&gt;isCustomButton&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; to make sure the move to the stage will be allowed. The variable is saved in the browser's &lt;strong&gt;local cache&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The custom buttons handle any additional logic (e.g. set record's fields) and move to the next/previous stage. In case of errors they call rollback functions. Finally, they reset the  &lt;code&gt;isCustomButton&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The business process flow is finished by completing the process and setting the record to &lt;strong&gt;Inactive&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;During process restart, the record is re-activated and the business process flow is moved back to the previous stage.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code supports both scenarios: with and without automatic completion of the final stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;In order to see this demo in action, download the  packaged solution from &lt;a href="https://github.com/kkazala/Business-Process-Flow-With-Custom-Buttons/releases" rel="noopener noreferrer"&gt;Github&lt;/a&gt; and import it to your Power Platform Environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;If you'd like to use this script in your own solution, the source code is also on &lt;a href="https://github.com/kkazala/Business-Process-Flow-With-Custom-Buttons" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. It's &lt;code&gt;Typescript&lt;/code&gt;, you will need - &lt;a href="https://github.com/Power-Maverick/DataverseDevTools-VSCode" rel="noopener noreferrer"&gt;Dataverse DevTools&lt;/a&gt;&lt;/p&gt;

</description>
      <category>powerplatform</category>
      <category>powerapps</category>
      <category>businessprocessflow</category>
      <category>modeldriven</category>
    </item>
    <item>
      <title>Get SharePoint location for Dataverse record</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Wed, 26 Feb 2025 09:13:20 +0000</pubDate>
      <link>https://forem.com/kkazala/get-sharepoint-location-for-dataverse-record-fdc</link>
      <guid>https://forem.com/kkazala/get-sharepoint-location-for-dataverse-record-fdc</guid>
      <description>&lt;p&gt;SharePoint document management for Dataverse offers numerous &lt;a href="https://ludovicperrichon.com/synchronise-documents-in-between-dataverse-and-sharepoint" rel="noopener noreferrer"&gt;advantages&lt;/a&gt;. But while accessing documents and their locations via a model-driven Power Platform app is straightforward, retrieving them using Power Automate can be quite challenging.&lt;/p&gt;

&lt;p&gt;If you need to archive attached documents in a different location or send them all via email as attachments, you must first locate the SharePoint Online (SPO) library and folder associated with the entity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get SharePoint location for record
&lt;/h2&gt;

&lt;p&gt;The "Get SharePoint location for record" flow uses the &lt;strong&gt;Document Location&lt;/strong&gt; Dataverse table to gather details about the attachment location, such as the &lt;code&gt;Relative URL&lt;/code&gt; (folder name) and &lt;code&gt;sharepointdocumentlocationid&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Once SharePoint integration with Dataverse is configured for an entity, an entry pointing to the library in SharePoint is added. Note that the library name is based on the table logical name:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foq2gombgxiy1fy9tdvz8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foq2gombgxiy1fy9tdvz8.png" alt="document location" width="800" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only when the first document is attached to a record, additional entry is created in the &lt;strong&gt;Document Location&lt;/strong&gt; table , referencing a folder in the SharePoint library. The folder name is based on the record properties:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8yejvt5sv9fjv1cj13n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8yejvt5sv9fjv1cj13n.png" alt="document location for a record" width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above values are not enough to access the SharePoint location where the documents are stored, but can be used in a call to the &lt;a href="https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/reference/retrieveabsoluteandsitecollectionurl?view=dataverse-latest" rel="noopener noreferrer"&gt;RetrieveAbsoluteAndSiteCollectionUrl()&lt;/a&gt; Dataverse function to obtain the SharePoint Online site collection URL:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/api/data/v9.2/sharepointdocumentlocations(sharepointdocumentlocationid)/Microsoft.Dynamics.CRM.RetrieveAbsoluteAndSiteCollectionUrl()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The flow then executes a series of SharePoint REST api calls  to obtain a full set of information, like&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;parameter name&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;th&gt;example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tenant_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the URL of the tenant's root site; also used as a hostname when retrieving SPO site &lt;a href="https://learn.microsoft.com/en-us/graph/api/site-get?view=graph-rest-1.0&amp;amp;tabs=http#example-1-get-a-site-using-the-site-id" rel="noopener noreferrer"&gt;using GUID&lt;/a&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;contoso.sharepoint.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;site_url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The URL of the current SharePoint site, as defined in the &lt;code&gt;site URL&lt;/code&gt; parameter.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://contoso.sharepoint.com/sites/XYZ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;site_title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Title of the current SPO site&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Project XYZ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;site_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;id&lt;/code&gt; of the current SPO site in a &lt;code&gt;guid&lt;/code&gt; format.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;web_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;id&lt;/code&gt; of the current SPO web object in a &lt;code&gt;guid&lt;/code&gt; format.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;library_absolute_url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The full URL of the library.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://contoso.sharepoint.com/sites/XYZ/idapps_externalcloudservice&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;library_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;RootFolder&lt;/code&gt;. Used in the URL, is generated automatically and cannot be changed by users. It can be changed with PowerShell.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;idapps_externalcloudservice&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;library_title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The title of the library. This property can be changed by the user.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;The Archive Library&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;library_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Library's id in a &lt;code&gt;guid&lt;/code&gt; format&lt;/td&gt;
&lt;td&gt;&lt;code&gt;zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;library_drive_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Used by Graph API when referencing libraries.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b!S3SdNSBmTUGa4v5ffh_rslLJssoXH4xEuShkEO-uxKg9bblUMeoaTbQC5t69DJ-x&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;folder_absolute_url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;absolute url of a SPO library folder associated with the current teams channel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://contoso.sharepoint.com/sites/XYZ/idapps_externalcloudservice/test01_5437302CBC7A4D96AFD9BDFDAF15EF7F&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;folder_display_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;display name of the folder; white spaces are not encoded&lt;/td&gt;
&lt;td&gt;&lt;code&gt;test01_5437302CBC7A4D96AFD9BDFDAF15EF7F&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;folder_drive_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;driveItem Id&lt;/code&gt; for the folder. Can be used in MS Graph API &lt;a href="https://learn.microsoft.com/en-us/graph/api/driveitem-get" rel="noopener noreferrer"&gt;Get driveItem&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;01JEVXUVBDVF6ZMUFRM5B34EGLOEDAUF5B&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;folder_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SPO list item id. Can be used in SharePoint REST API, or MS Graph API &lt;a href="https://learn.microsoft.com/en-us/graph/api/listitem-get" rel="noopener noreferrer"&gt;Get listItem&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;15&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;error_message&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The error message if any of the actions failed, or empty string.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{"Error":"..."}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;success&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You may download the solution with Power Automate workflow including the above examples from &lt;a href="https://github.com/kkazala/Power-Automate-Utils" rel="noopener noreferrer"&gt;Power Automate Utils&lt;/a&gt; GitHub repo.&lt;/p&gt;

</description>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>dataverse</category>
    </item>
    <item>
      <title>Ever created a multi-lingual model-driven app, and had to add automation accessing user’s input? In the correct language, that is? If yes, you know it ain’t trivial :) Now you can use my Power Automate workflow to speed up your work.</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Tue, 25 Feb 2025 12:02:31 +0000</pubDate>
      <link>https://forem.com/kkazala/ever-created-a-multi-lingual-model-driven-app-and-had-to-add-automation-accessing-users-input-in-45km</link>
      <guid>https://forem.com/kkazala/ever-created-a-multi-lingual-model-driven-app-and-had-to-add-automation-accessing-users-input-in-45km</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/kkazala" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F584954%2Fb880f1b3-24fd-4878-8362-a332a824bdc7.jpg" alt="kkazala"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/kkazala/get-localized-choice-values-for-dataverse-record-4nln" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Get Localized choice values for Dataverse record&lt;/h2&gt;
      &lt;h3&gt;Kinga ・ Feb 25&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#powerplatform&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#powerautomate&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#dataverse&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#powerapps&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>dataverse</category>
      <category>powerapps</category>
    </item>
    <item>
      <title>Get Localized choice values for Dataverse record</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Tue, 25 Feb 2025 11:00:31 +0000</pubDate>
      <link>https://forem.com/kkazala/get-localized-choice-values-for-dataverse-record-4nln</link>
      <guid>https://forem.com/kkazala/get-localized-choice-values-for-dataverse-record-4nln</guid>
      <description>&lt;p&gt;Model-driven applications offer excellent support for building multilingual applications. Translations for UI elements and entity configurations can be easily provided using an Excel file, and the application adapts to the user's selected language through the Personalization settings (see &lt;a href="https://learn.microsoft.com/en-us/power-apps/user/set-personal-options#languages-tab-option" rel="noopener noreferrer"&gt;Languages tab options&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;When accessing record information through Power Automate, choice field values are presented as numerical codes rather than their display names. To obtain the choice display names in the user's language, these numerical values must be retrieved using tools like Power Automate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Localized choice values for record
&lt;/h2&gt;

&lt;p&gt;The "Utils - Get Localized choice values for record" workflow retrieves definitions of choice and multi-choice fields in a Dataverse table, providing numerical values and labels for each choice in a specified language. It can be used either as a child workflow or as a standalone flow, and  accepts the following &lt;strong&gt;parameters&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Table name&lt;/td&gt;
&lt;td&gt;The  logical name of dataverse entity, as defined in &lt;em&gt;Properties / Advanced options / Logical name&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lcid&lt;/td&gt;
&lt;td&gt;LCID code of a language, e.g. 1033 for English. Consider saving the language used by the user when a record is created. You may retrieve the language code using JavaScript: &lt;code&gt;Xrm.Utility.getGlobalContext().userSettings.languageId&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lcid fallback&lt;/td&gt;
&lt;td&gt;LCID code of language used as a fallback, in case the primary language is not detected. Use the default language of your environment.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The definitions of choice columns are retrieved using "Invoke an HTTP request" action, calling the following endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;https://org0api.crm17.dynamics.com/api/data/v9.2/EntityDefinitions(LogicalName='ENTITY_NAME')/Attributes/Microsoft.Dynamics.CRM.PicklistAttributeMetadata&lt;/code&gt; request for single-choice, and &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;https://org0api.crm17.dynamics.com/api/data/v9.2/EntityDefinitions(LogicalName='ENTITY_NAME')/Attributes/Microsoft.Dynamics.CRM.MultiSelectPicklistAttributeMetadata&lt;/code&gt; request for multi-choice fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: The "&lt;a href="https://learn.microsoft.com/en-us/connectors/webcontents/" rel="noopener noreferrer"&gt;HTTP with Microsoft Entra ID (preauthorized)&lt;/a&gt;" connector operates through a Microsoft 1st party trusted application. This application includes preauthorization for various Microsoft services and there is no need for administrators to explicitly grant consent for actions to be executed by the application on behalf of the user.&lt;br&gt;
Microsoft also released a new version of the connector, the "&lt;a href="https://learn.microsoft.com/en-us/connectors/webcontentsv2/" rel="noopener noreferrer"&gt;HTTP With Microsoft Entra ID&lt;/a&gt;", allowing administrators to grant discrete consent.&lt;/p&gt;

&lt;p&gt;The reason for using the  "HTTP with Microsoft Entra ID (preauthorized)" connector in this workflow is to ensure it works immediately once configured, and no additional action must be executed by the administrators.&lt;/p&gt;

&lt;p&gt;Update the workflow to use the "HTTP With Microsoft Entra ID" connector, if required.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The flow &lt;strong&gt;returns the following values&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Results&lt;/td&gt;
&lt;td&gt;JSON object with the following structure:   &lt;code&gt;[{"LogicalName":"fieldName","Options":[{"Value":339870000,"Label":""}]}]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error message&lt;/td&gt;
&lt;td&gt;Empty, if success. Otherwise error message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Success&lt;/td&gt;
&lt;td&gt;"True" or "False"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Importing solution
&lt;/h2&gt;

&lt;p&gt;When importing a solution, you will need to provide a connection reference to your Power Platform Environment. Ensure that the connection is created using the URL of your Power Platform Environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04ja4jo7q0tm89bfv3gj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04ja4jo7q0tm89bfv3gj.png" alt="Creating new connection" width="592" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The value of "URL of the request"  does not include a host name. The request URL will be created by combining the URL specified in the referenced connection with the API endpoint defined in the "URL of the request" field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlp0jvn2a2aw000bnnoq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlp0jvn2a2aw000bnnoq.png" alt="Image description" width="613" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the flow
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Get Localized choice values - test&lt;/strong&gt; flow provides an example on how to use the results returned by the &lt;strong&gt;Get Localized choice values&lt;/strong&gt; flow.&lt;/p&gt;

&lt;p&gt;To speed up the retrieval of the localized label, the results from the child flow are converted into an &lt;code&gt;XML&lt;/code&gt; object, and an &lt;code&gt;xpath&lt;/code&gt; expression is used to quickly extract the correct value. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;sxPathQuery&lt;/code&gt; variable is set to the following expression:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;//arr[LogicalName="{fieldName}"]/Options[Value={fieldValue}]/Label&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;{fieldName}&lt;/code&gt; and &lt;code&gt;{fieldValue}&lt;/code&gt; tokens are replaced by a field logical name and a numerical value, and used in the &lt;code&gt;xpath()&lt;/code&gt; expression, e.g.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;xpath(outputs('Compose:_Json_to_Xml'), concat('string(', replace(replace(variables('sxPathQuery'), '{fieldName}', 'kk_targetgroup'), '{fieldValue}', '339870000'), ')'))&lt;/code&gt;, or &lt;/p&gt;

&lt;p&gt;&lt;code&gt;xpath(outputs('Compose:_Json_to_Xml'), concat('string(', replace(replace(variables('sxPathQuery'), '{fieldName}', 'kk_country1'), '{fieldValue}', '756'), ')'))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When building real-life solution, you would define the &lt;code&gt;fieldValues&lt;/code&gt; based on the record's properties.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwfjfuorip80ds1c2bsv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwfjfuorip80ds1c2bsv.png" alt="Image description" width="800" height="890"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may download the solution with Power Automate workflow including the above examples from &lt;a href="https://github.com/kkazala/Power-Automate-Utils" rel="noopener noreferrer"&gt;Power Automate Utils&lt;/a&gt; GitHub repo.&lt;/p&gt;

</description>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>dataverse</category>
      <category>powerapps</category>
    </item>
    <item>
      <title>XPath in Power Automate - cheat sheet</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Mon, 17 Feb 2025 13:32:50 +0000</pubDate>
      <link>https://forem.com/kkazala/xpath-in-power-automate-d37</link>
      <guid>https://forem.com/kkazala/xpath-in-power-automate-d37</guid>
      <description>&lt;p&gt;While Power Automate documentation does not explicitly state the XPath version supported by the  &lt;a href="https://learn.microsoft.com/en-us/azure/logic-apps/workflow-definition-language-functions-reference#xpath" rel="noopener noreferrer"&gt;xPath()&lt;/a&gt; function, there are sources that confirm Power Automate supports &lt;strong&gt;XPath 1.0&lt;/strong&gt;. Sources like... community discussions, or failed tests when using XPath 2.0 😉 &lt;/p&gt;

&lt;p&gt;For the XPath reference, including supported syntax and functions, see &lt;a href="https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-3.5/ms256115(v=vs.90)" rel="noopener noreferrer"&gt;XPath Reference&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  the bookstore
&lt;/h2&gt;

&lt;p&gt;Most of the examples I found for using &lt;code&gt;xpath&lt;/code&gt; in Power Automate cover the very basic example of the &lt;a href="https://www.w3schools.com/xml/xpath_nodes.asp" rel="noopener noreferrer"&gt;bookstore&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Let's extend the example with additional books and chapter information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;bookstore&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;book&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Harry Potter&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;author&amp;gt;&lt;/span&gt;J K. Rowling&lt;span class="nt"&gt;&amp;lt;/author&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;year&amp;gt;&lt;/span&gt;2005&lt;span class="nt"&gt;&amp;lt;/year&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;price&lt;/span&gt; &lt;span class="na"&gt;currency=&lt;/span&gt;&lt;span class="s"&gt;"USD"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;29.99&lt;span class="nt"&gt;&amp;lt;/price&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;info&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;chapters&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;chapter&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;The Boy Who Lived&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;page&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/page&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Introduction to Harry Potter's early life.&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/chapter&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;chapter&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;The Vanishing Glass&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;page&amp;gt;&lt;/span&gt;15&lt;span class="nt"&gt;&amp;lt;/page&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Harry's encounter with a snake at the zoo.&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/chapter&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/chapters&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/info&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/book&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;book&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"de"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Der Hobbit&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;author&amp;gt;&lt;/span&gt;J.R.R. Tolkien&lt;span class="nt"&gt;&amp;lt;/author&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;year&amp;gt;&lt;/span&gt;1937&lt;span class="nt"&gt;&amp;lt;/year&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;price&lt;/span&gt; &lt;span class="na"&gt;currency=&lt;/span&gt;&lt;span class="s"&gt;"USD"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;19.99&lt;span class="nt"&gt;&amp;lt;/price&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;info&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;chapters&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;chapter&lt;/span&gt; &lt;span class="na"&gt;lcid=&lt;/span&gt;&lt;span class="s"&gt;"1031"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Eine unerwartete Party&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;page&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/page&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Bilbo Beutlin trifft die Zwerge.&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/chapter&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;chapter&lt;/span&gt; &lt;span class="na"&gt;lcid=&lt;/span&gt;&lt;span class="s"&gt;"1031"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Gebratenes Hammelfleisch&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;page&amp;gt;&lt;/span&gt;35&lt;span class="nt"&gt;&amp;lt;/page&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Die Zwerge begegnen Trollen.&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/chapter&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/chapters&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/info&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/book&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;book&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;1984&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;author&amp;gt;&lt;/span&gt;George Orwell&lt;span class="nt"&gt;&amp;lt;/author&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;year&amp;gt;&lt;/span&gt;1949&lt;span class="nt"&gt;&amp;lt;/year&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;price&lt;/span&gt; &lt;span class="na"&gt;currency=&lt;/span&gt;&lt;span class="s"&gt;"USD"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;14.99&lt;span class="nt"&gt;&amp;lt;/price&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;info&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;chapters&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;chapter&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;The Principles of Newspeak&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;page&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/page&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Introduction to the language of Oceania.&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/chapter&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;chapter&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;War is Peace&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;page&amp;gt;&lt;/span&gt;50&lt;span class="nt"&gt;&amp;lt;/page&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Explanation of the Party's slogans.&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/chapter&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/chapters&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/info&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/book&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/bookstore&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important!&lt;/strong&gt; Remember to parse the string to &lt;strong&gt;xml object&lt;/strong&gt; using &lt;code&gt;xml()&lt;/code&gt; function. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn84pq01xaepa8ncrkbuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn84pq01xaepa8ncrkbuw.png" alt=" " width="614" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Selecting Nodes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;xPath expression&lt;/th&gt;
&lt;th&gt;Result &lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xpath(variables('oBookstoreXml'),'//book/*')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;all direct descendants of 'book' nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xpath(variables('oBookstoreXml'),'//book/*[@*]')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;all direct descendants of 'book' nodes, which have at least one attribute of any kind&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xpath(variables('oBookstoreXml'),'//book[title[@lang="en"]]')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;all  'book' nodes where title has parameter lang='en&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xpath(variables('oBookstoreXml'),'//book/*[self::title or self::author]')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;all title and author elements of all book nodes &lt;sup&gt;*&lt;/sup&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;sup&gt;*&lt;/sup&gt; The &lt;code&gt;|&lt;/code&gt; operator, used for for selecting several paths, is not supported in xPath 1.0. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  XPath functions
&lt;/h2&gt;

&lt;p&gt;I'm using &lt;strong&gt;Select&lt;/strong&gt; action in all the examples. &lt;/p&gt;

&lt;p&gt;For a list of supported XPath functions, see &lt;a href="https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-3.5/ms256138(v=vs.90)" rel="noopener noreferrer"&gt;XPath Functions&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 1
&lt;/h3&gt;

&lt;p&gt;Select all direct descendants of 'book' nodes and read nodes information. This example used the following XPath functions: &lt;code&gt;name()&lt;/code&gt;, &lt;code&gt;string()&lt;/code&gt;, &lt;code&gt;count()&lt;/code&gt;, &lt;code&gt;concat()&lt;/code&gt;, &lt;code&gt;position()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlzouzypmh0s1gfgekf5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlzouzypmh0s1gfgekf5.png" alt=" " width="615" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From&lt;/strong&gt;: &lt;code&gt;xpath(variables('oBookstoreXml'),'//book/*')&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Map&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;expression&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;nodeName&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), 'name(/*)')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nodeValueAsString&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), 'string(/*)')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chapterCount&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), 'count(//chapter)')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chapterInformation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), 'concat("This node has ",count(//chapter), " chapter child nodes")')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nodePosition&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), 'position()')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Results
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodeName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodeValueAsString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Harry Potter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chapterCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chapterInformation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This node has 0 chapter child nodes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodePosition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodeName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodeValueAsString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"J K. Rowling"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chapterCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chapterInformation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This node has 0 chapter child nodes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodePosition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//....&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodeName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodeValueAsString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      The Boy Who Lived&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      1&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      Introduction to Harry Potter's early life.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      The Vanishing Glass&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      15&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      Harry's encounter with a snake at the zoo.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chapterCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chapterInformation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This node has 2 chapter child nodes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodePosition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;position()&lt;/code&gt; function returns &lt;code&gt;1&lt;/code&gt; for each node, because the &lt;code&gt;xpath&lt;/code&gt; expressions in the &lt;code&gt;Map&lt;/code&gt; section only have access to the chunk returned by the &lt;code&gt;From&lt;/code&gt; query. &lt;/p&gt;

&lt;p&gt;Some string functions, .e.g. &lt;code&gt;upper-case()&lt;/code&gt;, would throw an error because they are not supported in XPath 1.0.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example 2
&lt;/h3&gt;

&lt;p&gt;Select all direct descendants of 'book' nodes, which have at least one attribute of any kind. This example focuses on working with attributes: filtering based on their presence and accessing their values&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4lwxqq9gyjmiqsmkkj5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4lwxqq9gyjmiqsmkkj5.png" alt=" " width="609" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From&lt;/strong&gt;: &lt;code&gt;xpath(variables('oBookstoreXml'),'//book/*[@*]')&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Map&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;expression&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;nodeName&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), 'name(/*)')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;attributeLang&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), '//@lang')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;attributeLangValue&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), 'string(//@lang)')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;anyAttribute&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), '//@*')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Results
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodeName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attributeLang"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"lang=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attributeLangValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"anyAttribute"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"lang=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Example 3
&lt;/h3&gt;

&lt;p&gt;Select all 'book' nodes where title has parameter lang='en', perform more complex transformations to retrieve results as string, array or a JSON object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2x4ws5qnqda0lt0cayc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2x4ws5qnqda0lt0cayc.png" alt=" " width="608" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From&lt;/strong&gt;: &lt;code&gt;xpath(variables('oBookstoreXml'),'//book/*[@*]')&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Map&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;expression&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;titleAsArray&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), '//title/text()')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chapterAsArray&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), '//chapter/name/text()')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;titlesAsString&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), 'string(//title)')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chapterAsString&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), 'string(//chapter/name)')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chaptersAfterPage10AsArray&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), '//chapter[page&amp;gt;10]/name/text()')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chaptersAndPages&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xpath(item(), '//chapter/*[self::name or self::page]/text()')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;titleAndChaptersAsJSON&lt;/td&gt;
&lt;td&gt;&lt;code&gt;json(concat('{"title":"',xpath(item(), string(//title)'),'","chapters":',xpath(item(), '//chapter/name/text()'),'}'))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Results
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"titleAsArray"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Harry Potter"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chapterAsArray"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Boy Who Lived"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Vanishing Glass"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"titlesAsString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Harry Potter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chapterAsString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The Boy Who Lived"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chaptersAfterPage10AsArray"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Vanishing Glass"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chaptersAndPages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Boy Who Lived"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Vanishing Glass"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"15"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"titleAndChaptersAsJSON"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Harry Potter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"chapters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"The Boy Who Lived"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"The Vanishing Glass"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;string()&lt;/code&gt; function converts nodes to strings, while &lt;code&gt;/text()&lt;/code&gt; is a node test that selects text nodes directly.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;xpath(item(), '//chapter/*[self::name or self::page]/text()')&lt;/code&gt; expression selects multiple paths in a way supported by XPath 1.0.&lt;/p&gt;

&lt;p&gt;The xPath expression used by &lt;strong&gt;titleAndChaptersAsJSON&lt;/strong&gt; is a bit more involved and is using both, Power Automate and XPath functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"title":"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string(//title)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;","chapters":&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//chapter/name/text()&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;json()&lt;/code&gt; function allows us to return an object. the &lt;code&gt;concat()&lt;/code&gt; function generates string representing the object. Both of these functions are Power Automate functions.&lt;/p&gt;

&lt;p&gt;The value returned as &lt;code&gt;title&lt;/code&gt; is retrieved using &lt;code&gt;string(//title)&lt;/code&gt; XPath expression ensuring that the returned value is a &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The chapters list is retrieved using &lt;code&gt;//chapter/name/text()&lt;/code&gt; XPath expression, returning a list of string values.&lt;/p&gt;

&lt;h4&gt;
  
  
  What didn't work.
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;xpath(item(),'//book/concat(title/text(), " - ", author/text())')&lt;/code&gt; expression would be useful in transforming XML to an object with a simplified structure. Unfortunately, XPath 1.0 does not support the &lt;code&gt;concat&lt;/code&gt; function directly within the path expression.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond XML
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;xpath()&lt;/code&gt; is an incredibly useful and powerful function, that can speed up content transformations. And its application goes beyond to parsing XML files. Whenever the &lt;code&gt;Select&lt;/code&gt; action is not enough, and I want to avoid using &lt;code&gt;Apply to each&lt;/code&gt;, I transform JSON to XML and use &lt;code&gt;xPath()&lt;/code&gt; for more power 🚀🚀🚀 &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7oz027is5mzvv7hii59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7oz027is5mzvv7hii59.png" alt=" " width="610" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Value&lt;/strong&gt;: &lt;code&gt;xml(json(concat('{ "root": { "arr": ',variables('jsonResponse'), '}}')))&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are unsure when to use &lt;code&gt;Select&lt;/code&gt; vs &lt;code&gt;Apply to each&lt;/code&gt; action in your workflows, see &lt;a href="https://medium.com/@greenlightza/streamlining-your-power-automate-flows-with-the-select-action-39036dea6a57" rel="noopener noreferrer"&gt;Streamlining your Power Automate Flows with the Select Action&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You may download the solution with Power Automate workflow including the above examples from &lt;a href="https://github.com/kkazala/Power-Automate-Utils" rel="noopener noreferrer"&gt;Power Automate Utils&lt;/a&gt; GitHub repo.&lt;/p&gt;

&lt;p&gt;Stay tuned for my next example, showing the sheer power of &lt;code&gt;Select&lt;/code&gt; and &lt;code&gt;xPath&lt;/code&gt; working together.&lt;/p&gt;

</description>
      <category>powerautomate</category>
      <category>xml</category>
      <category>xpath</category>
      <category>powerplatform</category>
    </item>
    <item>
      <title>My posts by technology</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Sun, 05 Jan 2025 14:36:47 +0000</pubDate>
      <link>https://forem.com/kkazala/my-posts-by-technology-oeb</link>
      <guid>https://forem.com/kkazala/my-posts-by-technology-oeb</guid>
      <description>&lt;h2&gt;
  
  
  Azure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CI/CD
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/change-management-in-infrastructure-as-a-code-iac-32kn"&gt;Change Management in Infrastructure as a Code (IaC)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/access-microsoft-365-resources-from-custom-on-premise-application-5he9"&gt;Access Microsoft 365 resources from custom on premise application - setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/defaultazurecredential-with-certificate-based-authentication-3l1"&gt;DefaultAzureCredential with certificate-based authentication: how to make it work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/rbac-for-exchange-online-mailboxes-1one"&gt;RBAC for Exchange Online Mailboxes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/azure-functions-pnpcore-managed-identity-3-4dfc"&gt;Azure Functions + PnP.Core + Managed Identity=💙&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Development
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/beyond-microsoft-graph-postman-collection-4o4b"&gt;Beyond Microsoft Graph - Postman collection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/event-hub-replication-tasks-with-logic-apps-2aje"&gt;Event Hub Replication Tasks with Logic Apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/apim-json-schema-validation-done-easy-39na"&gt;APIM JSON Schema Validation done easy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/display-page-views-per-calendar-week-6gm"&gt;Application Insights: Display Heatmap of Page Views per calendar week&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Azure DevOps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CI/CD
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/change-management-in-infrastructure-as-a-code-iac-32kn"&gt;Change Management in Infrastructure as a Code (IaC)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/convert-to-workload-identity-federation-347a"&gt;Convert to workload identity federation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/deploy-spfx-app-using-pipelines-workload-identity-federation-5fhi"&gt;Deploy SPFx app using pipeline's Workload Identity federation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/azure-devops-pipeline-with-workload-identity-federation-2gpj"&gt;Azure DevOps Pipeline: no secrets, no certificates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/cicd-48f0"&gt;CI/CD for Automating SP Migration with ShareGate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Not-so-random issues
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/azure-devops-and-the-term-install-module-is-not-recognized-issue-30ck"&gt;Azure DevOps and "The term 'Install-Module' is not recognized" issue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/azure-devops-pipelines-shallow-fetch-1-is-now-default-4656"&gt;Azure DevOps pipelines shallow fetch =1 is now default&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Power Platform
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/power-platform-cost-estimates-3oga"&gt;Power Platform cost optimization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/license-calculator-kan"&gt;Power Apps License calculator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/lets-talk-money-1040"&gt;Let's talk money&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/what-makes-a-solution-premium-2l8n"&gt;What makes a solution "Premium"&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Development
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/create-group-event-in-power-automate-without-a-premium-license-4n6c"&gt;Invoke an HTTP request without a premium license&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.toInvoke%20an%20HTTP%20request%20without%20a%20premium%20license:%20connectors%20summary"&gt;Invoke an HTTP request without a premium license: connectors summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/calling-dataverse-web-api-functions-i9a"&gt;Calling Dataverse Web API functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/power-platform-extensibility-options-5cog"&gt;Power Platform extensibility options, summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/force-refresh-of-custom-scripts-in-model-driven-1i8a"&gt;Force refresh of custom scripts in Power Platform model-driven apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/dax-in-power-bi-getting-started-quickly-clj"&gt;DAX in Power BI- getting started... quickly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/power-query-data-transformations-getting-started-quickly-528i"&gt;Power Query Data transformations - getting started... quickly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/beyond-microsoft-graph-postman-collection-4o4b"&gt;Beyond Microsoft Graph - Postman collection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Utils
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/data-source-environment-variables-in-power-automate-actions-3mo5"&gt;Data Source Environment Variables in Power Automate actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/get-sharepoint-library-info-from-teams-context-1cbj"&gt;Get SharePoint library info from Teams context&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  SharePoint Development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/extortion-pack-4k8d"&gt;Extortion Pack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/sharepoint-solutions-as-a-spyware-667"&gt;SharePoint solutions as a spyware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/making-sharepoint-online-even-more-secure-3le1"&gt;Making SharePoint Online even more secure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CI/CD
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/deploy-spfx-app-using-pipelines-workload-identity-federation-5fhi"&gt;Deploy SPFx app using pipeline's Workload Identity federation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/azure-functions-pnp-powershell-managed-identity-and-sharepoint-online-2ih5"&gt;Azure Functions, PnP PowerShell, Managed Identity and SharePoint Online&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Development
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/spyon-pnpsp-select-and-filter-3ap4"&gt;jest.SpyOn @pnp/sp select() and filter()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/mock-localized-strings-in-spfx-solutions-42p3"&gt;Mock localized strings in SPFx solutions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/use-gettheme-in-spfx-workbench-19kn"&gt;Get correct theme colors in SPFx workbench&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/set-properties-for-spfx-application-customizer-46ep"&gt;Set properties for/from SPFx Application Customizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/spfx-project-managed-with-rush-a-very-quick-start-1oca"&gt;SPFx project managed with Rush: a Very Quick Start&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/few-things-i-wish-i-knew-before-starting-with-spfx-development-hlf"&gt;SPFx v1.13+ development: do it right from the start&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/panel-for-listview-command-set-sharepoint-online-4hp8"&gt;Panel for ListView Command Set (SharePoint Online)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/debugging-spfx-113-solutions-11cd"&gt;Debugging SPFx 1.13+ solutions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/why-rush-38di"&gt;Why Rush?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/spfx-project-managed-with-rush-a-very-quick-start-1oca"&gt;SPFx project managed with Rush: a Very Quick Start&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/sharepoint-migration-with-sharegate-powershell-4h19"&gt;SharePoint Migration with ShareGate PowerShell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hacked by...
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/hacked-by-postman-37kj"&gt;Hacked by… Postman?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/extortion-pack-4k8d"&gt;Extortion Pack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/sharepoint-solutions-as-a-spyware-667"&gt;SharePoint solutions as a spyware&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  PowerShell
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkazala/importexcel-and-conditional-formatting-109l"&gt;ImportExcel and Conditional Formatting&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>cicd</category>
      <category>powerplatform</category>
      <category>microsoft365</category>
    </item>
    <item>
      <title>Get SharePoint library info from Teams context</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Sun, 05 Jan 2025 14:12:06 +0000</pubDate>
      <link>https://forem.com/kkazala/get-sharepoint-library-info-from-teams-context-1cbj</link>
      <guid>https://forem.com/kkazala/get-sharepoint-library-info-from-teams-context-1cbj</guid>
      <description>&lt;p&gt;Integration between Power Apps and MS Teams allows creating context-aware applications, that access information stored for example in the SharePoint site connected to the team. &lt;/p&gt;

&lt;h2&gt;
  
  
  Embedding vs integrating
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/power-apps/teams/embed-teams-app" rel="noopener noreferrer"&gt;Embedding&lt;/a&gt; Power Apps canvas apps is different from &lt;a href="https://learn.microsoft.com/en-us/power-apps/teams/create-apps-overview" rel="noopener noreferrer"&gt;creating&lt;/a&gt; Canvas Apps in MS Teams. &lt;/p&gt;

&lt;p&gt;A Canvas App &lt;strong&gt;created in Teams&lt;/strong&gt; can only be edited using Power Apps app in MS teams. &lt;br&gt;
The environment is &lt;strong&gt;not&lt;/strong&gt; displayed in &lt;a href="https://make.powerapps.com/" rel="noopener noreferrer"&gt;https://make.powerapps.com/&lt;/a&gt;, but can be found using &lt;a href="https://make.powerautomate.com/" rel="noopener noreferrer"&gt;https://make.powerautomate.com/&lt;/a&gt;. This is useful when you need to export solution.👈 Still, you won't be able to edit this app via browser. &lt;br&gt;
The app has access to a &lt;a href="https://learn.microsoft.com/en-us/power-apps/teams/use-teams-integration-object" rel="noopener noreferrer"&gt;Teams integration object&lt;/a&gt;, which provides context information, for example team id and group  id, and channel id.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h36eivq7j80alslqi14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h36eivq7j80alslqi14.png" alt="Image description" width="577" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embedded&lt;/strong&gt; Canvas App, on the other hand, is a standalone Canvas App, added to MS Teams. &lt;/p&gt;

&lt;p&gt;Embedding Canvas Apps in MS Teams, available since March 2020, gives an app access to the team's &lt;a href="https://learn.microsoft.com/en-us/power-apps/teams/embed-teams-app#use-context-from-teams" rel="noopener noreferrer"&gt;context&lt;/a&gt; information using the &lt;code&gt;Param('parameterName')&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxplw29p6eoxt5voq6pt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxplw29p6eoxt5voq6pt.png" alt="Image description" width="800" height="142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The team Id parameter
&lt;/h2&gt;

&lt;p&gt;Sadly... the id returned by &lt;code&gt;teamId&lt;/code&gt; parameter is not a team's &lt;code&gt;guid&lt;/code&gt;, but an &lt;code&gt;internalId&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The best explanation of these &lt;code&gt;internalIds&lt;/code&gt; can be found in &lt;a href="https://stackoverflow.com/questions/66491929/is-there-any-microsoft-api-to-get-the-group-id-from-channel-id" rel="noopener noreferrer"&gt;stackoverflow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9rrvujo5q9fkg6s6pqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9rrvujo5q9fkg6s6pqw.png" alt="stackoverflow answer" width="671" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I find it very unfortunate. &lt;br&gt;
The internal id cannot be used with either the Teams Power Automate actions, or the MS Graph API. &lt;br&gt;
Calling the &lt;code&gt;https://graph.microsoft.com/v1.0/teams?$select=id,internalId&lt;/code&gt; returns &lt;code&gt;null&lt;/code&gt; for the &lt;code&gt;internalId&lt;/code&gt;. The only way of retrieving the &lt;code&gt;guid&lt;/code&gt; is indeed retrieving all the teams the user has access to, and for each of them, retrieving the &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;internalId&lt;/code&gt; values. &lt;br&gt;
In terms of solution design, this seems like an &lt;strong&gt;anti pattern&lt;/strong&gt;...&lt;/p&gt;

&lt;p&gt;Moreover, the licensing document states that the M365 licenses provide &lt;em&gt;"limited usage rights"&lt;/em&gt; to Power Platform, allowing users to extend the M365 services in order to support business processes. But finding the team's guid requires using &lt;strong&gt;Premium connector&lt;/strong&gt; because the &lt;code&gt;Send a Microsoft Graph HTTP request&lt;/code&gt; action does not support &lt;code&gt;https://graph.microsoft.com/v1.0/teams?$select= id,internalId&lt;/code&gt; query.&lt;/p&gt;

&lt;p&gt;So dissapointing...&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetching &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;driveId&lt;/code&gt;, &lt;code&gt;webUrl&lt;/code&gt;, etc.
&lt;/h2&gt;

&lt;p&gt;Nevertheless... I decided to build a flow that retrieves all the guids, ids, names and paths that might be useful in building Power Platform solutions.&lt;/p&gt;

&lt;p&gt;Depending on which Power Automate action you are using, you will need to know the target location's &lt;code&gt;URL&lt;/code&gt;, &lt;code&gt;guid&lt;/code&gt;, &lt;code&gt;driveId&lt;/code&gt; or list &lt;code&gt;title&lt;/code&gt;. I briefly described this topic in my previous post: &lt;a href="https://dev.to/kkazala/data-source-environment-variables-in-power-automate-actions-3mo5"&gt;Data Source Environment Variables in Power Automate actions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Retrieving these values based on the team and channel &lt;code&gt;internalId&lt;/code&gt; requires the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;get &lt;code&gt;guid&lt;/code&gt;s of all teams the user has access to and for each of them, fetch the &lt;code&gt;internalId&lt;/code&gt; property. If the &lt;code&gt;internalId&lt;/code&gt; is equal to &lt;code&gt;teamId&lt;/code&gt; provided by the MS Teams context, this is the team you are looking for. the &lt;code&gt;guid&lt;/code&gt; will be used to access team information with MS Graph.
&lt;em&gt;Unfortunately, the &lt;code&gt;internalId&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt; when retrieving all teams with &lt;code&gt;https://graph.microsoft.com/v1.0/teams?$select=id,internalId&lt;/code&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get SharePoint folder information for the Teams channel, using the &lt;code&gt;guid&lt;/code&gt; retrieved in the previous step, and the &lt;code&gt;channelId&lt;/code&gt; from team's context. The &lt;code&gt;https://graph.microsoft.com/v1.0/teams/{teamGuid}/channels/{channelId}/filesFolder?$select=id,name,parentReference&lt;/code&gt; query returns &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;parentReference&lt;/code&gt; properties, which are used by &lt;code&gt;drives&lt;/code&gt; API in the next step.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyi5lnrsa4s60dxukyv0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyi5lnrsa4s60dxukyv0u.png" alt="results step 1" width="800" height="162"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get SharePoint folder information by calling &lt;code&gt;https://graph.microsoft.com/v1.0/drives/{driveId}/items/{id}/listItem?$select=id,webUrl,parentReference&lt;/code&gt;. This query returns &lt;code&gt;folder id&lt;/code&gt; (integer), &lt;code&gt;absolute URL&lt;/code&gt; and a reference to a SharePoint site used by the channel. The &lt;code&gt;parentReference/siteId&lt;/code&gt; returns &lt;code&gt;tenantName,SiteId,WebId&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rhdiim29bxhe3nioz65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rhdiim29bxhe3nioz65.png" alt="results step 2" width="800" height="154"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get library information using &lt;code&gt;https://graph.microsoft.com/v1.0/drives/{driveId}/list?$select=id,webUrl,name,displayName,parentReference&lt;/code&gt;. This query returns library information: &lt;code&gt;display name&lt;/code&gt;, &lt;code&gt;internal name&lt;/code&gt; which is used as part of the url, &lt;code&gt;library guid&lt;/code&gt; and &lt;code&gt;absolute URL&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6fjqy5c2hrsv23mu6vh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6fjqy5c2hrsv23mu6vh.png" alt="results step 3" width="800" height="152"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get site information using &lt;code&gt;https://graph.microsoft.com/v1.0/sites/{siteId}?$select=name,weburl,displayName&lt;/code&gt; &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q3qra621a79guyz6jgl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q3qra621a79guyz6jgl.png" alt="results step 4" width="800" height="122"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;The output may be used in a parent Power Automate flow, to access library and folder used to store channel's documents.&lt;/p&gt;

&lt;p&gt;To test it, add the &lt;strong&gt;Get Teams Channel Library Info - test&lt;/strong&gt; Power App to a MS Teams channel. &lt;/p&gt;

&lt;p&gt;The top section displays Teams context parameters. The &lt;strong&gt;Fetch folder information&lt;/strong&gt; button triggers the &lt;strong&gt;Get Teams Channel Library Info&lt;/strong&gt; flow, with results displayed below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbv25oq8y3imixy2lpnb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbv25oq8y3imixy2lpnb.png" alt="Power Apps application screenshot" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;This Power Automate Flow is using &lt;strong&gt;HTTP with Microsoft Entra ID&lt;/strong&gt; connector, which requires &lt;strong&gt;Premium license&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In order to successfully execute the flow, you need to grant the &lt;strong&gt;PowerPlatform-webcontentsv2-Connector&lt;/strong&gt; service principal the following API permissions to &lt;code&gt;Microsoft Graph&lt;/code&gt; resource:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Channel.ReadBasic.All&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;Team.ReadBasic.All&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Files.Read.All&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkt21rbgyyaqkhgjda40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkt21rbgyyaqkhgjda40.png" alt="API Permissions" width="800" height="135"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow the &lt;a href="https://learn.microsoft.com/en-us/connectors/webcontentsv2/#authorize-the-connector-to-act-on-behalf-of-a-signed-in-user" rel="noopener noreferrer"&gt;Authorize the connector to act on behalf of a signed-in user&lt;/a&gt; procedure to grant the permissions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Doesn't work!
&lt;/h4&gt;

&lt;p&gt;If you see a &lt;em&gt;" Missing scope permissions on the request."&lt;/em&gt; error, it is possible that you tested the flow before granting the required API permissions. Now you have to wait. According to my experience - approximately one hour. &lt;/p&gt;

&lt;h2&gt;
  
  
  Download the solution
&lt;/h2&gt;

&lt;p&gt;You may download the workflow from the &lt;a href="https://github.com/kkazala/Power-Automate-Utils" rel="noopener noreferrer"&gt;Power Automate Utils&lt;/a&gt; github repository.  &lt;/p&gt;

&lt;p&gt;The flow accepts two parameters: &lt;code&gt;teamsId&lt;/code&gt; and &lt;code&gt;channelId&lt;/code&gt;. Depending on the app type, use the following parameters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Embeded Canvas App&lt;/th&gt;
&lt;th&gt;Integrated Canvas App&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;teamId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Param("teamId")&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Teams.ThisTeam.Id&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;channelId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Param("channelId")&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Teams.ThisChannel.Id&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/SharePoint/teams-connected-sites" rel="noopener noreferrer"&gt;Overview of Teams and SharePoint integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://forwardforever.com/what-is-the-difference-between-http-with-microsoft-entra-id-and-http-with-microsoft-entra-id-preauthorized-connectors/" rel="noopener noreferrer"&gt;What is the difference between HTTP with Microsoft Entra ID and HTTP with Microsoft Entra ID (preauthorized) connectors?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://forwardforever.com/calling-an-api-using-entra-id-authentication-in-flow/" rel="noopener noreferrer"&gt;Using an API in Power Automate with Entra ID authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/66491929/is-there-any-microsoft-api-to-get-the-group-id-from-channel-id" rel="noopener noreferrer"&gt;Is there any Microsoft API to get the group Id from channel id? - Stack Overflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>powerplatform</category>
      <category>powerautomate</category>
      <category>powerapps</category>
      <category>msteams</category>
    </item>
    <item>
      <title>Invoke an HTTP request without a premium license: connectors summary</title>
      <dc:creator>Kinga</dc:creator>
      <pubDate>Fri, 27 Dec 2024 13:31:00 +0000</pubDate>
      <link>https://forem.com/kkazala/invoke-an-http-request-without-a-premium-license-connectors-summary-4pmd</link>
      <guid>https://forem.com/kkazala/invoke-an-http-request-without-a-premium-license-connectors-summary-4pmd</guid>
      <description>&lt;p&gt;As of today, there are &lt;strong&gt;six Power Automate standard connectors&lt;/strong&gt; allowing us to send &lt;strong&gt;http requests&lt;/strong&gt; to Microsoft 365 tenant.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcs9a4gn75k2cz9oybba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcs9a4gn75k2cz9oybba.png" alt="All HTTP standard actions" width="321" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These connectors provide &lt;code&gt;Send an HTTP request&lt;/code&gt; actions that support only a subset of MS Graph API endpoints. &lt;br&gt;
If they don't provide the required functionality, you may need to use a premium HTTP action to work around these limitations. At this point you need the align the structure of the API requests, with the segments supported by each  &lt;code&gt;Send an HTTP request&lt;/code&gt; action.&lt;/p&gt;

&lt;p&gt;I personally like preparing my API requests using  &lt;a href="https://learn.microsoft.com/en-us/graph/graph-explorer/graph-explorer-overview" rel="noopener noreferrer"&gt;Graph Explorer&lt;/a&gt; first, as this allows me to explore the Microsoft Graph API, find out which parameters should be used, and what information is returned by the endpoints.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;:These are not shareable connections. If the power app is shared with another user, another user will be prompted to create new connection explicitly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  HTTP actions summary
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Also important&lt;/strong&gt;: Below, I'm only providing evaluation of &lt;code&gt;GET&lt;/code&gt; functions. &lt;br&gt;All the &lt;code&gt;Send HTTP&lt;/code&gt; actions support &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;PATCH&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Office 365 Users
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fir8fmnfnd9z01kjud0ee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fir8fmnfnd9z01kjud0ee.png" alt="Office 365 Users action" width="321" height="42"&gt;&lt;/a&gt; &lt;br&gt;
Segments supported: 1st segment: &lt;code&gt;/me&lt;/code&gt;, &lt;code&gt;/users/&lt;/code&gt;, 2nd segment: &lt;code&gt;messages&lt;/code&gt;, &lt;code&gt;mailFolders&lt;/code&gt;, &lt;code&gt;events&lt;/code&gt;, &lt;code&gt;calendar&lt;/code&gt;, &lt;code&gt;calendars&lt;/code&gt;, &lt;code&gt;outlook&lt;/code&gt;, &lt;code&gt;inferenceClassification&lt;/code&gt;. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supported segments&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/me&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get the signed-in user's details. &lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/user-get" rel="noopener noreferrer"&gt;Get a user&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{id / service principal}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gets a specific user by Id (GUID) or a service principal name (&lt;code&gt;user@contoso.onmicrosoft.com&lt;/code&gt;). &lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/user-get?" rel="noopener noreferrer"&gt;Get a user&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{id}/messages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lists the user's email messages in their primary inbox. &lt;br&gt; &lt;a href="https://learn.microsoft.com/en-us/graph/api/user-list-messages?view=graph-rest-1.0&amp;amp;tabs=http" rel="noopener noreferrer"&gt;List messages&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{id}/mailFolders&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get the mail folders directly under the root folder of the signed-in user, including by default: &lt;code&gt;Archive&lt;/code&gt;, &lt;code&gt;Conversation History&lt;/code&gt;, &lt;code&gt;Deleted items&lt;/code&gt;, &lt;code&gt;Drafts&lt;/code&gt;, &lt;code&gt;Inbox&lt;/code&gt;, &lt;code&gt;Junk Email&lt;/code&gt;, &lt;code&gt;Outbox&lt;/code&gt;, &lt;code&gt;Sent Items&lt;/code&gt;&lt;br&gt; &lt;a href="https://learn.microsoft.com/en-us/graph/api/user-list-mailfolders" rel="noopener noreferrer"&gt;List mailFolders&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{id}/events&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lists the user's upcoming events in their calendar. &lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/user-list-events?view=graph-rest-1.0&amp;amp;tabs=http" rel="noopener noreferrer"&gt;List events&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{id}/calendar&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns the information about the user's default calendar. &lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/resources/calendar" rel="noopener noreferrer"&gt;calendar resource type&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{id}/calendars&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get all the user's calendars from either the default or a specific calendar group. &lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/user-list-calendars" rel="noopener noreferrer"&gt;List calendars&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{id}/outlook&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns Id in a &lt;code&gt;user-id#tenant-id&lt;/code&gt; format. It is a unique identifier for a user within a specific tenant in Microsoft Graph.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{id}/inferenceClassification&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The inferenceClassification resource in Microsoft Graph API is used to classify a user’s messages to help them focus on the most relevant or important ones. This endpoint retrieves the list of overrides a user has set up. &lt;br&gt; &lt;a href="https://learn.microsoft.com/en-us/graph/api/resources/inferenceclassification" rel="noopener noreferrer"&gt;inferenceClassification resource type&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Resources
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/connectors/office365users/#send-an-http-request" rel="noopener noreferrer"&gt;Office 365 Users | Send an HTTP request&lt;/a&gt; action, and &lt;a href="https://learn.microsoft.com/en-us/connectors/office365users/#known-issues-and-limitations" rel="noopener noreferrer"&gt;Known Issues and Limitations&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/graph/api/resources/users" rel="noopener noreferrer"&gt;Working with users in Microsoft Graph&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Office 365 Outlook
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fza2m8lrc57jw63waklgz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fza2m8lrc57jw63waklgz.png" alt="Office 365 Outlook" width="321" height="41"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Segments supported: 1st segment: &lt;code&gt;/me&lt;/code&gt;, &lt;code&gt;/users/&lt;/code&gt;, 2nd segment: &lt;code&gt;messages&lt;/code&gt;, &lt;code&gt;mailFolders&lt;/code&gt;, &lt;code&gt;events&lt;/code&gt;, &lt;code&gt;calendar&lt;/code&gt;, &lt;code&gt;calendars&lt;/code&gt;, &lt;code&gt;outlook&lt;/code&gt;, &lt;code&gt;inferenceClassification&lt;/code&gt;. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supported segments&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/me&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The first segment is supported to access the second segment, but calling the &lt;code&gt;https://graph.microsoft.com/v1.0/users/me&lt;/code&gt; endpoint without the second segment will result in an error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{id / service principal}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;as above&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This action is &lt;em&gt;almost&lt;/em&gt; identical to &lt;code&gt;Send HTTP request&lt;/code&gt; from &lt;code&gt;Office 365 users&lt;/code&gt; connector; see the &lt;strong&gt;Office 365 Users&lt;/strong&gt; above for the documentation on the rest of the supported segments.&lt;/p&gt;

&lt;h4&gt;
  
  
  Resources
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/connectors/office365/#send-an-http-request" rel="noopener noreferrer"&gt;Office 365 Outlook| Send an HTTP request&lt;/a&gt; action&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/connectors/office365" rel="noopener noreferrer"&gt;Office 365 Outlook&lt;/a&gt; connector documentation for known issues, shared mailbox support information, common errors, etc.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  SharePoint
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri68jw9knh8lkgan52qy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri68jw9knh8lkgan52qy.png" alt="SharePoint" width="321" height="42"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This action may execute any SharePoint &lt;strong&gt;REST API&lt;/strong&gt; you have access to. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rest API&lt;/strong&gt; is different from MS Graph API, even though MS Graph API also provides actions that access SharePoint. &lt;br&gt;
SharePoint REST API is older, is supported also in SharePoint on premise, and unlike MS Graph API does not require granting API permissions to the software that is using them. &lt;/p&gt;

&lt;p&gt;Microsoft Graph, on the other hand,  is a newer approach supporting various M365 services. New actions are &lt;a href="https://learn.microsoft.com/en-us/sharepoint/dev/apis/sharepoint-rest-graph" rel="noopener noreferrer"&gt;added to SharePoint REST API using Microsoft Graph&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service?tabs=csom" rel="noopener noreferrer"&gt;Get to know the SharePoint REST service&lt;/a&gt;  and &lt;a href="https://learn.microsoft.com/en-us/connectors/sharepointonline/#known-issues-and-limitations" rel="noopener noreferrer"&gt;SharePoint&lt;/a&gt; connector documentation for information about delegation, throttling limits, etc.&lt;/p&gt;




&lt;h3&gt;
  
  
  Microsoft Teams
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F370fs83em1khzcxf6kvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F370fs83em1khzcxf6kvm.png" alt="Microsoft Teams" width="321" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Segments supported: 1st segment: &lt;code&gt;/teams&lt;/code&gt;, &lt;code&gt;/me&lt;/code&gt;, &lt;code&gt;/users&lt;/code&gt;,  2nd segment: &lt;code&gt;channels&lt;/code&gt;, &lt;code&gt;chats&lt;/code&gt;, &lt;code&gt;installedApps&lt;/code&gt;, [3rd segment]: &lt;code&gt;messages&lt;/code&gt;, &lt;code&gt;pinnedMessages&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supported segments&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/teams&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Although &lt;code&gt;/teams&lt;/code&gt; is supported to access the second segment, calling the &lt;code&gt;https://graph.microsoft.com/v1.0/users/teams&lt;/code&gt;  or &lt;code&gt;https://graph.microsoft.com/v1.0/users/teams/{id}&lt;/code&gt; endpoint without the second segment will result in an error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/me&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;as above&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{user-id / service principal}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;as above&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/teams/{user-id}/channels&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retrieve the list of channels in a team. &lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/channel-list?view=graph-rest-1.0&amp;amp;tabs=http" rel="noopener noreferrer"&gt;List channels&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/me/chats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all "one on one" chats for the user. &lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/chat-list" rel="noopener noreferrer"&gt;List chats&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{user-id / service principal}/chats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;as above&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/teams/{team-id}/installedApps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all app installations within a team.&lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/team-list-installedapps" rel="noopener noreferrer"&gt;List apps in team&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/teams/{team-id}/channels/{channel-id}/messages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retrieve the list of messages (without the replies) in a channel of a team.&lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/channel-list-messages" rel="noopener noreferrer"&gt;List channel messages&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/me/chats/{chat-id}/messages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;as above&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/users/{user-id / service principal}/chats/{chat-id}/messages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Error  &lt;code&gt;User Mri does not match request initiator!&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If a combination of &lt;code&gt;1st/2nd/3rd&lt;/code&gt; segment is not mentioned in the table above, it is probably (at least, based on my tests), not supported. &lt;/p&gt;

&lt;p&gt;For example, calling &lt;code&gt;https://graph.microsoft.com/v1.0/chats/{chat-id}/installedApps&lt;/code&gt; is a correct MS Graph API call, but is not supported by the "Microsoft Teams" connector and will result in an error.&lt;/p&gt;

&lt;p&gt;I'm also not sure how to use &lt;code&gt;pinnedMessages&lt;/code&gt;. I only found &lt;code&gt;/chats/{chat-id}/pinnedMessages&lt;/code&gt; in the &lt;a href="https://learn.microsoft.com/en-us/graph/api/chat-list-pinnedmessages?view=graph-rest-1.0&amp;amp;tabs=http" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, but &lt;code&gt;chats&lt;/code&gt; cannot be used as a first segment. &lt;/p&gt;

&lt;h4&gt;
  
  
  Resources
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/connectors/teams/?tabs=text1%2Cdotnet#creating-a-connection" rel="noopener noreferrer"&gt;Microsoft Teams&lt;/a&gt; connector&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Office 365 Groups
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxky878vcuf8177mfrnuh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxky878vcuf8177mfrnuh.png" alt="Office 365 Groups " width="321" height="43"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is one segment that is supported: &lt;code&gt;/groups&lt;/code&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supported segments&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;groups&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all the groups available to the current user. &lt;br&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/api/group-list" rel="noopener noreferrer"&gt;List groups&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;groups/{group-Id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get the properties and relationships of a group. &lt;br&gt; &lt;a href="https://learn.microsoft.com/en-us/graph/api/group-get" rel="noopener noreferrer"&gt;Get group&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Office 365 Groups Mail
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqjvmcx4d7mnbfmp8nii.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqjvmcx4d7mnbfmp8nii.png" alt="Office 365 Groups Mail" width="321" height="45"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Segments supported: 1st segment: &lt;code&gt;me&lt;/code&gt;, &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;groups,&lt;/code&gt; 2nd segments: &lt;code&gt;messages&lt;/code&gt;, &lt;code&gt;mailFolders&lt;/code&gt;, &lt;code&gt;events&lt;/code&gt;, &lt;code&gt;calendar&lt;/code&gt;, &lt;code&gt;calendars&lt;/code&gt;, &lt;code&gt;outlook&lt;/code&gt;, &lt;code&gt;inferenceClassification&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Although &lt;code&gt;groups&lt;/code&gt; is not mentioned in the error message of the &lt;code&gt;Send an HTTP request&lt;/code&gt; action, it does work just like it &lt;a href="https://dev.to/kkazala/create-group-event-in-power-automate-without-a-premium-license-4n6c"&gt;used to&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This action seems identical to the &lt;code&gt;Send HTTP request&lt;/code&gt; of &lt;code&gt;Office 365 Outlook&lt;/code&gt; connector; see the &lt;strong&gt;Office 365 Outlook&lt;/strong&gt; above for the documentation on the rest of the supported segments.&lt;/p&gt;

</description>
      <category>powerautomate</category>
      <category>powerplatform</category>
      <category>microsoftgraph</category>
    </item>
  </channel>
</rss>
