<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-5285970135510371565</atom:id><lastBuildDate>Mon, 21 Sep 2026 11:00:00 +0000</lastBuildDate><category>Events</category><category>Article</category><category>Troubleshooting</category><category>Functionality</category><category>Around the Blogosphere</category><category>Code</category><category>Dexterity</category><category>Installation</category><category>SQL Scripting</category><category>Convergence</category><category>Web Client</category><category>Best Practices</category><category>GPUG</category><category>SQL Server</category><category>Training</category><category>Technical Conference</category><category>Dynamics GP 12</category><category>Dynamics GP 2013</category><category>Integration</category><category>VBA</category><category>Roadmap</category><category>Sales Order Processing</category><category>Architecture</category><category>Dynamics GP 2010</category><category>Support Debugging Tool</category><category>Visual Studio Tools</category><category>Integration Manager</category><category>PowerApps</category><category>Reporting</category><category>Compliance</category><category>Azure</category><category>Dynamics GP 2015</category><category>PowerAddicts</category><category>Security</category><category>Inventory</category><category>Modifier</category><category>Dynamics GP 2010 R2</category><category>General Ledger</category><category>Power Platform</category><category>Power Automate</category><category>Purchasing</category><category>MVPs</category><category>Report Writer</category><category>C#</category><category>Dynamics GP 11</category><category>Payables Management</category><category>Microsoft Office</category><category>SmartList and SmartList Builder</category><category>Amplify</category><category>Dynamics GP 2016</category><category>Flow</category><category>Payroll</category><category>Word Templates</category><category>Dynamics GP 2018</category><category>Receivables Management</category><category>Upgrades</category><category>DevOps</category><category>SQL Reporting Services</category><category>VBScript</category><category>GPPC</category><category>DEX.INI</category><category>From the Newsgroups</category><category>System Manager</category><category>Business Central</category><category>Extender</category><category>PowerPlatform</category><category>VB.NET</category><category>Windows 8</category><category>eConnect</category><category>Home Page</category><category>Field Services</category><category>Power Apps</category><category>Season Greetings</category><category>Service Architecture</category><category>The Technology Corner</category><category>Visual Studio 2008</category><category>Visual Studio Team Services</category><category>Community</category><category>Human Resources</category><category>Management Reporter</category><category>Workflow</category><category>Business Analyzer</category><category>COM</category><category>Corporate Performance Management</category><category>Decisions Conference</category><category>Fixed Assets</category><category>Maintenance</category><category>OLE Container</category><category>Power BI</category><category>SharePoint</category><category>Source Code Control</category><category>reimagine</category><category>ALM</category><category>CRM</category><category>Copilot Studio</category><category>Macros</category><category>Navigation Pane</category><category>PowerShell</category><category>Product Feedback</category><category>Tax Updates</category><category>Web Services</category><category>DocWatch</category><category>Intelligent Edge</category><category>Internet Explorer</category><category>Project Accounting</category><category>Bank Reconciliation</category><category>Best of Series</category><category>Books</category><category>FRx</category><category>Humor</category><category>MVP Summit</category><category>Named Printers</category><category>Table Import</category><category>Visual Studio</category><category>Windows 10</category><category>AI Builder</category><category>Ad Campaigns</category><category>Cognitive Services</category><category>Dexterity Shared Components</category><category>Dynamics 365</category><category>Dynamics NAV</category><category>EFT</category><category>Electronic Banking</category><category>Encumbrance</category><category>Line Sequence Number</category><category>MOSS</category><category>Manufacturing</category><category>Mixed Reality</category><category>Office Web Components</category><category>UI flows</category><category>Windows 7</category><category>Analysis Cubes</category><category>Analytical Accounting</category><category>Automated Solutions</category><category>Business Alerts</category><category>Database Maintenance Utility</category><category>Docker</category><category>Document Attach</category><category>Fargo Floods</category><category>Internet Information Services</category><category>MCP</category><category>Menus for Visual Studio Tools</category><category>Multicurrency Management</category><category>Office 365</category><category>Online Services</category><category>Power Virtual Agents</category><category>Printer Compatibility</category><category>Silverlight</category><category>Software Development Kits</category><category>XBox</category><category>AL language</category><category>Augmented Reality</category><category>Bing Maps Enterprise</category><category>Bots</category><category>Chrome</category><category>Connect</category><category>Continuum</category><category>DEXSQL</category><category>Dataverse</category><category>Drill-Down Builder</category><category>Flic</category><category>GP Power Tools</category><category>IMHO</category><category>Kinnect</category><category>Newsgroups</category><category>Notes</category><category>OpenXML</category><category>Performance</category><category>PowerPlatform PowerAddicts</category><category>Professional Services Tool Library</category><category>Robotic Process Automation</category><category>SafePay</category><category>Service Call Management</category><category>Team Foundation Server</category><category>Telemetry</category><category>Translation</category><category>VAT</category><category>VS Code</category><category>Windows Server</category><category>ADO</category><category>AI</category><category>Accounts Rollup</category><category>Adobe Acrobat</category><category>Agents</category><category>Application Insights</category><category>Azure Application Insights</category><category>Azure Key Vault</category><category>Best of 2009</category><category>Business Portal</category><category>COVID19</category><category>Certificates</category><category>Check Links</category><category>Claude Code</category><category>Clear Data</category><category>Common Data Services</category><category>Computer Vision</category><category>Coronavirus</category><category>DEX_ROW_ID</category><category>DUOS</category><category>Deferrals</category><category>Discussions</category><category>Dynamics GP</category><category>Dynamics GP   14</category><category>Dynamics GP 10</category><category>Dynamics GP Russian</category><category>Flexicoder</category><category>FlowFam</category><category>Forecaster</category><category>Form Processing</category><category>GP PowerShell</category><category>GitHub</category><category>HTML 5</category><category>Hololense</category><category>IoT</category><category>LINQ to SQL</category><category>Mentor</category><category>Microsoft Band</category><category>Microsoft Edge</category><category>Microsoft Gadgets</category><category>Multitenancy</category><category>Next Document Number</category><category>ODBC</category><category>Open Source</category><category>PO Commitments</category><category>Partner Connections</category><category>Process Server</category><category>Project Madeira</category><category>RPA</category><category>RemoteApp</category><category>Requisitions</category><category>SmartLists</category><category>SmartLists Designer</category><category>Splash Screen</category><category>Surface</category><category>Task Scheduler</category><category>Text Analytics</category><category>The Partner Event</category><category>Twilio</category><category>Use Tax</category><category>Virtual Earth</category><category>Virtualization</category><category>Web API</category><category>XBRL</category><category>pac CLI</category><title>The Workbench</title><description>Hands-on with AI, Copilot Studio, and the Power Platform</description><link>http://www.theworkbench.blog/</link><managingEditor>noreply@blogger.com (Mariano Gomez)</managingEditor><generator>Blogger</generator><openSearch:totalResults>1102</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-4103367055235025259</guid><pubDate>Mon, 21 Sep 2026 11:00:00 +0000</pubDate><atom:updated>2026-09-21T07:00:00.115-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Copilot Studio</category><category domain="http://www.blogger.com/atom/ns#">DocWatch</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><title>Copilot Studio | The Agent Your Flow Can&#39;t Call</title><description>&lt;!-- Cover image is hosted in the public theworkbench-assets repo. If you prefer Google-hosted
     images, re-upload the PNG through the Blogger editor before you publish. --&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;
&lt;img alt=&quot;The agent your flow can&#39;t call: Copilot Studio harness choice&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-14-copilot-harness-split.png&quot; style=&quot;max-width:100%;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;There is a particular kind of bad afternoon in this business. You have built the thing, it works, you demo it, everyone is happy. Then somebody asks the obvious follow-up question, the one that was always coming: &quot;great, now can the nightly flow call it?&quot; And you go to wire it up and discover that the answer is no, not because you did anything wrong, but because of a choice you made on day one without knowing it was a choice.&lt;/p&gt;

&lt;p&gt;Microsoft published a short new article in mid-August that will save somebody that afternoon. It is worth reading before you build your next agent rather than after.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Background&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The article is &lt;a href=&quot;https://learn.microsoft.com/en-us/power-automate/call-copilot-studio-agent&quot;&gt;Call Microsoft Copilot Studio agents from Power Automate&lt;/a&gt;, new in the Power Automate documentation and last updated August 18, 2026. It opens with a two-row table, and that table is the whole post:&lt;/p&gt;

&lt;blockquote&gt;Standard harness: Call the agent from a Power Automate cloud flow by using the Microsoft Copilot Studio connector.&lt;br/&gt;&lt;br/&gt;GitHub Copilot harness: Use the agent node in a Copilot Studio workflow. You can&#39;t call this type of agent from a Power Automate cloud flow by using the Microsoft Copilot Studio connector.&lt;/blockquote&gt;

&lt;p&gt;Now, a &lt;b&gt;harness&lt;/b&gt; needs defining, because the word is new enough that plenty of people building agents right now have never seen it. Per the &lt;a href=&quot;https://learn.microsoft.com/en-us/microsoft-copilot-studio/harnesses-overview&quot;&gt;harnesses overview&lt;/a&gt;, you design the agent and the model supplies the reasoning, and the harness is the runtime sitting between the two: it decides when to call the model, what to send it, how to interpret what comes back, and which tools to call. Everything you build in Copilot Studio runs on one.&lt;/p&gt;

&lt;p&gt;There are three. The &lt;b&gt;GitHub Copilot harness&lt;/b&gt; powers agents and workflows built for reasoning-heavy, multistep work, and bills through Copilot Credits on usage. The &lt;b&gt;standard harness&lt;/b&gt; powers rule-based agents and agent flows, where you define the topics and paths and get predictable behavior. The &lt;b&gt;Copilot chat harness&lt;/b&gt; is for extending Microsoft 365 Copilot.&lt;/p&gt;

&lt;p&gt;So the harness is not a setting you flip later. It determines how your agent reasons, how you are billed, and, as of this article, what can call it.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;This was not one article&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Here is the part that makes me confident this is a real platform move rather than a documentation footnote. That new Power Automate page did not arrive alone. Across the same week, roughly a hundred Copilot Studio articles were touched, and the substantive edits among them all point the same direction: Microsoft is retiring the informal vocabulary and replacing it with harness names everywhere.&lt;/p&gt;

&lt;p&gt;Pages that used to say &quot;the classic experience&quot; and &quot;the new agent experience&quot; now say &quot;the standard harness&quot; and &quot;agents powered by the GitHub Copilot harness.&quot; The telemetry articles were split along the same line: agent-level telemetry is now documented as available &lt;i&gt;only&lt;/i&gt; with the standard harness, while environment-level telemetry works with both. The article on adding tools to an agent was amended to say that coding-agent skills can only be added to agents powered by the GitHub Copilot harness. Even the old skills article was reworded to name both harnesses explicitly.&lt;/p&gt;

&lt;p&gt;One renamed page is housekeeping. A hundred pages renamed in one week, with capability boundaries drawn along the new names, is a platform telling you that this distinction is now load-bearing.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Why it matters&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;For &lt;b&gt;makers&lt;/b&gt;, the practical consequence is a question you now have to ask at the start: does anything else need to call this agent? If a scheduled flow, an approval process, or an existing automation has to invoke it, you want the standard harness, because that is the one the Power Automate connector can reach. If the agent is going to be talked to by humans and needs to reason its way through messy multistep work, the GitHub Copilot harness is the more capable runtime, and you accept that your integration path runs through Copilot Studio workflows instead.&lt;/p&gt;

&lt;p&gt;You may be asking whether that is a real constraint or just a temporary gap. The documentation does not say, and I am not going to guess. What it does say is what works today, and today the connector supports one harness and not the other.&lt;/p&gt;

&lt;p&gt;For &lt;b&gt;professional developers&lt;/b&gt;, the sharper point is that this is an architectural decision wearing the costume of a product setting. It sits alongside two others made at the same moment: your billing model, since the GitHub Copilot harness runs on Copilot Credits and the standard harness runs on the licensing model, and your observability model, since agent-level telemetry export is standard-harness only. Three consequences, one choice, made in a dropdown before you have written anything.&lt;/p&gt;

&lt;p&gt;NOTE: there is a workaround, and it is a legitimate one rather than a hack, but it does change your topology. You call a GitHub Copilot harness agent from an &lt;b&gt;agent node&lt;/b&gt; inside a Copilot Studio workflow. That means the orchestration lives in Copilot Studio rather than in Power Automate. If your organization&#39;s automation estate, source control, and deployment pipeline are all built around cloud flows, that is not a small relocation.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The demo concept&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Build the same trivial agent twice, once on each harness, and then try to call both from one cloud flow. The standard harness agent answers. The other one is not selectable, because it never appears in the connector&#39;s agent picker at all.&lt;/p&gt;

&lt;p&gt;That is the demonstration worth recording, because it is a negative result and negative results are what documentation tends to bury. Then build the workflow-plus-agent-node path for the second agent and show it working. Two agents, two integration paths, one screen recording, and nobody on your team ever has that bad afternoon.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Steps to recreate&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;First, the supported path. These steps are quoted from the new article.&lt;/p&gt;

&lt;p&gt;1) Sign in to Power Automate.&lt;/p&gt;

&lt;p&gt;2) Create a cloud flow, or open an existing cloud flow and select &lt;b&gt;Edit&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;3) In the designer, select the plus sign (&lt;b&gt;+&lt;/b&gt;) where you want to call the agent, and then select &lt;b&gt;Add an action&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;4) Search for &lt;b&gt;Microsoft Copilot Studio&lt;/b&gt;, and then select &lt;b&gt;Execute Agent and wait&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;5) If prompted, sign in with Microsoft Entra ID to create a connection.&lt;/p&gt;

&lt;p&gt;6) In &lt;b&gt;Agent&lt;/b&gt;, select the published standard harness agent that you want to call.&lt;/p&gt;

&lt;p&gt;7) In &lt;b&gt;Message&lt;/b&gt;, enter the instructions for the agent. You can add dynamic content from earlier steps in the flow.&lt;/p&gt;

&lt;p&gt;8) Configure the optional inputs your scenario needs: &lt;b&gt;Locale&lt;/b&gt; (the language of the message, as a BCP-47 locale), &lt;b&gt;Conversation ID&lt;/b&gt; (an existing conversation ID, to continue an agent conversation), and &lt;b&gt;Environment ID&lt;/b&gt; (the environment that contains the agent).&lt;/p&gt;

&lt;p&gt;9) Add any actions that should use the agent&#39;s response, then select &lt;b&gt;Save&lt;/b&gt; and test the flow.&lt;/p&gt;

&lt;p&gt;A few things to note about that sequence. The word &lt;b&gt;published&lt;/b&gt; in step 6 is not filler: an unpublished agent will not be there to pick, and that is the first thing to check when the dropdown looks empty. &lt;b&gt;Execute Agent and wait&lt;/b&gt; blocks the flow until the agent responds, which is what you want when the next action consumes the answer; the article notes that if you do not need to wait, the plain &lt;b&gt;Execute Agent&lt;/b&gt; action sends the message and returns the conversation ID instead. And that conversation ID is the interesting output, because passing it back in on the next call is what turns a series of one-shot invocations into an actual conversation. The action surfaces the last response, a list of responses, and the conversation ID as dynamic content.&lt;/p&gt;

&lt;p&gt;Now the other path, for a GitHub Copilot harness agent:&lt;/p&gt;

&lt;p&gt;1) In Copilot Studio, go to &lt;b&gt;Workflows&lt;/b&gt; and open an existing workflow, or create a new one.&lt;/p&gt;

&lt;p&gt;2) On the &lt;b&gt;Add&lt;/b&gt; panel, select the &lt;b&gt;Agent&lt;/b&gt; icon.&lt;/p&gt;

&lt;p&gt;3) Under &lt;b&gt;Agent&lt;/b&gt;, select &lt;b&gt;An existing agent&lt;/b&gt;, and then select the published GitHub Copilot harness agent you want to call.&lt;/p&gt;

&lt;p&gt;4) In &lt;b&gt;Message&lt;/b&gt;, enter the instructions for this run, adding dynamic content from earlier workflow steps as needed.&lt;/p&gt;

&lt;p&gt;5) Add the later workflow steps that use the agent response, and test the workflow before you publish it.&lt;/p&gt;

&lt;p&gt;Notice the symmetry. Both paths are an agent-invoking step with a message and a response, and both want the target published first. The difference is entirely which product hosts the orchestration, which is exactly why the constraint is easy to miss until it bites: the shape of the work is identical, only the address changes.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Companion repo sketch&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;A small comparison lab. Two exported solutions, &lt;code&gt;agent-standard/&lt;/code&gt; and &lt;code&gt;agent-ghcopilot/&lt;/code&gt;, each holding the same deliberately boring agent so the harness is the only variable. A &lt;code&gt;flow-caller/&lt;/code&gt; solution with the cloud flow that calls the standard harness agent through &lt;b&gt;Execute Agent and wait&lt;/b&gt;. A &lt;code&gt;workflow-caller/&lt;/code&gt; solution with the Copilot Studio workflow that reaches the other one through an agent node.&lt;/p&gt;

&lt;p&gt;Then the file that makes the repository worth cloning: a &lt;code&gt;MATRIX.md&lt;/code&gt; recording what each harness supports, with the observed result and the date beside every row. Connector callable, agent-level telemetry, coding-agent skills, billing model. Date every row, because this is a moving platform and an undated compatibility matrix is worse than none at all. It ages into confident misinformation.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Final Notes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The change itself is one table in one short article. What makes it worth your time is the timing: it landed in the same week that a hundred sibling pages were rewritten to make harness the organizing noun of the whole product. That is not a coincidence, and it is a reasonable bet that more capability boundaries get drawn along this line before the year is out.&lt;/p&gt;

&lt;p&gt;So ask the integration question first. Before the topics, before the knowledge sources, before anybody sees a demo: what needs to be able to call this? The answer picks your harness, and the harness picks a great deal else.&lt;/p&gt;

&lt;p&gt;What I learned from this exercise: the most expensive decisions on a platform are rarely the ones that look like decisions. They look like defaults.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br/&gt;
Mariano Gomez Bent&lt;br/&gt;
Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/09/copilot-studio-agent-your-flow-cant-call.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-4424552724186502185</guid><pubDate>Thu, 17 Sep 2026 11:00:00 +0000</pubDate><atom:updated>2026-09-17T07:00:00.116-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">DocWatch</category><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><title>Power Apps | Seven Skills, One Prompt: The Dataverse Plugin for Coding Agents</title><description>&lt;!-- Cover image is hosted in the public theworkbench-assets repo. If you prefer Google-hosted
     images, re-upload the PNG through the Blogger editor before you publish. --&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;
&lt;img alt=&quot;Seven skills, one prompt: the Dataverse plugin for AI coding agents&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-13-dataverse-agent-plugin.png&quot; style=&quot;max-width:100%;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Anyone who has built anything nontrivial on Microsoft Dataverse knows the tax. You want to stand up a small data model, load a few thousand rows into it, and move the whole thing to a test environment. That is one sentence to describe and four tools to execute: the SDK for Python for the bulk write, the Dataverse CLI for authentication, the Power Platform CLI for the solution export, and the Web API for whatever the other three do not cover. None of it is hard. All of it is friction, and the friction is mostly syntax you have to remember rather than decisions you have to make.&lt;/p&gt;

&lt;p&gt;Well, in late August Microsoft published something that goes after exactly that friction, and it arrived quietly, as two new articles with no fanfare attached.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Background&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Two new pages landed in the &lt;code&gt;MicrosoftDocs/powerapps-docs&lt;/code&gt; repository, both dated 07/31/2026 and both published in the week ending August 24:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/developer/data-platform/agents-plugin/&quot;&gt;Microsoft Dataverse plugin for AI coding agents (preview)&lt;/a&gt;, the overview and install article.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/developer/data-platform/agents-plugin/reference&quot;&gt;Microsoft Dataverse plugin for AI coding agents reference (preview)&lt;/a&gt;, the per-skill reference.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are new files, not edits, and the developer table of contents was amended to carry them, which is the tell that this is a shipped surface rather than a stray draft. The source is open, in the &lt;a href=&quot;https://github.com/microsoft/Dataverse-skills&quot;&gt;microsoft/Dataverse-skills&lt;/a&gt; repository, so you can read every instruction the agent is given before you let it near an environment. I would encourage you to do exactly that.&lt;/p&gt;

&lt;p&gt;Now, the term &lt;b&gt;coding agent&lt;/b&gt; deserves a definition, because it is doing a lot of work in these articles. A coding agent is an AI assistant that runs inside your development environment, reads and writes files in your project, and executes commands on your behalf. GitHub Copilot, Claude Code, Cursor and Codex are the four named as supported. The distinction that matters: a coding agent runs commands, where a chat assistant only suggests them.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Solution: a plugin is instructions, not code&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Here is the part worth slowing down for, because it is easy to misread this as &quot;Microsoft shipped another connector.&quot;&lt;/p&gt;

&lt;p&gt;It did not. The documentation is precise: this is an open-source set of &lt;i&gt;instructions&lt;/i&gt; that help a supported coding agent perform Dataverse development and administration tasks. It does not replace the Dataverse development tools. It tells the agent which one to reach for.&lt;/p&gt;

&lt;p&gt;You may be asking why that is worth shipping at all. Very simple: tool selection is the hard part. An agent that knows the Web API exists will cheerfully use it to insert five hundred rows one HTTP call at a time, and it will be correct, and it will be terrible. The plugin&#39;s job is to know that five hundred rows means the Python SDK and &lt;code&gt;CreateMultiple&lt;/code&gt;, that a schema question means MCP, and that a solution export means the Power Platform CLI. The routing rule is stated plainly: MCP for interactive queries and small record sets, the Python SDK for bulk operations, transformations, paging and analytics.&lt;/p&gt;

&lt;p&gt;Seven skills ship with it. &lt;code&gt;dv-overview&lt;/code&gt; loads first and carries the tool-selection guidance; every other skill sits behind it. &lt;code&gt;dv-connect&lt;/code&gt; sets up the workspace. &lt;code&gt;dv-query&lt;/code&gt; reads and analyzes, up to server-side aggregation and pandas DataFrames. &lt;code&gt;dv-data&lt;/code&gt; handles creates, updates, upserts, CSV imports and sample data. &lt;code&gt;dv-metadata&lt;/code&gt; builds tables, columns, relationships, alternate keys, forms and views. &lt;code&gt;dv-solution&lt;/code&gt; runs the solution lifecycle. &lt;code&gt;dv-admin&lt;/code&gt; and &lt;code&gt;dv-security&lt;/code&gt; cover environment settings, retention, bulk delete, audit configuration and role assignment. A single request can pull several at once.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The two design decisions I would point at&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The first is buried in &lt;code&gt;dv-metadata&lt;/code&gt;, and every Dataverse developer will recognize it. The skill instructs the agent to follow an &lt;b&gt;environment-first metadata workflow&lt;/b&gt;: make the change in Dataverse through a managed API, export and unpack the solution, then commit the generated files. And then:&lt;/p&gt;

&lt;blockquote&gt;The agent shouldn&#39;t create new Dataverse components by writing solution XML manually.&lt;/blockquote&gt;

&lt;p&gt;That is the correct instinct, written down. Hand-authored solution XML is how you get components that import cleanly and then behave strangely, and an agent left alone would absolutely write it, because from a language model&#39;s point of view XML is just text and text is easy. A small sentence carrying a lot of hard-won experience.&lt;/p&gt;

&lt;p&gt;The second is the guardrail model, and it is more honest than I expected. The documentation states that Dataverse enforces the platform controls, that the agent-level guardrails guide how the agent plans and confirms, and that they &quot;aren&#39;t a substitute for reviewing the proposed action.&quot; Then it names the boundary that actually protects you: the agent cannot exceed the permissions of the authenticated identity. Table privileges, field-level security, ownership and sharing, and administrator permissions are enforced on every request.&lt;/p&gt;

&lt;p&gt;NOTE: the agent-level confirmations are still worth knowing. Before the first operation against an environment in a session, the agent must show the target environment URL and get confirmation. Before creating a publisher prefix it must show existing publishers, because a prefix is permanent. And an unfiltered bulk delete, which bypasses the recycle bin, requires an explicit acknowledgment naming the table logical name and stating that &lt;b&gt;all records&lt;/b&gt; should be deleted. That is the right shape for a destructive operation: make the human type the dangerous part.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Why it matters&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;For &lt;b&gt;makers&lt;/b&gt;, the honest answer is: not yet, and that is fine. This is a developer surface, needing a local toolchain, a terminal and a coding agent. If your Dataverse work happens entirely in make.powerapps.com, nothing here changes your Tuesday. What it does change is who can help you, and how fast.&lt;/p&gt;

&lt;p&gt;For &lt;b&gt;professional developers&lt;/b&gt;, there are two claims here and they are not the same size. The small one is convenience, real but unremarkable. The large one is that Microsoft has published, in the open, its own opinion about which Dataverse tool to use for which job, in a form a machine reads. That opinion has existed for years, scattered across documentation, conference sessions, and the accumulated instinct of people who have been burned enough times. Written down as executable guidance, it becomes reviewable, forkable, and arguable in a way instinct never is.&lt;/p&gt;

&lt;p&gt;Two cautions, both from the documentation rather than invented by me. This is &lt;b&gt;preview&lt;/b&gt;. And Dataverse MCP access carries an authorization chain no plugin can shortcut: the developer authenticates, a tenant administrator consents to the MCP client application, and an environment administrator allows that application in each target environment. The connection flow tells you what is needed; it does not bypass administrator approval. In a governed tenant, that is a ticket, not a command.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The demo concept&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Not &quot;watch the agent make a table,&quot; because that is a parlor trick that proves nothing you could not do faster by hand. The demonstration worth building is the four-tool problem from the top of this post, executed as one prompt, with the tool selection made visible. Build a small ticketing model, load a few hundred rows, package it, deploy it to a second environment. Then go back and look at which skill did what. If &lt;code&gt;dv-data&lt;/code&gt; reached for &lt;code&gt;CreateMultiple&lt;/code&gt; rather than five hundred single inserts, the routing did its job, and that is the whole point in one observation.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Steps to recreate&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;1) Install the plugin. The command differs by agent:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;GitHub Copilot:  /plugin install dataverse@awesome-copilot
Claude Code:     /plugin install dataverse@claude-plugins-official
Cursor:          /add-plugin dataverse&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. These are slash commands typed into the agent&#39;s own chat, not shell commands. The part after the &lt;code&gt;@&lt;/code&gt; is the marketplace the plugin comes from, and it differs because each vendor runs its own. In GitHub Copilot you can also run &lt;code&gt;/plugin&lt;/code&gt;, open &lt;b&gt;Discover&lt;/b&gt;, and search for &lt;b&gt;dataverse&lt;/b&gt;; in Cursor, go to &lt;b&gt;Settings&lt;/b&gt; &amp;gt; &lt;b&gt;Plugins&lt;/b&gt;, search for &lt;b&gt;Dataverse&lt;/b&gt;, open &lt;b&gt;Microsoft Dataverse&lt;/b&gt;, and select &lt;b&gt;Add to Cursor&lt;/b&gt;. Codex is the odd one out, having no default marketplace carrying this plugin: open &lt;b&gt;Plugins&lt;/b&gt; &amp;gt; &lt;b&gt;Add marketplace&lt;/b&gt;, set &lt;b&gt;Source&lt;/b&gt; to &lt;code&gt;https://github.com/microsoft/Dataverse-skills.git&lt;/code&gt;, leave &lt;b&gt;Git ref&lt;/b&gt; and &lt;b&gt;Sparse paths&lt;/b&gt; empty, add the marketplace, then install the &lt;code&gt;dataverse&lt;/code&gt; plugin from it.&lt;/p&gt;

&lt;p&gt;2) Connect, then verify, in plain language:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Connect to my Dataverse environment.
List the tables in my Dataverse environment.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first triggers &lt;code&gt;dv-connect&lt;/code&gt;, which checks whether the workspace is already configured, verifies and installs the required tools, discovers your environments and asks you to select one, configures Dataverse CLI and Power Platform CLI authentication, creates the local workspace configuration while excluding credentials and generated artifacts from source control, registers the Dataverse MCP server, and verifies the connection. That is nine steps behind one sentence, and the one I would call out is the source-control exclusion, because it is the step a hurried human skips. Note also that some coding agents must be &lt;b&gt;restarted&lt;/b&gt; after MCP registration before the MCP tools appear. If the second command comes back saying it has no tools, that is why.&lt;/p&gt;

&lt;p&gt;3) Do real work. This prompt is drawn from tests in the repository, which is a useful signal: it is known to work rather than merely plausible.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Write a Python script that efficiently creates 500 ticket records in my
Dataverse new_ticket table. Each ticket should have a unique title and a
priority value. Optimize for the fewest HTTP calls.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. &quot;Optimize for the fewest HTTP calls&quot; is the phrase doing the work, pushing the agent from a naive loop to &lt;code&gt;CreateMultiple&lt;/code&gt; with batching. Change &lt;code&gt;new_ticket&lt;/code&gt; to your own logical name, publisher prefix and all. And notice it asks for a &lt;i&gt;script&lt;/i&gt;, so you get an artifact you can read, commit, and run again, rather than an action that already happened.&lt;/p&gt;

&lt;p&gt;4) Package and move it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Pack the CustomerService solution, import it into the test environment, and
verify that the ticket table, main form, and active tickets view are available.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The verification clause is not decoration. &lt;code&gt;dv-solution&lt;/code&gt; supports post-deployment validation of tables, forms, views, role assignments and import errors, so asking for it is what turns &quot;the import returned success&quot; into &quot;the components are actually there.&quot; Two different claims, and only one is worth trusting.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Companion repo sketch&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;A lab repository that is honest about being a lab. A &lt;code&gt;prompts/&lt;/code&gt; folder with the exact prompts in order, so someone else can reproduce the run. A &lt;code&gt;transcripts/&lt;/code&gt; folder with what the agent actually did, because the interesting artifact is the routing rather than the result: which skill was selected, which tool it chose, whether it batched. A &lt;code&gt;solution/&lt;/code&gt; folder holding the solution exactly as &lt;code&gt;dv-solution&lt;/code&gt; unpacked it, so the environment-first workflow shows up in the diff instead of being asserted in a README. And a short &lt;code&gt;FINDINGS.md&lt;/code&gt; recording where the agent chose well and where it did not, because a lab that records only successes is marketing.&lt;/p&gt;

&lt;p&gt;Point the README at a developer environment from the Power Apps Developer Plan, which the documentation names as the appropriate nonproduction option, and say so loudly. Nobody should be learning this against production.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Final Notes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;What I keep coming back to is not the convenience. It is that the routing table is public. Microsoft has written down, in a repository you can read, which Dataverse tool it thinks you should use for which job and why. Whether or not you install the plugin, that is worth twenty minutes of your time, because it is the closest thing we have had to an official answer to a question this platform has been quietly asking developers for a decade.&lt;/p&gt;

&lt;p&gt;And it is preview, so it will change. Read the skills before you trust them, run against a developer environment first, and remember that the confirmations are guidance to the agent rather than enforcement by the platform. The enforcement is your identity&#39;s privileges, and that is the line that actually holds.&lt;/p&gt;

&lt;p&gt;What I learned from this exercise: the valuable part of an agent integration is rarely the automation. It is the accumulated judgment somebody had to write down to make the automation behave.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br/&gt;
Mariano Gomez Bent&lt;br/&gt;
Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/09/power-apps-seven-skills-one-prompt.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-4792628291846088702</guid><pubDate>Mon, 14 Sep 2026 11:00:00 +0000</pubDate><atom:updated>2026-09-14T07:00:00.115-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">DocWatch</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><title>Power Automate | Licensing the Flow Nobody Owns</title><description>&lt;!-- Cover image is hosted in the public theworkbench-assets repo. If you prefer Google-hosted
     images, re-upload the PNG through the Blogger editor before you publish. --&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;
&lt;img alt=&quot;The flow nobody owns: service principals, licensed at last&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-12-sp-flow-license.png&quot; style=&quot;max-width:100%;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;If you have done any serious application lifecycle management work in Power Platform, you know the pattern: you move flow ownership off a human being and onto a service principal, because people change roles, people leave, and a mission critical flow should not stop working because somebody&#39;s manager reassigned a license on a Tuesday. It is good practice, and I have watched it save projects.&lt;/p&gt;

&lt;p&gt;It also had a sharp edge, and in mid-August Microsoft filed it down.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Background&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Here is the edge. A service principal application user is a non-interactive user, which means you cannot assign it a license. So the moment your service principal owned flow used anything premium (a premium connector, a custom connector, an HTTP action), you had a compliance problem. Your options were a Power Automate Process license assigned to the flow itself, which requires the flow to be solution-aware, or a Process license on a flow group sharing that capacity. Both are real answers. Both cost money that, in a lot of cases, you had already spent on a perfectly good user license sitting right there.&lt;/p&gt;

&lt;p&gt;And if you did neither, the flow got suspended, with a message that will be familiar to anyone who has been on the receiving end of it:&lt;/p&gt;

&lt;blockquote&gt;This flow was suspended because flows owned by service principals are not compliant.&lt;/blockquote&gt;

&lt;p&gt;Now, as of &lt;a href=&quot;https://learn.microsoft.com/en-us/power-automate/assign-user-license-service-principal-flow&quot;&gt;a new article published on August 15, 2026&lt;/a&gt;, there is a third option: designate a licensed &lt;i&gt;user&lt;/i&gt;, and the flow runs under that user&#39;s Power Automate entitlement while the service principal remains the owner.&lt;/p&gt;

&lt;p&gt;This is not a documentation-only change. The existing &lt;a href=&quot;https://learn.microsoft.com/en-us/power-automate/service-principal-support&quot;&gt;Support for service principal owned flows&lt;/a&gt; article was edited the same week, and where it listed two licensing routes it now lists three. Two independent pages moving the same direction in the same week is usually how you tell something actually shipped.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;What you get, and what it costs you&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Designating a user license means the flow runs under that user&#39;s entitlement, and &lt;b&gt;that user&#39;s action limits apply&lt;/b&gt;. A Process license, by contrast, is capacity attached to the flow itself, entitling it to 250,000 actions per day independent of any user, and it can be shared across up to 25 flows in a flow group.&lt;/p&gt;

&lt;p&gt;So the new option is cheaper and simpler, and you pay for it in headroom. A high-volume integration flow that would chew through 250,000 daily actions is not a good candidate for somebody&#39;s personal entitlement. A nightly reconciliation flow that fires forty times a day absolutely is.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The two prerequisites that will bite you&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The first: &lt;b&gt;the designated user must be a co-owner of the flow.&lt;/b&gt; Not merely a licensed user in the tenant. A co-owner. If they are not, share the flow with them first.&lt;/p&gt;

&lt;p&gt;The second is the important one: &lt;b&gt;the user&#39;s license must cover every premium feature the flow uses.&lt;/b&gt; The documentation names premium connectors, custom connectors and HTTP actions, says a Power Automate Premium license covers these, and then says something worth reading twice: a Microsoft 365 seeded license does not, and the flow stays noncompliant if you designate a user who only has one.&lt;/p&gt;

&lt;p&gt;That is the failure mode. You designate a user, the save succeeds, the UI looks right, and the flow is still out of compliance because the person you picked has a seeded license. If you are troubleshooting a flow that stayed suspended after you &quot;fixed&quot; it, check that first.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Why it matters&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;For makers, the ALM-correct thing is no longer the expensive thing. Moving ownership to a service principal used to come with an invoice attached, and that invoice was enough to talk a lot of teams out of doing it properly. The workflow itself is short: open the flow&#39;s &lt;b&gt;Details&lt;/b&gt; page, find &lt;b&gt;User license&lt;/b&gt; in the licensing section, pick the user, save.&lt;/p&gt;

&lt;p&gt;For professional developers, two things. It is cleanly scriptable, because the designation is stored in Dataverse as the &lt;code&gt;Licensee&lt;/code&gt; column on the flow&#39;s row in the Process (&lt;code&gt;workflow&lt;/code&gt;) table, a lookup to a User (&lt;code&gt;systemuser&lt;/code&gt;) record. Setting it programmatically is, in the documentation&#39;s words, equivalent to using the Details page.&lt;/p&gt;

&lt;p&gt;And then the one I would put on a wall: the designation points to a user record in a specific environment, so &lt;b&gt;it is not carried in a solution&lt;/b&gt;. Deploying through a managed solution or a pipeline does not reapply it in the target. Think about what that means. You promote the flow to production, everything imports green, the flow turns on, and it is unlicensed there because the designation never travelled. Nothing failed. Nothing warned you. You find out when it gets suspended.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The demo concept&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;A post-deployment licensing step: one script, run after solution import, that resolves the identifiers, sets the designation, and reads it back to prove it landed. Here is the request that does the work, straight from the documentation:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;PATCH [Organization URI]/api/data/v9.2/workflows(&amp;lt;workflowId&amp;gt;) HTTP/1.1
Content-Type: application/json

{
    &quot;licensee_systemuserid@odata.bind&quot;: &quot;/systemusers(&amp;lt;systemUserId&amp;gt;)&quot;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;@odata.bind&lt;/code&gt; annotation is how the Web API sets a lookup: you are binding a reference to a row in another table, which is why the value is a path and not a bare GUID. This is a PATCH against the &lt;code&gt;workflows&lt;/code&gt; entity set, which is the Process table, because cloud flows are rows there where Category is &lt;b&gt;Modern Flow&lt;/b&gt;. You need two identifiers: the flow&#39;s &lt;code&gt;workflowid&lt;/code&gt;, which also appears in its URL in the portal, and the user&#39;s &lt;code&gt;systemuserid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Wired together, and trimmed to the essentials:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$api = &quot;$OrgUrl/api/data/v9.2&quot;
$headers = @{ Authorization = &quot;Bearer $token&quot;; &#39;Content-Type&#39; = &#39;application/json&#39; }

# Category 5 is Modern Flow. Refuse to act unless exactly one row matches.
$flows = (Invoke-RestMethod -Headers $headers -Uri
    &quot;$api/workflows?`$filter=category eq 5 and name eq &#39;$FlowName&#39;&quot;).value
if ($flows.Count -ne 1) { throw &quot;Expected 1 flow, found $($flows.Count). Refusing to guess.&quot; }

$users = (Invoke-RestMethod -Headers $headers -Uri
    &quot;$api/systemusers?`$filter=domainname eq &#39;$UserUpn&#39;&quot;).value
if ($users.Count -ne 1) { throw &quot;Expected 1 user, found $($users.Count).&quot; }

$body = @{ &#39;licensee_systemuserid@odata.bind&#39; = &quot;/systemusers($($users[0].systemuserid))&quot; } |
    ConvertTo-Json
Invoke-RestMethod -Method Patch -Headers $headers -Body $body `
    -Uri &quot;$api/workflows($($flows[0].workflowid))&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note, because there is more opinion here than code. Both lookups refuse to proceed unless they match exactly one row: a script that silently picks the first of three similarly named flows will license the wrong one and you will not find out for a month. The backticks before &lt;code&gt;$filter&lt;/code&gt; are PowerShell escapes, because &lt;code&gt;$&lt;/code&gt; starts a variable in PowerShell and OData query options genuinely begin with a dollar sign; leave them out and you send a URL with the query options silently deleted. And &lt;code&gt;$token&lt;/code&gt; is whatever your pipeline already uses to authenticate against the environment.&lt;/p&gt;

&lt;p&gt;Then verify, because a PATCH returning 204 tells you the request was accepted, not that the designation is what you wanted:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;GET [Organization URI]/api/data/v9.2/workflows(&amp;lt;workflowId&amp;gt;)?$select=name,_licensee_value HTTP/1.1
Prefer: odata.include-annotations=&quot;OData.Community.Display.V1.FormattedValue&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That &lt;code&gt;Prefer&lt;/code&gt; header is the point. Without it you get a raw GUID in &lt;code&gt;_licensee_value&lt;/code&gt; and you will spend ten minutes looking it up by hand. With it, Dataverse also returns the user&#39;s display name, and your pipeline log becomes evidence rather than a promise. The underscore-prefixed column name is the standard convention for reading a lookup&#39;s value, and it trips up everyone exactly once.&lt;/p&gt;

&lt;p&gt;To remove a designation, &lt;code&gt;DELETE&lt;/code&gt; the same path with &lt;code&gt;/licensee_systemuserid/$ref&lt;/code&gt; appended. The article notes it succeeds even when no user is designated, which makes it safe in a teardown script.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Doing it from a flow instead&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;If your deployment process is itself a cloud flow, the documentation gives this path:&lt;/p&gt;

&lt;p&gt;1) Add the &lt;b&gt;Update a row&lt;/b&gt; action from the &lt;b&gt;Microsoft Dataverse&lt;/b&gt; connector.&lt;/p&gt;

&lt;p&gt;2) In &lt;b&gt;Table name&lt;/b&gt;, select &lt;b&gt;Processes&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;3) In &lt;b&gt;Row ID&lt;/b&gt;, enter the &lt;code&gt;workflowid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;4) In &lt;b&gt;Licensee (Users)&lt;/b&gt;, enter &lt;code&gt;/systemusers(&amp;lt;systemUserId&amp;gt;)&lt;/code&gt;. If the field is not shown, select &lt;b&gt;Show advanced options&lt;/b&gt;. Leave it empty to remove the designation.&lt;/p&gt;

&lt;p&gt;NOTE: the documentation does not spell out the navigation to the flow&#39;s &lt;b&gt;Details&lt;/b&gt; page for the manual route, it simply says to open it, so I am not going to invent a click path. It is the page you land on when you select the flow by name from &lt;b&gt;My flows&lt;/b&gt; or from the solution.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Companion repo sketch&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Three scripts and a pipeline step: &lt;code&gt;Set-FlowLicensee.ps1&lt;/code&gt; as above, &lt;code&gt;Remove-FlowLicensee.ps1&lt;/code&gt; for the &lt;code&gt;$ref&lt;/code&gt; teardown, and the one that earns its keep long term, &lt;code&gt;Get-FlowLicensee.ps1&lt;/code&gt;, which lists every Modern Flow owned by an application user and reports which have a designation and which do not. That is your compliance drift report in about thirty lines. The pipeline step exists purely because the designation does not travel in a solution, so it must be reapplied per environment by something that cannot forget.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Final Notes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I like this change more than its size suggests. It removes a real disincentive to doing ALM properly, and the disincentive was purely financial rather than technical, which is the most annoying kind.&lt;/p&gt;

&lt;p&gt;If you carry away one thing: the designation is per environment and solutions do not move it. Everything else here is a five minute configuration change. That one is an architectural fact about your deployment pipeline.&lt;/p&gt;

&lt;p&gt;What I learned from this exercise: &quot;it deployed successfully&quot; and &quot;it is licensed&quot; are two different claims, and only one of them shows up green in your pipeline.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br/&gt;
Mariano Gomez Bent&lt;br/&gt;
Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/09/power-automate-licensing-flow-nobody.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-113240145197573997</guid><pubDate>Thu, 10 Sep 2026 11:00:00 +0000</pubDate><atom:updated>2026-09-10T11:50:14.581-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Copilot Studio</category><category domain="http://www.blogger.com/atom/ns#">DocWatch</category><title>Copilot Studio | Grounding a Copilot Studio Agent on Azure SQL</title><description>&lt;!-- Cover image is hosted in the public theworkbench-assets repo. If you prefer Google-hosted
     images, re-upload the PNG through the Blogger editor before you publish. --&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;
&lt;img alt=&quot;Grounding on Azure SQL: your schema is now the prompt&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-11-azuresql-knowledge.png&quot; style=&quot;max-width:100%;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Every Monday I read what moved in the Microsoft Learn documentation over the previous week, mostly because I got tired of finding out about a capability three months late, when a customer asks why we are not already using it. Most weeks the honest answer is &quot;nothing worth your time&quot;. The week of August 13th was not one of those weeks.&lt;/p&gt;

&lt;p&gt;A new article appeared in the Copilot Studio documentation, and it changes the answer to a question I have been asked more times than I can count: &lt;i&gt;can my agent answer questions straight out of my database?&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Now it can.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Background&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Until now, grounding a Copilot Studio agent meant pointing it at content that was, broadly speaking, prose: SharePoint documents, websites, uploaded files, &lt;a href=&quot;https://www.theworkbench.blog/2026/08/copilot-studio-adding-dataverse.html&quot;&gt;Dataverse tables&lt;/a&gt;. If your answer lived in a relational database in Azure, you either built a tool that queried it and shaped the result yourself, or you exported the data somewhere the agent could already read. Both work. Neither is what you would call delightful.&lt;/p&gt;

&lt;p&gt;Dataverse is the one I have spent real time on, in &lt;a href=&quot;https://www.theworkbench.blog/2026/08/copilot-studio-adding-dataverse.html&quot;&gt;an earlier article on adding those knowledge sources with the Web API&lt;/a&gt; instead of clicking them together in the maker portal. Worth keeping in mind as you read on, because Azure SQL is a different animal in one important respect: that Dataverse recipe works precisely because a Dataverse knowledge source is itself Dataverse rows, and here there is no intermediate copy of anything. Your data stays in your database.&lt;/p&gt;

&lt;p&gt;The new article is &lt;a href=&quot;https://learn.microsoft.com/en-us/microsoft-copilot-studio/agents-experience/knowledge-add-azure-sql-tables&quot;&gt;Add Azure SQL tables as a knowledge source&lt;/a&gt;. In its own words, you ground your agent in the structured data stored in your Azure SQL database, and the agent answers by reading from the tables you select.&lt;/p&gt;

&lt;p&gt;Select the tables. That is the whole configuration story. No tool authoring, no schema mapping, no intermediate copy of the data.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The part everybody will skip, and shouldn&#39;t&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;There is a security model here, and it is not the one most people will assume. Azure SQL knowledge uses the Power Platform SQL connection you create during setup, and then:&lt;/p&gt;

&lt;blockquote&gt;Users only receive answers based on data the maker can access through the maker&#39;s configured connection and database permissions.&lt;/blockquote&gt;

&lt;p&gt;Read that again. The ceiling is &lt;b&gt;the maker&#39;s&lt;/b&gt; connection, not the end user&#39;s own database rights. If you wire up a connection that can read the whole Sales schema, then every user who can talk to that agent can get answers derived from the whole Sales schema. The agent is not brokering each user&#39;s individual SQL permissions row by row.&lt;/p&gt;

&lt;p&gt;That is not a defect, it is how connection-based grounding works everywhere in Power Platform. But it does mean table selection is a &lt;i&gt;security&lt;/i&gt; decision, not just a relevance one, and I would even venture to say it is the sentence in that article most likely to be skimmed past and later regretted. Select the tables the agent needs. Not the tables you happen to have.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;What it means for you&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;If you are a maker, a whole category of question moves from &quot;that needs a developer&quot; to &quot;that needs a good description&quot;. Order status, purchase history, revenue by customer or date: ground an agent on it in an afternoon. The catch is that quality now depends on your schema. The documentation asks for clear column names over cryptic abbreviations (&lt;code&gt;CustomerName&lt;/code&gt;, not &lt;code&gt;CustNm&lt;/code&gt;), primary keys on every table, and descriptive names such as &lt;code&gt;OrderDate&lt;/code&gt; rather than &lt;code&gt;Date1&lt;/code&gt;. It also warns that extra tables dilute grounding. So, your schema quality is now prompt quality, and every badly named column you inherited is now, quite literally, a worse answer.&lt;/p&gt;

&lt;p&gt;If you are a professional developer, three things matter. The primary key requirement is not decorative: the agent uses primary keys to identify rows and return results, so heap tables will behave poorly. Network reachability is on you, and the prerequisites offer firewall rules allowing Azure services or private connectivity, the first of which will not survive most security reviews, so budget for that conversation early. And best of all, the documentation hands you a testability seam: create a diagnostic view returning a small, known dataset and confirm the connection before you point at production. That turns &quot;the agent gave a weird answer&quot; into something you can bisect in ten seconds.&lt;/p&gt;

&lt;p&gt;NOTE: the documentation hedges its own UI labels, saying you pick &lt;b&gt;Azure SQL&lt;/b&gt; &lt;i&gt;or&lt;/i&gt; &lt;b&gt;SQL Server&lt;/b&gt; &quot;depending on the label shown in your environment&quot;. I am reproducing that hedge rather than guessing.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;A demo worth building&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Something small and controlled: a three-table order schema, a diagnostic view with a known answer, and an agent grounded on exactly those tables, so you can change one thing at a time and watch what it does to answer quality. Here is the schema, written the way the documentation asks:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE TABLE dbo.Customers (
    CustomerId   INT           NOT NULL IDENTITY(1,1),
    CustomerName NVARCHAR(200) NOT NULL,
    CustomerCity NVARCHAR(100) NULL,
    CONSTRAINT PK_Customers PRIMARY KEY CLUSTERED (CustomerId)
);

CREATE TABLE dbo.Orders (
    OrderId     INT           NOT NULL IDENTITY(1,1),
    CustomerId  INT           NOT NULL,
    OrderDate   DATE          NOT NULL,
    OrderStatus NVARCHAR(40)  NOT NULL,
    OrderTotal  DECIMAL(18,2) NOT NULL,
    CONSTRAINT PK_Orders PRIMARY KEY CLUSTERED (OrderId),
    CONSTRAINT FK_Orders_Customers FOREIGN KEY (CustomerId)
        REFERENCES dbo.Customers (CustomerId)
);

CREATE TABLE dbo.OrderLines (
    OrderLineId INT           NOT NULL IDENTITY(1,1),
    OrderId     INT           NOT NULL,
    ProductName NVARCHAR(200) NOT NULL,
    Quantity    INT           NOT NULL,
    UnitPrice   DECIMAL(18,2) NOT NULL,
    LineTotal   DECIMAL(18,2) NOT NULL,
    CONSTRAINT PK_OrderLines PRIMARY KEY CLUSTERED (OrderLineId),
    CONSTRAINT FK_OrderLines_Orders FOREIGN KEY (OrderId)
        REFERENCES dbo.Orders (OrderId)
);

CREATE VIEW dbo.AgentGroundingCheck
AS
SELECT &#39;GROUNDING-OK&#39; AS DiagnosticMarker, 42 AS DiagnosticNumber;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. Every table carries an explicit primary key, because that is what the agent uses to identify rows. Every column name is a phrase a human would say out loud, and you should resist the urge to shorten them. The view at the bottom is the diagnostic seam: add it to the knowledge source, ask &quot;what is the diagnostic marker?&quot;, and you learn whether the connection works at all, independent of whether your business data is right. Pick your own marker value, and drop the view from the knowledge source before real users arrive, because it is scaffolding, not a feature.&lt;/p&gt;

&lt;p&gt;Now the description, which is not code but is configuration, and which the documentation treats as the highest-leverage text you will write:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Azure SQL knowledge for Contoso order management. Includes Customers,
Orders, and OrderLines tables. Use this source for questions about order
status, order history, customer purchases, and revenue by customer or
date. Don&#39;t use for inventory on-hand or shipping carrier tracking.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is lifted from the article&#39;s own example, and the shape is what matters: domain, tables, what to use it for, and then what &lt;b&gt;not&lt;/b&gt; to use it for. That last sentence does real work, because generative orchestration is choosing between your knowledge sources, and an exclusion is often a stronger signal than an inclusion.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The steps&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The full click path is in &lt;a href=&quot;https://learn.microsoft.com/en-us/microsoft-copilot-studio/agents-experience/knowledge-add-azure-sql-tables&quot;&gt;the source&lt;/a&gt;, and given the label hedge above I would rather you read it there than trust my transcription. These are the steps that carry a decision:&lt;/p&gt;

&lt;p&gt;1) &lt;b&gt;Prepare the database.&lt;/b&gt; Primary keys defined, readable column names, and your Azure SQL server reachable from Power Platform.&lt;/p&gt;

&lt;p&gt;2) &lt;b&gt;Select the tables deliberately.&lt;/b&gt; This is the security decision from earlier, not a relevance one.&lt;/p&gt;

&lt;p&gt;3) &lt;b&gt;Write the description properly&lt;/b&gt;, in the shape above.&lt;/p&gt;

&lt;p&gt;4) &lt;b&gt;Publish the agent.&lt;/b&gt; The knowledge source is not available in the published experience until you do, and this is exactly the step that gets skipped and then generates a bug report.&lt;/p&gt;

&lt;p&gt;5) &lt;b&gt;Test with something that must come from those tables.&lt;/b&gt; The article&#39;s own example: &quot;Show me the top five customers by total sales last month.&quot;&lt;/p&gt;

&lt;p&gt;That is still a walk through a dialog, which raises the obvious question if you read the Dataverse piece: can this one be created from code instead? I have not checked, and I am not going to guess. The connection is a Power Platform connection and the knowledge source is a row somewhere, so there is a fair chance &lt;a href=&quot;https://www.theworkbench.blog/2026/08/copilot-studio-adding-dataverse.html&quot;&gt;the same approach&lt;/a&gt; applies. But that is a hypothesis, and it belongs in a follow-up where I can show it working rather than in a paragraph where I speculate about it.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Companion repo sketch&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Four folders is plenty: &lt;code&gt;sql/&lt;/code&gt; with schema, seed, diagnostic view and teardown; &lt;code&gt;agent/&lt;/code&gt; holding the knowledge description as its own version-controlled file, because it is configuration that changes behavior and deserves a diff history; a &lt;code&gt;test-questions.md&lt;/code&gt; with three columns, the question, the expected answer, and the table the answer must come from; and &lt;code&gt;docs/&lt;/code&gt; for the network and security notes. Use fixed dates in the seed data, never dates relative to today, or &quot;last month&quot; will mean something different in March than in September and your tests will rot. That third column in the test file is the piece people leave out, and without it you cannot tell a grounding failure from a data failure.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Final Notes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This lands exactly where agents have been weakest: answering from the boring, structured, authoritative data that businesses actually run on. Slick.&lt;/p&gt;

&lt;p&gt;One caution, the same one: the maker&#39;s connection defines what every user of that agent can reach. And since the article is four days old as I write this, labels may still be moving, so trust your screen over my transcription and go read &lt;a href=&quot;https://learn.microsoft.com/en-us/microsoft-copilot-studio/agents-experience/knowledge-add-azure-sql-tables&quot;&gt;the source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What I learned from this exercise: the schema you were going to clean up &quot;someday&quot; is now on the critical path to answer quality, and that&#39;s always a good thing, because it finally gives you a business reason to do it.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br/&gt;
Mariano Gomez Bent&lt;br/&gt;
Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/09/copilot-studio-grounding-copilot-studio.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-1666200584224273562</guid><pubDate>Mon, 07 Sep 2026 11:00:00 +0000</pubDate><atom:updated>2026-09-07T09:55:23.658-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Copilot Studio</category><category domain="http://www.blogger.com/atom/ns#">DocWatch</category><title>Copilot Studio | Migrate the Agent, Keep the Client ID</title><description>&lt;!--Cover image is hosted in the public theworkbench-assets repo. If you prefer Google-hosted
     images, re-upload the PNG through the Blogger editor before you publish.--&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img alt=&quot;Migrate the agent, keep the client ID: Copilot Studio agents move to Microsoft Entra Agent ID&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-16-entra-agent-id.png&quot; style=&quot;max-width: 100%;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;There is a question I have been asked in one form or another by every administrator who has ever inherited a tenant full of Copilot Studio agents, and it always arrives with the same slightly worried tone: &quot;what are all these app registrations in Entra, and which agent does each one belong to?&quot; It is a fair question. For years the answer was that Copilot Studio quietly provisioned an Azure app registration for every agent you created, those registrations piled up in Microsoft Entra ID looking exactly like every other application in the tenant, and telling them apart was an exercise in cross-referencing GUIDs. Not exactly a governance story.&lt;/p&gt;

&lt;p&gt;Well, in late August three articles landed in the Copilot Studio documentation that finally close that loop, and one of them is the migration runbook administrators have been waiting for.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Background&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Two brand new pages and one substantially rewritten page, all last updated on August 27, 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/microsoft-copilot-studio/govern-agents-identities-overview&quot;&gt;Agent identities and authentication for Copilot Studio&lt;/a&gt;, new, a plain-language explainer written as a set of questions.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/microsoft-copilot-studio/govern-migrate-api-entra-agent-identity&quot;&gt;Migrate Copilot Studio agents to Microsoft Entra Agent ID&lt;/a&gt;, new, and the reason for this post.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/microsoft-copilot-studio/admin-use-entra-agent-identities&quot;&gt;Microsoft Entra Agent IDs for Copilot Studio agents&lt;/a&gt;, rewritten with the migration guidance and the transition-period rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, the model itself, because the terminology is new and worth pinning down before anything else. A &lt;b&gt;Microsoft Entra Agent ID&lt;/b&gt; is a Microsoft Entra service principal with an &quot;Agent&quot; subtype. That is the whole definition. It is not a new protocol and not a new token type. The documentation is careful about this: the underlying OAuth-based authentication flow remains the same. What changes is that the agent is now a first-class object in Entra that an administrator can see, govern, and write policy against, rather than an anonymous app registration sitting in a list of four hundred others.&lt;/p&gt;

&lt;p&gt;Copilot Studio has been creating these automatically for every new agent since May 2026. Agents created before that date still carry the legacy app registration, and here is the sentence that turns this from trivia into a project: existing agents will be migrated by Microsoft automatically in a future update. So the migration is happening either way. The only decision in front of you is whether it happens on your schedule or on Microsoft&#39;s.&lt;/p&gt;

&lt;p&gt;NOTE: one other thing changed in the same rewrite and it is easy to miss. Previously you could opt out of Entra Agent ID at the environment level. That option is gone. All new agents get Microsoft Entra Agent IDs and you can no longer opt out of automatic agent identity creation. There is also now a tenant-level object called the &lt;b&gt;Microsoft Copilot Studio agent identity blueprint&lt;/b&gt;, added the first time an agent is created after the rollout, with a corresponding blueprint principal.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Solution: an in-place conversion with a rollback&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Here is the design decision worth slowing down for, and it is the one that makes the whole thing usable in a real tenant.&lt;/p&gt;

&lt;p&gt;Migration converts an agent&#39;s existing app-registration identity &lt;i&gt;in place&lt;/i&gt;. The agent keeps its application (client) ID. Everything downstream that resolves against that identifier, channel registrations and connectors among them, continues to resolve to the same value. The agent additionally gains an Entra Agent ID that administrators can manage.&lt;/p&gt;

&lt;p&gt;You may be asking why that detail deserves its own paragraph. Frankly, the answer is simple: the alternative would have been catastrophic. An identity migration that issued a new client ID would break every channel registration, every connector configuration, and every downstream system that had that GUID written into a config file somewhere, all at once, across an entire estate. Keeping the client ID is what turns &quot;a migration nobody will ever run&quot; into &quot;a migration you can pilot on Tuesday.&quot;&lt;/p&gt;

&lt;p&gt;And it is reversible. There is a documented rollback that reverts an agent to its legacy app-registration identity, which means you can validate an agent after migrating it and put it back if it does not pass. A migration path with a documented way back is a rarer thing than it should be, and whoever fought for it deserves the credit.&lt;/p&gt;

&lt;p&gt;What you get in exchange for the trip: a first-class agent identity that administrators can view and govern in Microsoft Entra, Conditional Access and other access policies designed for agentic workloads and &lt;i&gt;scoped to agents&lt;/i&gt; rather than inherited from app registrations, and a consistent identity model across the services that work with your agents. The Conditional Access point is the substantive one. Writing a policy that targets agents specifically, rather than catching them incidentally because they happen to be applications, is a capability that did not exist before.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Why it matters&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;For &lt;b&gt;makers&lt;/b&gt;, the honest answer is that this is not your job, but it will land on your calendar anyway. The documented process explicitly requires the administrator to coordinate a validation window with the makers who own the agents being migrated, and to wait for those makers to test before the next batch goes. If you own an agent, expect to be asked to exercise it across every channel it publishes to, run its actions and connectors, and confirm its authentication still behaves. Say yes and block the time. The alternative is finding out during the automatic migration, with nobody watching.&lt;/p&gt;

&lt;p&gt;For &lt;b&gt;professional developers and administrators&lt;/b&gt;, there are two pieces of work here. The near one is the pilot: identify eligible agents, migrate a representative handful, validate, expand. The further one is Conditional Access, and it is the more interesting of the two. Once agents are first-class identities in Entra, &quot;which policies apply to our agents&quot; becomes a question with an actual answer, and the documentation tells you to review Microsoft Entra sign-in logs including Conditional Access results before you widen a batch. That is a sentence with real work behind it, and it is the part I would start reading up on now rather than during the migration.&lt;/p&gt;

&lt;p&gt;Two cautions, both from the documentation rather than invented by me. The manual migration process is currently a &lt;b&gt;preview&lt;/b&gt; feature. And the documentation states plainly that migrating agent identities affects live agents and can disrupt authentication, connectors, and integrations if you do not plan the migration carefully. This is not a maintenance-window-free operation dressed up as one.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The demo concept&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Not &quot;watch an agent get migrated,&quot; because the interesting part of a successful migration is that nothing visible happens. The demonstration worth building is the &lt;b&gt;evidence trail&lt;/b&gt;, and it has three parts.&lt;/p&gt;

&lt;p&gt;Take one noncritical agent. Before you touch it, capture its application (client) ID and its Entra sign-in log entries. Migrate it through the API so you get the response object rather than a screen full of green checkmarks. Then capture the same two things again and put them side by side: the client ID identical, the agent now present in Entra as a service principal with the Agent subtype, and a sign-in log you can point a Conditional Access policy at. That before-and-after pair is the artifact that gets a change advisory board to approve the rest of the estate, and it is far more persuasive than any amount of documentation quoting.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Steps to recreate&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;First, the prerequisites, because two of them will stop you cold. You must be a &lt;b&gt;Power Platform Administrator&lt;/b&gt;, &lt;b&gt;Dynamics 365 Administrator&lt;/b&gt;, or &lt;b&gt;Global Administrator&lt;/b&gt;. Power Platform inventory must be enabled for your tenant, because that is how Advisor identifies eligible agents. And you must coordinate a validation window with the makers who own the agents. That third one is not a technical prerequisite, but the documentation lists it as one, and I would treat it exactly that way.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The administrator path, through the Power Platform admin center&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;1) Sign in to the Power Platform admin center.&lt;br /&gt;
2) In the left navigation pane, select &lt;b&gt;Actions&lt;/b&gt;.&lt;br /&gt;
3) Under &lt;b&gt;Actions&lt;/b&gt;, select &lt;b&gt;Recommendations&lt;/b&gt;.&lt;br /&gt;
4) On the &lt;b&gt;Recommendations&lt;/b&gt; tab, select &lt;b&gt;Active&lt;/b&gt;.&lt;br /&gt;
5) Search for and select &lt;b&gt;Migrate Copilot Studio agents to Microsoft Entra Agent ID for enhanced agent governance&lt;/b&gt;.&lt;br /&gt;
6) In the recommendation pane, expand &lt;b&gt;Why is this important?&lt;/b&gt; and read the migration guidance.&lt;br /&gt;
7) Review the eligible agents. Use the &lt;b&gt;Suggested migration order&lt;/b&gt; and &lt;b&gt;Migration notes&lt;/b&gt; columns to pick your pilot, and note that the table also gives you environment, environment type, owner, recent activity, and authentication method.&lt;br /&gt;
8) Select the checkbox next to each agent you want to migrate. The &lt;b&gt;Migrate&lt;/b&gt; button becomes available and the action bar shows how many agents you have selected.&lt;br /&gt;
9) Select &lt;b&gt;Migrate&lt;/b&gt;, review the confirmation, and confirm.&lt;br /&gt;
10) Review the &lt;b&gt;Action&lt;/b&gt;, &lt;b&gt;Action state&lt;/b&gt;, and &lt;b&gt;Action date&lt;/b&gt; columns for each agent. The &lt;b&gt;Action history&lt;/b&gt; tab shows actions across all recommendations.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio6Hvw2FB0EwA2jYruOhlNK9QuFHi4gQ0lE9s0oYbX6zlKDgRCdni8179FjeyKlaH_3W6L8aUGgC0ef1DoDUGr4tGp4Gp4kKWYjuD-UDbTi0oOvrOJ6FtuM3MgKNPHmHdUZSpZhQtKq8tuxKU0oOSs_N_uVSYiCQ9yITgtOmn7IzQHYzBgwLrddkzd9jXa/s1908/Screenshot%202026-09-07%20094808.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1065&quot; data-original-width=&quot;1908&quot; height=&quot;365&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio6Hvw2FB0EwA2jYruOhlNK9QuFHi4gQ0lE9s0oYbX6zlKDgRCdni8179FjeyKlaH_3W6L8aUGgC0ef1DoDUGr4tGp4Gp4kKWYjuD-UDbTi0oOvrOJ6FtuM3MgKNPHmHdUZSpZhQtKq8tuxKU0oOSs_N_uVSYiCQ9yITgtOmn7IzQHYzBgwLrddkzd9jXa/w653-h365/Screenshot%202026-09-07%20094808.png&quot; width=&quot;653&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Power Platform Admin Center&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;p&gt;Then stop. Do not queue the next batch. Validate first, and the documentation is specific about what validating means: confirm the agent responds correctly in every channel where it is published, that its actions, connectors, flows and integrations run, that it authenticates as expected including any custom authentication, and that it behaves correctly with applicable agent access policies and Conditional Access policies. Then go read the sign-in logs for those agents in the Microsoft Entra admin center. If an agent fails validation, stop the rollout and revert that agent before continuing.&lt;/p&gt;

&lt;p&gt;Keep in mind that Advisor recommendations can remain visible for up to a week after you act on them while the recommendation data refreshes. Seeing the recommendation still sitting there does not mean your migration did not take.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The API path, for when you want your own automation&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The admin center is the recommended manual method, but there are Power Platform API endpoints if you would rather script it, and the documentation supplies the samples. Everything needs an OAuth2 bearer token for the Power Platform API:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$token = (Get-AzAccessToken -ResourceUrl &quot;https://api.powerplatform.com&quot;).Token&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. This uses the Az PowerShell module, and the token has to be associated with an account holding one of the three admin roles listed earlier. There is no service-principal shortcut documented here, so if multifactor authentication or Conditional Access requires interactive sign-in, expect a browser window and complete the prompts. This is also the single most common failure in the troubleshooting table, listed as expired credentials or a token error.&lt;/p&gt;

&lt;p&gt;To migrate one agent:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$token = (Get-AzAccessToken -ResourceUrl &quot;https://api.powerplatform.com&quot;).Token
$environmentId = &quot;&amp;lt;EnvironmentId&amp;gt;&quot;
$botId = &quot;&amp;lt;BotId&amp;gt;&quot;
$uri = &quot;https://api.powerplatform.com/copilotstudio/environments/$environmentId/bots/$botId/api/agentidentitymigration/migrate?api-version=2024-10-01&quot;
Invoke-RestMethod `
  -Method Post `
  -Uri $uri `
  -Headers @{
    Authorization = &quot;Bearer $token&quot;
  }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. The request takes &lt;b&gt;no body&lt;/b&gt;, which surprised me the first time I read it: the agent is fully identified by the two IDs in the path. You get those two values from the agent inventory in the Power Platform admin center under &lt;b&gt;Manage&lt;/b&gt; &amp;gt; &lt;b&gt;Copilot Studio&lt;/b&gt;. The API version is pinned at &lt;code&gt;2024-10-01&lt;/code&gt;, so keep it, and note that this endpoint lives on &lt;code&gt;api.powerplatform.com&lt;/code&gt; rather than any Copilot Studio host. The response is an &lt;code&gt;AgentIdentityMigrationResult&lt;/code&gt; with a status of either &lt;code&gt;Migrated&lt;/code&gt; or &lt;code&gt;AlreadyMigrated&lt;/code&gt;, which means the call is safely idempotent. Running it twice does not do the migration twice, and that matters a great deal if you are looping over a list of agents and something times out halfway through.&lt;/p&gt;

&lt;p&gt;A successful response looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;status&quot;: &quot;Migrated&quot;,
  &quot;cdsBotId&quot;: &quot;&amp;lt;bot-id&amp;gt;&quot;,
  &quot;environmentId&quot;: &quot;&amp;lt;environment-id&amp;gt;&quot;,
  &quot;tenantId&quot;: &quot;&amp;lt;tenant-id&amp;gt;&quot;,
  &quot;agentIdentityId&quot;: &quot;&amp;lt;agent-identity-id&amp;gt;&quot;,
  &quot;applicationId&quot;: &quot;&amp;lt;application-client-id&amp;gt;&quot;,
  &quot;servicePrincipalObjectId&quot;: &quot;&amp;lt;service-principal-object-id&amp;gt;&quot;,
  &quot;managedIdentityId&quot;: &quot;&amp;lt;managed-identity-id&amp;gt;&quot;,
  &quot;completedAtUtc&quot;: &quot;2026-08-21T12:00:00Z&quot;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note, and this payload is the reason I would use the API even if I ran the migration from the admin center. Look at what comes back: &lt;code&gt;applicationId&lt;/code&gt;, the client ID you can compare against what you captured before, and &lt;code&gt;servicePrincipalObjectId&lt;/code&gt; and &lt;code&gt;agentIdentityId&lt;/code&gt;, the handles you need to find this agent in Entra afterward. Log the whole object. It is your evidence trail, produced for free, and reconstructing it later from the portal is tedious work you would rather not do.&lt;/p&gt;

&lt;p&gt;And to put one back:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$uri = &quot;https://api.powerplatform.com/copilotstudio/environments/$environmentId/bots/$botId/api/agentidentitymigration/rollback?api-version=2024-10-01&quot;
Invoke-RestMethod `
  -Method Post `
  -Uri $uri `
  -Headers @{
    Authorization = &quot;Bearer $token&quot;
  }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. Same shape, same authentication, same absence of a body, and the same idempotent design: the response status is &lt;code&gt;RolledBack&lt;/code&gt; or &lt;code&gt;NotMigrated&lt;/code&gt;. Write this script at the same time you write the migrate script, not after something has gone wrong. A rollback you have already tested on a throwaway agent is a rollback you can actually reach for at four in the afternoon with a maker on the phone.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Companion repo sketch&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;A small runbook repository, honest about being a runbook. A &lt;code&gt;scripts/&lt;/code&gt; folder with three files and no more: &lt;code&gt;Get-AgentInventory.ps1&lt;/code&gt; to pull the agents and their environment and bot IDs, &lt;code&gt;Invoke-AgentMigration.ps1&lt;/code&gt; that takes a CSV of the batch and writes every response object to disk, and &lt;code&gt;Invoke-AgentRollback.ps1&lt;/code&gt; written first and tested first. A &lt;code&gt;batches/&lt;/code&gt; folder with the CSV per batch, so the pilot, the second wave and the long tail are separate committed files rather than a spreadsheet somebody is editing in place. An &lt;code&gt;evidence/&lt;/code&gt; folder holding the before-and-after client IDs and the raw JSON responses, because that is the artifact that survives the project. And a &lt;code&gt;VALIDATION.md&lt;/code&gt; with the checklist from the documentation turned into tick boxes per agent: channels, actions, connectors, flows, integrations, custom authentication, access policies, Conditional Access.&lt;/p&gt;

&lt;p&gt;Point the README at a nonproduction tenant for the first run and say so in bold. And put the troubleshooting table in there too, because the four failure modes Microsoft documents are the four you will hit: inventory returning no agents when Power Platform inventory is not enabled or your role is wrong, token and reauthentication prompts, agents skipped because they are already migrated or you left out an ID, and single-agent failures from eligibility, access, or throttling, where the answer is to wait and rerun.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Final Notes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;What I keep coming back to is not the identity model, welcome as it is. It is that Microsoft shipped the migration runbook &lt;i&gt;and&lt;/i&gt; the rollback &lt;i&gt;and&lt;/i&gt; a troubleshooting table with four named failure modes, for a migration it is eventually going to run for you anyway. It did not have to do any of that. It could have flipped the switch on a Tuesday and let us all find out.&lt;/p&gt;

&lt;p&gt;So take the invitation. Enable Power Platform inventory, open the Advisor recommendation, pick three agents nobody will miss, and run the pilot while the stakes are zero and the makers are available. The version of this project where you go first is a much better project than the version where you go last.&lt;/p&gt;

&lt;p&gt;What I learned from this exercise: the most valuable sentence in a migration document is rarely the one describing the migration. It is the one telling you how to undo it.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;
Mariano Gomez Bent&lt;br /&gt;
Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/09/copilot-studio-migrate-agent-keep.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio6Hvw2FB0EwA2jYruOhlNK9QuFHi4gQ0lE9s0oYbX6zlKDgRCdni8179FjeyKlaH_3W6L8aUGgC0ef1DoDUGr4tGp4Gp4kKWYjuD-UDbTi0oOvrOJ6FtuM3MgKNPHmHdUZSpZhQtKq8tuxKU0oOSs_N_uVSYiCQ9yITgtOmn7IzQHYzBgwLrddkzd9jXa/s72-w653-h365-c/Screenshot%202026-09-07%20094808.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-8604335111466068845</guid><pubDate>Fri, 04 Sep 2026 11:00:00 +0000</pubDate><atom:updated>2026-09-04T07:00:00.113-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">DocWatch</category><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><title>Power Apps | Describe the App, Approve the Plan</title><description>&lt;!-- Cover image is hosted in the public theworkbench-assets repo. If you prefer Google-hosted
     images, re-upload the PNG through the Blogger editor before you publish. --&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;
&lt;img alt=&quot;Describe the app, approve the plan: the model app builder skill for Power Apps&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-15-model-app-builder.png&quot; style=&quot;max-width:100%;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Every one of us who has stood up a model-driven app from nothing has lived the same first afternoon. You know the business process cold, you could describe it to a colleague in ninety seconds, and yet the next four hours go to clicking: a table, then its columns, then the relationships, then a main form, then two views, then a chart nobody asked for, then the sitemap, then the security roles you will get wrong the first time and fix on Thursday. None of that is thinking. It is transcription, and it is the reason so many good internal apps never get built at all.&lt;/p&gt;

&lt;p&gt;Well, in late August a new article appeared in the Power Apps documentation that goes after that first afternoon directly, and it did not arrive alone.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Background&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;A brand new page landed in the &lt;code&gt;MicrosoftDocs/powerapps-docs&lt;/code&gt; repository, dated 08/27/2026, and it is live on Learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/model-driven-apps/model-driven-app-external-tools&quot;&gt;Build and edit model-driven apps with AI code generation tools (preview)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What tells you this is a real shipped surface rather than a stray draft is the company it keeps. In the same set of changes, &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/model-driven-apps/app-building-steps&quot;&gt;Steps to building a model-driven app&lt;/a&gt; and the &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/model-driven-apps/app-designer-overview&quot;&gt;Overview of the model-driven app designer&lt;/a&gt; both gained a TIP block pointing at the new article, the existing &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/model-driven-apps/generative-page-external-tools&quot;&gt;generative pages&lt;/a&gt; article gained a NOTE telling you which of the two skills to reach for, and the maker landing page and table of contents were amended to carry it. Microsoft does not wire four existing articles into a page it is not serious about.&lt;/p&gt;

&lt;p&gt;Now, the thing itself. It is called the &lt;b&gt;model app builder skill&lt;/b&gt;, and it runs inside an AI code generation tool such as GitHub Copilot CLI or Claude Code. A &lt;b&gt;skill&lt;/b&gt;, in this context, is a packaged set of instructions and commands that teaches one of those tools how to perform a specific job. It is not a connector, and it is not a service you call. It is guidance the tool loads, plus the command-line plumbing to act on it. The distinction matters, because it means everything the skill does, it does as &lt;i&gt;you&lt;/i&gt;, through tools you already have authenticated on your own machine.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;What the skill actually produces&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This is the part that surprised me, so let me quote the capability list rather than paraphrase it into something vaguer. The documentation says the skill can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a model-driven app from a description of a business scenario.&lt;/li&gt;
&lt;li&gt;Plan the app around user personas and the jobs they need to accomplish.&lt;/li&gt;
&lt;li&gt;Create supporting tables, columns, relationships, forms, views, charts, and sample data.&lt;/li&gt;
&lt;li&gt;Create generative pages for experiences that go beyond standard forms and views.&lt;/li&gt;
&lt;li&gt;Create a sitemap with custom icons for each table.&lt;/li&gt;
&lt;li&gt;Add JavaScript validation rules to forms.&lt;/li&gt;
&lt;li&gt;Add security roles based on the planned personas and data access needs.&lt;/li&gt;
&lt;li&gt;Edit an existing model-driven app by describing the changes you want.&lt;/li&gt;
&lt;li&gt;Verify the deployed app against the approved specification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read that list twice. Security roles derived from personas. Sitemap icons and form validation created as &lt;b&gt;web resources&lt;/b&gt; and wired to the right components during implementation. That is not a scaffolder producing a table and a form and calling it an app. That is the boring 80 percent of the first afternoon, including the parts people skip.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Solution: the dry run is the whole feature&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Here is where I would slow down, because the interesting design decision is not the generation. It is the gate in front of the generation.&lt;/p&gt;

&lt;p&gt;The skill runs an interactive, multistep process, and the documentation is explicit about the order. You describe the business scenario, and the skill asks follow-up questions about users, data, workflows and the experience you want. It then presents an &lt;b&gt;app spec&lt;/b&gt;: personas, jobs to be done, tables, relationships, forms, views, charts, JavaScript validation rules, generative page intents, and the sitemap with a proposed icon for each table. You review and refine that specification. Only then does it validate the spec and present a &lt;b&gt;dry-run build plan&lt;/b&gt;, grouped by build phase, in the conversation. And then the sentence that carries the whole design:&lt;/p&gt;

&lt;blockquote&gt;No app artifacts are created until you approve the plan.&lt;/blockquote&gt;

&lt;p&gt;You may be asking why a plan step deserves this much attention when every generator ever built has had a preview mode. Very simple: the failure mode of an AI that writes to Dataverse is not a bad form. It is thirty artifacts you did not ask for, scattered across a solution, with a publisher prefix on all of them and no obvious way to tell which ones matter. A plan you can read and argue with before anything is written is the difference between a tool you can use in a real environment and a tool you can only use in a sandbox you are willing to throw away.&lt;/p&gt;

&lt;p&gt;After the build, there is an optional verification step that compares the deployed app with the approved app spec. That is worth noticing too. &quot;The build reported success&quot; and &quot;the app matches what I approved&quot; are two different claims, and only one of them is worth anything on Monday morning.&lt;/p&gt;

&lt;p&gt;NOTE: the editing path is the same skill and it works in reverse. Point it at an existing app and it retrieves the deployed app, builds an &lt;i&gt;editable app spec&lt;/i&gt; from it, and then proposes changes against that spec. Which means the spec is not just an input format. It is a two-way representation of the app, and that is the part of this design most likely to still be here in three years.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Why it matters&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;For &lt;b&gt;makers&lt;/b&gt;, this is genuinely for you, and that is a change from most of what lands in the developer docs. The article is tagged for makers and developers both, and the entry point is a sentence about your business process rather than a table designer. But be honest with yourself about the toolchain: this needs Node.js, the Power Platform CLI, the Azure CLI, and a terminal-based AI coding tool on your machine. If you have never opened a command prompt on purpose, the skill is not the barrier. The prerequisites are. That is a fair trade to know about up front rather than discover forty minutes in.&lt;/p&gt;

&lt;p&gt;For &lt;b&gt;professional developers&lt;/b&gt;, the claim worth weighing is the app spec. We have spent years arguing about how to describe a model-driven app in a form that survives review, diffing and source control, and the answers have all been either solution XML, which nobody enjoys reading, or a wiki page that goes stale in a week. A reviewable specification that generates the app and can be regenerated from the app is a different proposition. Whether the schema holds up is an open question, and the documentation says plainly that it might change between releases, but the shape is right.&lt;/p&gt;

&lt;p&gt;Two cautions, both taken from the documentation rather than invented by me. This is &lt;b&gt;preview&lt;/b&gt;, and Microsoft states that the app spec schema and command-line options might change between releases. And the skill does not support every model-driven app artifact or concept, so some of your app will still be built in the designers. The related warning is the one I would put on a sticky note: changes you make outside the skill can affect later AI-assisted edits, so before you approve another build, read the plan to confirm it preserves your manual customizations. An agent that regenerates from a spec has no idea what you changed by hand unless the spec caught it.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The demo concept&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Not &quot;watch it build an app,&quot; because a video of artifacts appearing proves nothing about whether they were the right artifacts. The demonstration worth building is the &lt;b&gt;round trip&lt;/b&gt;, and it takes three moves.&lt;/p&gt;

&lt;p&gt;Build a small app from a prompt and keep the approved app spec. Then go into Power Apps and change something by hand that the spec never knew about, a business rule, a column on a form, a tweaked view. Then ask the skill for an unrelated change and read the new plan carefully to see whether your manual work survives. That single observation is more useful than any amount of generation footage, because it answers the only question a working developer actually has: can I use this on an app I care about, or only on one I am willing to lose?&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Steps to recreate&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;1) Get the prerequisites in place first. The documentation lists a current long-term support version of &lt;b&gt;Node.js&lt;/b&gt;, &lt;b&gt;Power Platform CLI (PAC CLI) 2.7.0 or later&lt;/b&gt;, the latest &lt;b&gt;Azure CLI&lt;/b&gt;, and &lt;b&gt;GitHub Copilot CLI&lt;/b&gt; or &lt;b&gt;Claude Code&lt;/b&gt;. You also need a Power Platform environment where you can create and modify Dataverse and model-driven app artifacts, an authenticated PAC CLI profile pointed at that environment, and an authenticated Azure CLI session.&lt;/p&gt;

&lt;p&gt;2) Make sure both authentications are the same person. This is the one prerequisite that reads like a footnote and behaves like a blocker:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;az login&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. The documentation is specific that you run &lt;code&gt;az login&lt;/code&gt; with &lt;i&gt;the same identity used by the active PAC CLI profile&lt;/i&gt;. Two different accounts across the two CLIs is the classic way to get a confusing permission error much later in the run, long after you have forgotten which account each tool holds. Check the active PAC profile with &lt;code&gt;pac auth list&lt;/code&gt; before you start, and if the two do not match, fix it now rather than at step six.&lt;/p&gt;

&lt;p&gt;3) Install the plugin. There is a one-line installer that sets up all of the Power Platform plugins at once, in PowerShell:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;iwr https://raw.githubusercontent.com/microsoft/power-platform-skills/main/scripts/install.js -OutFile install.js; node install.js; del install.js&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. This downloads a JavaScript file, runs it with Node, and deletes it, which is exactly the kind of command you should read before you run. The installer detects which supported AI code generation tools you have, registers the Power Platform Skills marketplace, installs the plugins, and turns on automatic updates. The source lives in the public &lt;a href=&quot;https://github.com/microsoft/power-platform-skills&quot;&gt;microsoft/power-platform-skills&lt;/a&gt; repository, so you can read &lt;code&gt;scripts/install.js&lt;/code&gt; first, and I would encourage you to do exactly that. There is an equivalent for a Windows command window:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -fsSL https://raw.githubusercontent.com/microsoft/power-platform-skills/main/scripts/install.js | node&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;4) Or install just the one plugin, which is what I would do the first time. These are slash commands typed into the AI coding tool&#39;s own chat, not shell commands:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/plugin marketplace add microsoft/power-platform-skills
/plugin install model-apps@power-platform-skills&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. The first command registers the marketplace, the second installs the Power Apps plugin from it, and the part after the &lt;code&gt;@&lt;/code&gt; is the marketplace name. Restart the tool afterward if it does not pick up the plugin on its own. For Claude Code specifically, the documentation points out that plugins can be installed at global, local or user scope, and that depending on the scope you must be in the correct directory for the plugin to load. If the skill appears to be missing, check where you are standing before you reinstall anything.&lt;/p&gt;

&lt;p&gt;5) Build something. Start a conversation with the tool and invoke the skill:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/app-builder

Build an equipment inspection app for field technicians and dispatchers.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. That example prompt is quoted from the documentation, along with &quot;Build an app to manage supplier onboarding and contract approvals&quot; and &quot;Create a model-driven app for tracking service requests across multiple teams.&quot; Notice the shape they all share: a business process and the people in it, not a list of tables. That is deliberate, because personas are a first-class part of the app spec and they are what the security roles get derived from. You can also skip &lt;code&gt;/app-builder&lt;/code&gt; and simply describe the app you want.&lt;/p&gt;

&lt;p&gt;6) Then work the review, which is the part that earns the whole exercise. Answer the skill&#39;s questions about the process, users, data and workflows. Read the app spec and check that the personas, jobs to be done, tables, relationships, forms, views, charts, validation rules, generative pages, navigation and sitemap icons actually support the business scenario, and ask for revisions until they do. Read the dry-run build plan and approve it only when its proposed changes match your intent. Let it build. Take the optional verification step. Then open the app at &lt;a href=&quot;https://make.powerapps.com&quot;&gt;make.powerapps.com&lt;/a&gt;, run its primary scenarios, and inspect the generated artifacts with your own eyes.&lt;/p&gt;

&lt;p&gt;7) To edit an app you already have, invoke &lt;code&gt;/app-builder&lt;/code&gt; again and name it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/app-builder

Add an Invoices table and related forms and views to the Supplier Management app.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note. The skill asks you to confirm which existing app it should retrieve, then presents an editable app spec built from the deployed app, and then the same plan-and-approve cycle applies. This is the path where the caution about manual customizations bites, so read that plan properly rather than skimming for the word &quot;success.&quot;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;One more thing that landed in the same set of changes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The generative pages article picked up a genuinely useful capability that has nothing to do with AI coding tools, and it would be a shame to let it get buried: you can now &lt;b&gt;embed a generative page inside a model-driven app form&lt;/b&gt;, in a section or a tab. Create and publish a generative page set up to accept the &lt;code&gt;recordId&lt;/code&gt; input parameter, then:&lt;/p&gt;

&lt;p&gt;1) Open the form in the form designer.&lt;br/&gt;
2) In the left pane, select &lt;b&gt;Components&lt;/b&gt;, and then expand &lt;b&gt;Display&lt;/b&gt;.&lt;br/&gt;
3) Select &lt;b&gt;Generative page&lt;/b&gt;.&lt;br/&gt;
4) Select the generative page you want to embed.&lt;br/&gt;
5) Optionally, provide values for any additional static inputs the page accepts.&lt;br/&gt;
6) Save and publish the form.&lt;/p&gt;

&lt;p&gt;When a user opens a record, the form passes the current record ID to the page as &lt;code&gt;recordId&lt;/code&gt; automatically. You do not configure a static value for it. That is a small paragraph in the docs and a fairly large door, because it turns generative pages from a separate destination into something that lives on the record the user is already looking at.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Companion repo sketch&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;A lab repository built around the round trip rather than the generation. A &lt;code&gt;prompts/&lt;/code&gt; folder with the exact prompts in order, so somebody else can reproduce the run instead of taking your word for it. A &lt;code&gt;specs/&lt;/code&gt; folder holding the approved app spec from the first build and the regenerated spec from after the manual edit, because the diff between those two files &lt;i&gt;is&lt;/i&gt; the finding. A &lt;code&gt;plans/&lt;/code&gt; folder with the dry-run build plans exactly as they appeared, including the one you rejected, since a lab that records only the approved plan is hiding the interesting half. A &lt;code&gt;solution/&lt;/code&gt; folder with the exported and unpacked solution so the generated artifacts show up as reviewable files. And a short &lt;code&gt;FINDINGS.md&lt;/code&gt; that says which artifacts the skill got right, which it missed, and whether the manual customization survived, in plain language.&lt;/p&gt;

&lt;p&gt;Point the README at a developer environment, say so loudly, and repeat it. This is preview software that writes schema. Nobody should be pointing it at production to find out what it does.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Final Notes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;What I keep coming back to is that the headline feature of this skill is a document. Not the generation, which is impressive but is the part everybody expected. The app spec is the thing: a reviewable description of a model-driven app, produced from a conversation, editable by a human, capable of building the app and capable of being rebuilt from it. We have wanted that artifact for a very long time, and it is a little funny that it arrives as a side effect of teaching a coding agent to click the designers for us.&lt;/p&gt;

&lt;p&gt;It is preview, so treat it accordingly. Read the installer before you run it, keep your two CLI logins on the same identity, use a developer environment, and read every plan before you approve it. And if you take one habit from the whole exercise, make it the verification step, because the gap between &quot;it built&quot; and &quot;it matches what I approved&quot; is where every automation story eventually gets interesting.&lt;/p&gt;

&lt;p&gt;What I learned from this exercise: when a tool asks you to approve a plan, the plan is not a formality it added to be polite. It is the tool telling you exactly where the responsibility moves from the machine back to you.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br/&gt;
Mariano Gomez Bent&lt;br/&gt;
Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/09/power-apps-describe-app-approve-plan.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-5958214116179228133</guid><pubDate>Mon, 31 Aug 2026 11:00:00 +0000</pubDate><atom:updated>2026-08-31T07:00:00.121-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ALM</category><category domain="http://www.blogger.com/atom/ns#">Copilot Studio</category><category domain="http://www.blogger.com/atom/ns#">MCP</category><category domain="http://www.blogger.com/atom/ns#">Open Source</category><category domain="http://www.blogger.com/atom/ns#">pac CLI</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><title>Copilot Studio | Turning War Stories into Guardrails: Introducing pac-copilot-kit</title><description>&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Turning war stories into guardrails: building pac-copilot-kit&quot; height=&quot;630&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-10-pac-copilot-kit.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1200&quot; /&gt;&lt;/div&gt;

&lt;p&gt;Let me start with the announcement, because some of you came for the tool and not the story, and that is perfectly fine.&lt;/p&gt;

&lt;p&gt;Today I am releasing &lt;strong&gt;pac-copilot-kit&lt;/strong&gt;, open source under MIT at &lt;a href=&quot;https://github.com/dgpblogster/pac-copilot-kit&quot;&gt;github.com/dgpblogster/pac-copilot-kit&lt;/a&gt;. It is a paved-road toolkit for the Copilot Studio agent lifecycle, and it does exactly two things. First, capability: it creates Dataverse knowledge sources from code, inside your solution, repeatably, which is the one thing &lt;code&gt;pac&lt;/code&gt; cannot do at all. Second, the paved road: it makes Microsoft&#39;s own ALM prescription executable, one guarded command from YAML on disk to a published agent, in a shell or in CI. The first is why you install it. The second is why you keep it.&lt;/p&gt;

&lt;p&gt;The PowerShell module is on the PowerShell Gallery as &lt;code&gt;PacCopilotKit&lt;/code&gt;, and an MCP server that exposes the same engine to Claude Code, GitHub Copilot, or Codex is on npm as &lt;code&gt;pac-copilot-kit-mcp&lt;/code&gt;. Two commands and you are running:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Install-Module PacCopilotKit
npx -y pac-copilot-kit-mcp   # optional: the MCP door, for your AI agent&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Issues and pull requests are welcome, and the war-stories document in the repository is the living inventory of every gotcha the tool guards against. If that is all you needed, go build something and let me know how it goes!&lt;/p&gt;

&lt;p&gt;Now, if you brought popcorn, stay for the rest, because the story of &lt;em&gt;why&lt;/em&gt; this tool exists is the more interesting half, and it includes one moment where the build caught its own author in an overclaim.&lt;/p&gt;

&lt;h2&gt;Where it came from&lt;/h2&gt;

&lt;p&gt;My last two Copilot Studio articles, one on &lt;a href=&quot;https://www.theworkbench.blog/2026/08/copilot-studio-adding-dataverse.html&quot;&gt;wiring Dataverse knowledge sources with the Web API&lt;/a&gt; and one on &lt;a href=&quot;https://www.theworkbench.blog/2026/08/copilot-studio-real-alm-for-agents-and.html&quot;&gt;the ALM loop that keeps an agent rebuildable&lt;/a&gt;, both ended the same way: with a list of war stories and their workarounds. The runtime that silently ignores your knowledge source. The &lt;code&gt;pac&lt;/code&gt; auth profile that another workspace quietly re-points. The Quick Find view update that fails with an opaque error code. Each one cost me real hours, each one got written down, and I felt rather good about that.&lt;/p&gt;

&lt;p&gt;Then a thought started nagging at me. A war story you have to remember is a war story you will eventually forget. Six months from now, in a different tenant, I will hit one of these again and I will not remember the article, and neither will you. Writing it down was necessary. It was nowhere near sufficient. So, this time around, I turned the whole inventory into a tool.&lt;/p&gt;

&lt;h2&gt;From paragraphs to guardrails&lt;/h2&gt;

&lt;p&gt;The idea fits in one sentence: every war story becomes something that executes. Not documentation you consult, but a check that runs, refuses, and tells you why. I call them guardrails, and as it turns out, they come in exactly two flavors. &lt;strong&gt;Preflight checks&lt;/strong&gt; refuse before anything is touched: the runtime trap and the authentication requirement from the knowledge article, the profile drift from the ALM article, each now a refusal with the fix named in the message. &lt;strong&gt;Error translators&lt;/strong&gt; let a call happen and catch a known failure on the way back: when the infamous &lt;code&gt;0x80040216&lt;/code&gt; shows up on a savedquery update, you get the war story and the working alternatives, not the opaque code.&lt;/p&gt;

&lt;p&gt;Every guardrail lives under a contract from day one: one file, one test proving the failure it prevents is real, and one plain-language entry in a war-stories document that travels with the code. No entry, no guardrail. The document I would have written anyway now cannot drift from the code, because the code refuses to exist without it. And every refusal carries a typed exit code whose range means something: 10 through 19 says your environment is misconfigured, 20 says you asked for a route the platform is known to break. You may be asking why anyone should care about an exit code taxonomy. Very simple: CI cares. A pipeline that can tell &quot;the environment is wrong&quot; from &quot;the operation failed&quot; is one a human can diagnose from the log line alone.&lt;/p&gt;

&lt;p&gt;The natural home for all of this was a PowerShell module. But I work with an AI coding agent driving a lot of the platform interaction now, and an agent cannot benefit from a guardrail it cannot see, so the same engine got a second door: the MCP server, seven task-shaped verbs over the same guardrails. My favorite is the one with no cmdlet behind it, &lt;code&gt;explain-failure&lt;/code&gt;: when any operation is refused, the agent can ask what just happened and gets the war story, the fix, and a warning against working around the refusal, straight from the exit code registry, without another round trip.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I did not build this alone, and pretending otherwise would be strange in 2026. I paired with an AI coding agent (Claude Code, for the record) for the entire build. Keep in mind the division of labor, though: every platform fact in the tool was verified against a live environment before it was allowed to ship, because an AI pair is exactly like every other tool in my shop. Trust, but verify.&lt;/p&gt;

&lt;h2&gt;How my own tool tried to lie to me&lt;/h2&gt;

&lt;p&gt;Once the first guardrails were in place, we ran a red team pass against our own code: thirteen tests written to attack the guardrails the way a careless caller would, written before any fixes, expected to fail. Seven landed. Seven! The worst were bypasses of the flagship guardrail, which watched for &lt;code&gt;savedqueries(&lt;/code&gt; at the start of a request path. The very same forbidden request sailed right past it spelled as an absolute URL, or with a leading slash, or with the payload as a raw JSON string. Four spellings of one request, and the guardrail caught exactly one. Now, you may be thinking the fix is three more string checks. It is not! The fix was structural: normalize every request into one canonical shape before any check sees it, so the whole class of bypass dies at once. Suffice to say, every guardrail now gets a bypass hunt, red first, before it ships.&lt;/p&gt;

&lt;h2&gt;What live verification taught me, including about my own articles&lt;/h2&gt;

&lt;p&gt;The unit suite proves the code does what we intended. The live runs proved something better: that one of my published claims was too broad, and that the platform had two more surprises waiting. Three findings, in ascending order of embarrassment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, the drift guardrail caught me. Me!&lt;/strong&gt; The very first live pipeline run refused to deploy, because the active &lt;code&gt;pac&lt;/code&gt; profile on my machine pointed at a completely different environment than the one I had pinned. The founding war story of the whole effort, firing on its author on day one. I could not have scripted a better validation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second, my savedquery claim did not survive a third environment.&lt;/strong&gt; I reported that the &lt;code&gt;fetchxml&lt;/code&gt; update fails on every route, reproduced in two orgs. The integration test then found views that accept the very same call. We spent an afternoon hunting the discriminator: custom versus system table? No. The search index flag? No. Standard versus virtual versus elastic? Also no. The honest current claim is that the failure reproduces on most Quick Find views while a minority accept the call, and the discriminator is not yet identified. The guardrail was redesigned that same day, from refuse-up-front to attempt-and-translate, because refusing a route that sometimes works is its own kind of bug. If you figure out what separates the two, the comments are open and I will credit you properly!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third, and this one should worry every CI pipeline you own: &lt;code&gt;pac&lt;/code&gt; can print an error and hand your shell a success code.&lt;/strong&gt; Three times in one session, the CLI wrote a clear &lt;code&gt;Error:&lt;/code&gt; line and returned 0: an argument error twice, and an environment resolution failure. Any pipeline gating on the exit code treats all three as success and keeps right on going. Before publishing that sentence I wanted to know &lt;em&gt;which&lt;/em&gt; part of &lt;code&gt;pac&lt;/code&gt; was doing it, so I ran the same failing command two ways. Through the MSI-installed &lt;code&gt;pac&lt;/code&gt; on my &lt;code&gt;PATH&lt;/code&gt;, a two-line wrapper that calls &lt;code&gt;pac.launcher.exe&lt;/code&gt;: error printed, exit code 0. Through the versioned &lt;code&gt;pac.exe&lt;/code&gt; underneath it: same error, exit code 1. As it turns out, &lt;code&gt;pac&lt;/code&gt; itself tells the truth. It is the launcher that discards the exit code, on every command I tried, and that launcher is version 1.0.7 with a file date of September 2019, still shipping in the current installer. A seven-year-old shim, silently defeating a command Microsoft documents as safe to run in a build pipeline!&lt;/p&gt;

&lt;p&gt;This is not new. It sits on Microsoft&#39;s tracker as &lt;a href=&quot;https://github.com/microsoft/powerplatform-build-tools/issues/912&quot;&gt;issue #912&lt;/a&gt; (the launcher) and &lt;a href=&quot;https://github.com/microsoft/powerplatform-build-tools/issues/1027&quot;&gt;issue #1027&lt;/a&gt; (the symptom, with other users chiming in), both still open as I write this, and I have &lt;a href=&quot;https://github.com/microsoft/powerplatform-build-tools/issues/912#issuecomment-5309857001&quot;&gt;added the isolation above to the thread&lt;/a&gt;. In the meantime the tool refuses to believe a zero exit code when the output carries an &lt;code&gt;Error:&lt;/code&gt; line, and I would gently suggest your scripts do the same, or install &lt;code&gt;pac&lt;/code&gt; as a &lt;code&gt;dotnet tool&lt;/code&gt;, which skips the launcher entirely. The lesson generalizes: verify the exit codes of every CLI you automate, through the exact path your pipeline will call, because a wrapper on the &lt;code&gt;PATH&lt;/code&gt; can defeat a perfectly honest executable underneath it.&lt;/p&gt;

&lt;h2&gt;The bottom line&lt;/h2&gt;

&lt;p&gt;A war story is a liability until it is executable. The moment the savedquery story became a guardrail with a test, the test caught my own overclaim, and documentation cannot do that. That is the whole reason pac-copilot-kit exists, and the discriminator hunt from finding number two is genuinely open, so if you run it against your own environments, I would love to hear what you find.&lt;/p&gt;

&lt;p&gt;My next installment will be the one I promised last time: the walk from proof of concept to production, with the actual promotion done rather than theorized. Stay tuned!&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;Mariano Gomez Bent&lt;br /&gt;Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/08/copilot-studio-turning-war-stories-into.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-8320439968606332011</guid><pubDate>Fri, 28 Aug 2026 11:00:00 +0000</pubDate><atom:updated>2026-08-28T07:00:00.120-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ALM</category><category domain="http://www.blogger.com/atom/ns#">Copilot Studio</category><category domain="http://www.blogger.com/atom/ns#">Dataverse</category><category domain="http://www.blogger.com/atom/ns#">DevOps</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><title>Copilot Studio | Real ALM for Agents (and the One Click That Breaks Your Pipeline)</title><description>&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Real ALM for Copilot Studio agents: the repo is the agent&quot; height=&quot;630&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-09-agent-alm.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1200&quot; /&gt;&lt;/div&gt;
&lt;p&gt;In my &lt;a href=&quot;https://www.theworkbench.blog/2026/08/copilot-studio-adding-dataverse.html&quot;&gt;previous Copilot Studio article&lt;/a&gt;, I was working on a support agent grounded in Dataverse knowledge articles and a custom table of curated case resolutions, and I showed how to wire those knowledge sources up with the Web API rather than clicking them together in the maker portal. What I did not explain there is why I cared so much about scripting them in the first place.&lt;/p&gt;

&lt;p&gt;The reason is a question every consultant eventually asks about a sandbox: what happens to all of this when somebody refreshes the environment from production? The answer, of course, is that it all goes away. The agent, its topics, its knowledge sources, the custom table behind them, all of it. And the honest follow-up is the question that actually matters: how long would it take me to build it back?&lt;/p&gt;

&lt;p&gt;If the answer is &quot;about a week, and I would probably forget something,&quot; then what you have is not a project. It is a sandcastle! So, in this article I will walk through the lifecycle loop I settled on for a Copilot Studio agent, score it honestly against what Microsoft prescribes today, and show you the three places where the prescribed path quietly runs out of road. All three are documented by Microsoft, in public, and not one of them is where you would expect.&lt;/p&gt;

&lt;h2&gt;What Microsoft actually prescribes&lt;/h2&gt;

&lt;p&gt;Let me start by being fair to the guidance, because it is good guidance and I follow most of it. Microsoft&#39;s ALM story for Copilot Studio agents is &lt;strong&gt;solutions&lt;/strong&gt;, and it has not wavered: &lt;a href=&quot;https://learn.microsoft.com/microsoft-copilot-studio/authoring-solutions-overview&quot;&gt;the documentation&lt;/a&gt; is explicit that to move an agent between environments you need a custom solution rather than the default one. On top of that sits a set of &lt;a href=&quot;https://learn.microsoft.com/microsoft-copilot-studio/guidance/alm&quot;&gt;ALM golden rules&lt;/a&gt; familiar to anyone who has shipped a model-driven app: work in solutions, use a custom publisher and prefix, use environment variables for anything that changes between environments, deploy as managed downstream, and automate it all with source control. Microsoft also states a floor: at least three environments, development, test, and production.&lt;/p&gt;

&lt;p&gt;Alongside that, there is now a genuine authoring story for code-first people. The Visual Studio Code extension is generally available, the &lt;code&gt;pac copilot&lt;/code&gt; command group gives you a local workspace of YAML files, and the pitch includes Git and pull requests. Suffice to say, this is a real improvement over clicking everything in a portal and hoping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; read the banner at the top of those pages. Every ALM and code-first article I could find says the features described are powered by the &lt;em&gt;standard harness&lt;/em&gt;. If you are building in the newer agent experience, hold that thought.&lt;/p&gt;

&lt;h2&gt;The loop I actually ran&lt;/h2&gt;

&lt;p&gt;Here is the cycle, start to finish. Nothing exotic, and that is rather the point:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pac copilot init                          # scaffold a local agent workspace
# author agent.mcs.yml, settings.mcs.yml, topics/*.mcs.yml
# validate every file offline, before anything touches the tenant
pac copilot pack --publisher-prefix wrk --solution-name WorkbenchSupportAssistant
pac solution import --path .\WorkbenchSupportAssistant.zip --publish-changes
git add . &amp;amp;&amp;amp; git commit&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note here. The offline validation step is mine, not Microsoft&#39;s, and it is the single highest-value habit in the loop: a Power Fx string containing a colon followed by a space parses wrong and surfaces as strange runtime behavior rather than an error, and catching that locally costs a second where catching it after deployment costs an afternoon. &lt;code&gt;pac copilot pack&lt;/code&gt; is the interesting one: &lt;a href=&quot;https://learn.microsoft.com/power-platform/developer/cli/reference/copilot&quot;&gt;Microsoft documents it&lt;/a&gt; as a purely local operation that needs no authentication and no environment, which makes it, in their own words, safe to run in a build pipeline. Hold that thought too. And then, always, a commit. That repository is not a nicety. It &lt;em&gt;is&lt;/em&gt; the recovery plan.&lt;/p&gt;

&lt;h2&gt;Scoring myself against the golden rules&lt;/h2&gt;

&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Golden rule&lt;/th&gt;&lt;th&gt;What I did&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Always work in the context of solutions&lt;/td&gt;&lt;td&gt;Followed. Everything packs and imports as one solution.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Use a custom publisher and prefix&lt;/td&gt;&lt;td&gt;Followed, from day one.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Use environment variables for what changes between environments&lt;/td&gt;&lt;td&gt;Followed to the letter. The escalation address lives in an environment variable, never in a topic node.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Do not customize outside a development environment&lt;/td&gt;&lt;td&gt;Followed, though see below, because I only had one.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Create separate solutions only when you need independent deployment&lt;/td&gt;&lt;td&gt;Followed. One solution.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Automate ALM with source control&lt;/td&gt;&lt;td&gt;Followed, and then some.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Deploy as managed downstream&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Not followed.&lt;/strong&gt; Unmanaged only.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Six out of seven, and the miss is not laziness. It follows from a platform constraint that will hit you too: &lt;strong&gt;Copilot Studio&#39;s Dataverse knowledge sources only read the agent&#39;s own environment.&lt;/strong&gt; My agent had to be grounded on data that lived in one specific environment, so the agent had to live there as well. That collapses the three-environment model into one, and with nothing downstream to deploy to, managed solutions buy you nothing but ceremony. That is a limitation of my situation, not a flaw in the guidance. Keep in mind, though, that &quot;the data only exists in one place&quot; is an extremely common shape for a grounded agent, and the standard ALM advice does not really account for it.&lt;/p&gt;

&lt;h2&gt;Where the prescribed path runs out&lt;/h2&gt;

&lt;p&gt;Three gaps, and I found all three the hard way before finding them in the documentation afterward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First: the command built for pipelines has no pipeline.&lt;/strong&gt; Microsoft explicitly documents &lt;code&gt;pac copilot pack&lt;/code&gt; as safe to run in a build pipeline, so I went looking for the pipeline that accepts it. Let me be precise, because this claim deserves precision: agents are solution components, so the generic solution tasks deploy one just fine, and Microsoft&#39;s Build Tools FAQ says as much. What the &lt;a href=&quot;https://learn.microsoft.com/power-platform/alm/devops-build-tool-tasks&quot;&gt;Power Platform Build Tools task list&lt;/a&gt; does not contain is anything that knows an agent from a canvas app: no task wraps &lt;code&gt;pac copilot&lt;/code&gt;, and the only &quot;agent&quot; in that reference is the build agent running the job. &lt;a href=&quot;https://learn.microsoft.com/power-platform/alm/devops-github-available-actions&quot;&gt;GitHub Actions for Power Platform&lt;/a&gt; is the same story. I could not find a single Microsoft sample pipeline that runs &lt;code&gt;pac copilot pack&lt;/code&gt; followed by &lt;code&gt;pac solution import&lt;/code&gt;. You can build it yourself, and it is not hard, but the CLI was designed for CI, documented for CI, and the CI tooling has not caught up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second: the newer agent experience has no documented lifecycle at all.&lt;/strong&gt; Copilot Studio now ships more than one runtime, and I wrote last time about how that split silently breaks knowledge grounding. It splits the ALM story more sharply. Every solutions, import/export, and code-first article carries the standard-harness banner, and the newer experience&#39;s documented lifecycle is create, build, test, publish, monitor, all inside a single environment. No promotion, no solutions, no source control story. There is a related asymmetry worth knowing: in the newer experience each publish creates a new version, which &lt;a href=&quot;https://learn.microsoft.com/microsoft-copilot-studio/agents-experience/publication-fundamentals-publish-channels&quot;&gt;the documentation&lt;/a&gt; frames as a way to tell the live release from newer drafts. That is a counter, and I found no documented way to browse history or restore a previous version; rollback lives at the solution layer instead. So an agent can carry two unrelated version numbers, and only one can take you backward. I will say only what I can defend: I found no documentation of a restore capability, which is not the same as proving there is none.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third, and this is the one that changes how you should build: there is a manual click in the middle of the automated path.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;The one click that breaks your pipeline&lt;/h2&gt;

&lt;p&gt;Microsoft publishes a &lt;a href=&quot;https://learn.microsoft.com/troubleshoot/power-platform/copilot-studio/lifecycle-management/agents-solution-mapping&quot;&gt;troubleshooting article&lt;/a&gt; for agents whose components go missing after a solution import. The symptoms it lists are topics, environment variables, tools, child agents, and, yes, knowledge sources, all present in the source environment and absent in the target. The cause it gives is that the imported solution does not automatically include components added to the agent&#39;s source solution after the fact. The prescribed fix is to open the agent&#39;s commands menu, choose &lt;strong&gt;Advanced&lt;/strong&gt;, select &lt;strong&gt;Add required objects&lt;/strong&gt;, and export again, and the instruction is explicit that you repeat this before every export.&lt;/p&gt;

&lt;p&gt;Read that as an operations person rather than a maker. The fidelity of your deployment depends on a human remembering to click something in a portal &lt;em&gt;before every export&lt;/em&gt;. There is no CLI equivalent I could find, and no pipeline step, so your automated deployment has a manual precondition that fails silently when skipped. Nothing errors. The solution imports cleanly. The agent simply answers as though a knowledge source it needs was never there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; the documentation is candid about the general shape of this. The &lt;a href=&quot;https://learn.microsoft.com/microsoft-copilot-studio/authoring-solutions-import-export&quot;&gt;import and export guidance&lt;/a&gt; says outright that some components, custom topics and knowledge sources among them, might not be included depending on how they were created or linked; there is a published list of things that are simply not solution-aware (Application Insights settings, manual authentication, Direct Line and web channel security, deployed channels, sharing); and after any import you must reconfigure authentication and publish before sharing. None of it is hidden. It is just easy not to go looking until something breaks.&lt;/p&gt;

&lt;h2&gt;Why scripting the components sidesteps all of it&lt;/h2&gt;

&lt;p&gt;In the previous article I showed that a Dataverse knowledge source is really four ordinary Dataverse records, and that one header on each create call, &lt;code&gt;MSCRM.SolutionUniqueName&lt;/code&gt;, lands them inside your solution. That was written as a way around a tooling limitation. It turns out to be the whole answer to the click.&lt;/p&gt;

&lt;p&gt;The knowledge wiring in this project is a PowerShell script. It takes a token from the signed-in Azure CLI, talks to the Dataverse Web API directly, and creates the custom table, its columns, the table search configurations, the knowledge-source components, and the associations between them, every call carrying that header. The shape is the part worth stealing:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$org   = &quot;https://yourorg.crm.dynamics.com&quot;
$token = (az account get-access-token --resource $org | ConvertFrom-Json).accessToken

$headers = @{
  Authorization             = &quot;Bearer $token&quot;
  &quot;Content-Type&quot;            = &quot;application/json&quot;
  &quot;MSCRM.SolutionUniqueName&quot; = &quot;WorkbenchSupportAssistant&quot;   # every call. no exceptions.
}

$search = Invoke-RestMethod -Method Post -Headers $headers `
  -Uri &quot;$org/api/data/v9.2/dvtablesearchs&quot; `
  -Body (@{ name = &quot;wrk_case_resolutions_search&quot; } | ConvertTo-Json)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note here. The token comes from the Azure CLI, so there is no credential in the script and nothing to rotate in source control. The solution header sits in the shared &lt;code&gt;$headers&lt;/code&gt; block rather than being passed per call, which is the whole discipline in one line: you cannot forget it on the fourth create if it was never optional to begin with. And it deliberately depends on no &lt;code&gt;pac&lt;/code&gt; state whatsoever, because &lt;code&gt;pac&lt;/code&gt; authentication profiles are machine-global rather than per-project, and I have had a different workspace on the same laptop quietly re-point the profile my project was using. A recovery script that assumes the CLI is still aimed where you left it is a recovery script that fails on the one day you need it.&lt;/p&gt;

&lt;p&gt;Because the knowledge sources come from a script I can run again, I never depend on a solution remembering them. The failure mode Microsoft documents cannot happen to a component I rebuild from source in ninety seconds. The same goes for the custom table, its columns, and the flow behind the escalation topic, which had to be created with a direct call to the Dataverse workflow endpoint carrying that same header, because the tooling I first reached for created a flow that never appeared in the solution at all.&lt;/p&gt;

&lt;p&gt;And when something resists the API entirely, there is one more door. Last time I noted that updating a Quick Find view&#39;s find columns through the Web API fails with an opaque error, and that the maker portal was the fastest way through. Here is the part I promised to come back to: the same change can be made at the solution level, without clicking anything.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pac solution export --name WorkbenchSupportAssistant --path .\out
# unzip, edit the savedquery block in customizations.xml, re-zip
pac solution import --path .\WorkbenchSupportAssistant.zip --publish-changes&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I have come to think of this as solution surgery, and the safety rule is the whole trick: a Quick Find view is an ordinary Dataverse view, not an agent component. Microsoft warns that changing an agent&#39;s components directly inside the solution breaks export and import, and that warning is correct and worth obeying. The rest of the solution is ordinary Power Platform metadata and behaves accordingly. Keep in mind the import round-trips everything else in the solution, so if you have a flow in there, verify afterward that it came back activated. Mine did, but I checked.&lt;/p&gt;

&lt;h2&gt;What this approach costs, honestly&lt;/h2&gt;

&lt;p&gt;The scripts are real code, and real code needs maintenance. They encode undocumented record shapes that can change in any release, so my recovery plan has a shelf life and needs re-verification rather than blind trust. I gave up managed solutions, and with them the layering protections that stop someone editing production by hand. Parts of what I built sit outside the supported path, which is a fine place for a proof of concept and a rather different proposition for production. And I gave up the three-environment model, so I have no test environment standing between an idea and the only environment that exists, and I want to be blunt that source control does nothing whatsoever about that.&lt;/p&gt;

&lt;p&gt;That last point deserves precision, because I have seen it oversold. What all of this bought me is that &lt;strong&gt;the environment became replaceable, not unnecessary.&lt;/strong&gt; Rebuildability protects you from losing work; a test environment protects you from breaking something in front of people, and those are two different problems with two different answers. Anyone who tells you a tidy repository removes the need for proper environments is selling you something. Here is what reconciles the two, though, and it is why I would do it all again: &lt;strong&gt;being able to rebuild the whole agent from source is precisely what makes a second environment cheap.&lt;/strong&gt; When everything comes back by running a script, standing up a test environment stops being a project and becomes an afternoon pointed at a different URL. The discipline that looks like a substitute for the three-environment model is actually what makes it affordable.&lt;/p&gt;

&lt;h2&gt;So what does production actually look like?&lt;/h2&gt;

&lt;p&gt;Which is the question you are probably asking from inside your own proof of concept, and it has three answers worth knowing now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Placement is not a choice.&lt;/strong&gt; Dataverse knowledge reads only the agent&#39;s own environment, so the production agent lives in production, right alongside live customer data. Promoting a grounded agent is not like promoting a self-contained app into a tidy empty environment; you are placing an agent inside your live business system, and every decision about what it can see and say gets more serious the moment you do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution carries less than you would hope.&lt;/strong&gt; The agent, its topics, your table&#39;s schema, the environment variable definitions, and your flows travel. Authentication, deployed channels, sharing, and Application Insights settings do not, so a production deployment ends with an afternoon of hand configuration, plus pointing your environment variables at real values instead of the test address you have used since day one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your curated knowledge is data, not schema.&lt;/strong&gt; The table definition rides along in the solution; the reviewed content in it does not. So you choose between regenerating that content against production data and migrating the rows you already reviewed, and as it turns out, regeneration is the tempting answer and probably the wrong one, because synthesis is not deterministic and re-running it discards the editorial judgement that was the expensive part. Migrate the reviewed rows, including the ones you deliberately rejected, so the audit trail stays intact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; one sequencing trap. You cannot convert an unmanaged solution into a managed one in place. A development environment holding your work unmanaged is exactly right, and you export managed from it into production. But if you ever decide that environment should instead &lt;em&gt;receive&lt;/em&gt; managed solutions, the unmanaged solution has to come out first, and it takes your agent with it. Decide what each environment is for before the first managed export, not after.&lt;/p&gt;

&lt;p&gt;And then there is the part that is not really an ALM question at all: the guardrail work a sandbox lets you write down as caveats and a production rollout does not. That deserves its own article rather than a paragraph, so consider this the honest state of play. I know the shape production takes, I know which parts of my proof of concept were a loan rather than a discount, and the walk from one to the other is something I will be exploring in a future article, with the actual promotion done rather than theorized. Stay tuned!&lt;/p&gt;

&lt;h2&gt;The bottom line&lt;/h2&gt;

&lt;p&gt;Microsoft&#39;s ALM prescription for Copilot Studio agents is sound, and I followed six of its seven golden rules without argument. But the guidance assumes a shape of project that a grounded agent frequently cannot have, the tooling stops one step short of the automation it openly advertises, and the step that guarantees your components actually travel is a click somebody has to remember before every single export.&lt;/p&gt;

&lt;p&gt;So my rule ended up simple enough to fit on one line: &lt;strong&gt;the repository defines the agent, and an environment is a place I can put it.&lt;/strong&gt; One environment today, because the data gave me no choice. Two on the way to production, because promotion demands it. And the reason the second one will cost an afternoon rather than a fortnight is the same discipline that made the first one survivable.&lt;/p&gt;

&lt;p&gt;If you have automated a Copilot Studio agent deployment end to end, especially if you have found a way to handle the add-required-objects step without a human in the loop, please drop a note in the comments describing how. That is the piece I would most like to stop doing by hand.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;Mariano Gomez Bent&lt;br /&gt;Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/08/copilot-studio-real-alm-for-agents-and.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-3602864419858771009</guid><pubDate>Wed, 26 Aug 2026 11:00:00 +0000</pubDate><atom:updated>2026-08-26T08:28:11.938-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ALM</category><category domain="http://www.blogger.com/atom/ns#">Architecture</category><category domain="http://www.blogger.com/atom/ns#">Copilot Studio</category><category domain="http://www.blogger.com/atom/ns#">Dataverse</category><category domain="http://www.blogger.com/atom/ns#">Web API</category><title>Copilot Studio | Adding Dataverse Knowledge Sources with the Web API (the &quot;UI-Only&quot; Rule That Isn&#39;t)</title><description>&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Adding Copilot Studio Dataverse knowledge sources with the Web API&quot; height=&quot;630&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-08-dataverse-knowledge.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1200&quot; /&gt;&lt;/div&gt;
&lt;p&gt;Not long ago, I set out to build a support agent in Microsoft Copilot Studio for a product in the Dynamics ecosystem: the kind of agent that answers customer questions grounded in &lt;em&gt;your&lt;/em&gt; content, meaning Dataverse knowledge articles plus a custom table of curated case resolutions. No web browsing, no model knowledge; the knowledge sources are the agent&#39;s entire world. And since I treat agents as code (YAML in source control, &lt;code&gt;pac copilot pack&lt;/code&gt;, solution import, repeatable deployments), I ran head-first into a wall you may have hit yourself:&lt;/p&gt;
&lt;!-- On publish: link &quot;treat agents as code&quot; to the git-vs-pac source control article --&gt;

&lt;p&gt;&lt;strong&gt;Dataverse knowledge sources can only be added through the Copilot Studio UI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is what the documentation implies, that is the line the community tooling holds, and &lt;code&gt;pac copilot pack&lt;/code&gt; enforces it: put a Dataverse source definition in your workspace&#39;s &lt;code&gt;knowledge/&lt;/code&gt; folder and pack rejects it outright. Public website sources? Fine in YAML. SharePoint? Fine. Dataverse tables, the one source type that lives &lt;em&gt;in the same platform as the agent itself&lt;/em&gt;, are clicks only.&lt;/p&gt;

&lt;p&gt;Except, as it turns out, that is not quite true. Copilot Studio is built &lt;em&gt;on&lt;/em&gt; Dataverse. Every knowledge source you click together in the maker portal materializes as plain Dataverse rows, and anything that is plain Dataverse rows can be created with the Web API: inside a solution, from a pipeline, repeatably. So, in this article I will walk through the recipe, battle-tested twice now: once in a production-grade Dynamics 365 CE org, and once in a freshly provisioned vanilla environment, where it surfaced several extra lessons you will want in hand before trying this yourself.&lt;/p&gt;

&lt;div style=&quot;background: rgba(245, 158, 11, 0.12); border-left: 4px solid #f59e0b; border-radius: 6px; padding: 0.9rem 1.2rem; margin: 1.6rem 0;&quot;&gt;&lt;strong&gt;&amp;#9888;&amp;#65039; NOT OFFICIALLY SUPPORTED:&lt;/strong&gt; none of this is documented or supported by Microsoft. These are the shapes Copilot Studio happens to write today, discovered by inspecting what the maker UI creates, and they can change in any release. Use this for dev and ALM automation with your eyes open, and always verify the result in the maker portal afterward.&lt;/div&gt;

&lt;h2&gt;First, which kind of agent? (This one matters)&lt;/h2&gt;

&lt;p&gt;Copilot Studio now ships &lt;strong&gt;two agent runtimes&lt;/strong&gt;, which Microsoft calls &lt;em&gt;harnesses&lt;/em&gt;. The &lt;strong&gt;standard harness&lt;/strong&gt; is the classic experience: topics, the full Knowledge pane, solution-first ALM. The &lt;strong&gt;GitHub Copilot harness&lt;/strong&gt; is the new streamlined agent builder, with its Build, Preview, and Evaluate tabs and a model picker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dataverse knowledge is a standard-harness feature.&lt;/strong&gt; The new experience does not offer Dataverse in its Add knowledge dialog at all, and here is the trap that cost me an evening: if you create your knowledge component via the API against a new-experience agent, &lt;strong&gt;the Knowledge panel will happily display it&lt;/strong&gt; (the panel reads the same component table) &lt;strong&gt;while the runtime silently never queries it&lt;/strong&gt;. The agent will cheerfully answer from its own general knowledge and tell you it has no documents. No error anywhere!&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;The new-experience agent builder showing the API-created Curated Case Resolutions source listed in the Knowledge panel, displayed but never used&quot; height=&quot;573&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/images/post-08/fig1-new-experience-knowledge-panel.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1837&quot; /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center; font-size: 0.9em; margin: 0.4em 0 1.4em;&quot;&gt;&lt;em&gt;The trap in action: the new experience displays the API-created Dataverse source in its Knowledge panel...&lt;/em&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;The new-experience agent answering a scanner question from general model knowledge, stating it has no device docs in the workspace&quot; height=&quot;893&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/images/post-08/fig2-new-experience-ungrounded.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1832&quot; /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center; font-size: 0.9em; margin: 0.4em 0 1.4em;&quot;&gt;&lt;em&gt;...but its runtime never queries it. Note the answer opens with &amp;quot;I don&amp;#39;t have any device docs or network data in this workspace&amp;quot; while the source sits right there in the panel.&lt;/em&gt;&lt;/div&gt;

&lt;p&gt;So check your agent&#39;s runtime before wiring anything, as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GET /api/data/v9.2/bots?$select=name,schemaname,template&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A &lt;code&gt;template&lt;/code&gt; of &lt;code&gt;default-2.1.0&lt;/code&gt; (or a similar &lt;code&gt;default-*&lt;/code&gt;) means the standard harness; proceed. A &lt;code&gt;template&lt;/code&gt; of &lt;code&gt;cliagent-1.0.0&lt;/code&gt; means the new experience, and this recipe will not ground there. To build standard-harness agents, flip the &lt;strong&gt;&quot;New experience&quot; toggle off&lt;/strong&gt; on the Copilot Studio homepage, or pick &lt;strong&gt;&quot;Other ways to build.&quot;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; a fun fact discovered along the way. In the new experience, the default &quot;Search all websites&quot; knowledge chip is not a knowledge source row at all; it is an &lt;code&gt;enableWebSearch&lt;/code&gt; flag inside the bot&#39;s configuration JSON. Different harness, different bookkeeping.&lt;/p&gt;

&lt;h2&gt;Why bother?&lt;/h2&gt;

&lt;p&gt;If you are happy clicking the UI once, close this tab with my blessing. But if any of the following apply, read on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your dev environment is a &lt;strong&gt;sandbox that gets refreshed&lt;/strong&gt; from production periodically, wiping everything you built. Mine was! With the agent rebuildable from a git repository, knowledge sources included, a refresh becomes a non-event instead of a lost week.&lt;/li&gt;
&lt;li&gt;You deploy the &lt;strong&gt;same agent to multiple environments&lt;/strong&gt; and want identical knowledge wiring in each without a click-checklist taped to the monitor.&lt;/li&gt;
&lt;li&gt;You want knowledge sources &lt;strong&gt;inside your solution&lt;/strong&gt;, versioned and transported like everything else you ship.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Finding the shapes: mirror a working example&lt;/h2&gt;

&lt;p&gt;The trick that unlocked everything is almost embarrassingly simple: find a working reference implementation &lt;em&gt;in the same environment&lt;/em&gt; and mirror its record shapes. If your org runs Dynamics 365 Customer Service, Microsoft&#39;s own first-party copilots ship as solution components, and their Dataverse knowledge sources are sitting right there in the very same tables yours will use; that is what I mirrored. In a clean environment with no first-party copilots, make your own reference: click one knowledge source together in the UI, then query what it wrote. Either way, the shapes reveal themselves:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GET /api/data/v9.2/botcomponents?$filter=componenttype eq 16
  &amp;amp;$select=name,data,schemaname&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Four moving parts emerge from that inspection:&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Piece&lt;/th&gt;&lt;th&gt;What it is&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dvtablesearch&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A named &quot;table search&quot; configuration: the knowledge source&#39;s identity&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dvtablesearchentity&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A child row per table being searched, pointing at its parent via the &lt;code&gt;DVTableSearch&lt;/code&gt; navigation property and naming the table in &lt;code&gt;entitylogicalname&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;botcomponent&lt;/code&gt; (componenttype 16)&lt;/td&gt;&lt;td&gt;The agent-side knowledge component; its &lt;code&gt;data&lt;/code&gt; column holds KnowledgeSourceConfiguration YAML whose &lt;code&gt;skillConfiguration&lt;/code&gt; names the &lt;code&gt;dvtablesearch&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;botcomponent_dvtablesearch&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The N:N association tying the component to the search config&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;A few things to note before we build. First, the component attaches to your agent through its &lt;strong&gt;&lt;code&gt;parentbotid&lt;/code&gt; lookup&lt;/strong&gt;, and not, as you might reasonably guess, through the &lt;code&gt;bot_botcomponent&lt;/code&gt; N:N relationship. That relationship exists in the schema, but for knowledge components it stays empty; the parent lookup is what the platform actually uses. Ask me how long that one took! Second, on naming, because it bit me: &lt;code&gt;dvtablesearch.name&lt;/code&gt; is a &lt;strong&gt;machine-style identifier&lt;/strong&gt; (the component YAML references it verbatim), while the friendly display name your makers see in the Knowledge tab lives on the &lt;code&gt;botcomponent.name&lt;/code&gt;. Keep them distinct on purpose.&lt;/p&gt;

&lt;h2&gt;Step 0: the custom table (if you are grounding on one)&lt;/h2&gt;

&lt;p&gt;My scenario grounds the agent on a custom curated-resolutions table. If you only need standard tables like &lt;code&gt;knowledgearticle&lt;/code&gt; (which, by the way, is a base Dataverse table, present even in environments without any Dynamics 365 apps), feel free to skip ahead to Step 1. Otherwise, three gotchas await, and the third one is the difference between an agent that grounds and one that shrugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha 1: Memo columns want an explicit format.&lt;/strong&gt; Declare &lt;code&gt;Format: TextArea&lt;/code&gt; on each &lt;code&gt;MemoAttributeMetadata&lt;/code&gt;. That is plain multi-line text, which is what the knowledge indexer expects, and a working column reads back with both &lt;code&gt;Format&lt;/code&gt; and &lt;code&gt;FormatName&lt;/code&gt; as &lt;code&gt;TextArea&lt;/code&gt;. Here is the whole table, one create:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;POST /api/data/v9.2/EntityDefinitions
MSCRM.SolutionUniqueName: WorkbenchSupportAssistant

{
  &quot;@odata.type&quot;: &quot;Microsoft.Dynamics.CRM.EntityMetadata&quot;,
  &quot;SchemaName&quot;: &quot;wrk_caseresolution&quot;,
  &quot;DisplayName&quot;: { &quot;LocalizedLabels&quot;: [ { &quot;Label&quot;: &quot;Case Resolution&quot;, &quot;LanguageCode&quot;: 1033 } ] },
  &quot;DisplayCollectionName&quot;: { &quot;LocalizedLabels&quot;: [ { &quot;Label&quot;: &quot;Case Resolutions&quot;, &quot;LanguageCode&quot;: 1033 } ] },
  &quot;OwnershipType&quot;: &quot;UserOwned&quot;,
  &quot;HasActivities&quot;: false,
  &quot;HasNotes&quot;: false,
  &quot;SyncToExternalSearchIndex&quot;: true,
  &quot;Attributes&quot;: [
    { &quot;@odata.type&quot;: &quot;Microsoft.Dynamics.CRM.StringAttributeMetadata&quot;,
      &quot;SchemaName&quot;: &quot;wrk_title&quot;, &quot;IsPrimaryName&quot;: true, &quot;MaxLength&quot;: 300,
      &quot;RequiredLevel&quot;: { &quot;Value&quot;: &quot;ApplicationRequired&quot; },
      &quot;DisplayName&quot;: { &quot;LocalizedLabels&quot;: [ { &quot;Label&quot;: &quot;Title&quot;, &quot;LanguageCode&quot;: 1033 } ] } },
    { &quot;@odata.type&quot;: &quot;Microsoft.Dynamics.CRM.MemoAttributeMetadata&quot;,
      &quot;SchemaName&quot;: &quot;wrk_symptom&quot;, &quot;Format&quot;: &quot;TextArea&quot;, &quot;MaxLength&quot;: 4000,
      &quot;DisplayName&quot;: { &quot;LocalizedLabels&quot;: [ { &quot;Label&quot;: &quot;Symptom&quot;, &quot;LanguageCode&quot;: 1033 } ] } },
    { &quot;@odata.type&quot;: &quot;Microsoft.Dynamics.CRM.MemoAttributeMetadata&quot;,
      &quot;SchemaName&quot;: &quot;wrk_resolution&quot;, &quot;Format&quot;: &quot;TextArea&quot;, &quot;MaxLength&quot;: 10000,
      &quot;DisplayName&quot;: { &quot;LocalizedLabels&quot;: [ { &quot;Label&quot;: &quot;Resolution&quot;, &quot;LanguageCode&quot;: 1033 } ] } }
  ]
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One POST, one 204, done! And notice &lt;code&gt;SyncToExternalSearchIndex: true&lt;/code&gt; riding along in the create payload. Which brings us to...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha 2: Dataverse search must be on, and the org-level flag is just a column.&lt;/strong&gt; Copilot Studio&#39;s Dataverse knowledge rides Dataverse search. The admin-center setting (now &lt;em&gt;two&lt;/em&gt; checkboxes in the modern admin UI, one for &quot;AI and agent experiences&quot; and one for the global search bar) ultimately reflects a boolean on the organization record, and yes, you can flip it via API:&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;The Power Platform admin center Dataverse search settings showing the two indexing checkboxes plus the Search behavior options&quot; height=&quot;718&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/images/post-08/fig3-admin-dataverse-search.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;788&quot; /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center; font-size: 0.9em; margin: 0.4em 0 1.4em;&quot;&gt;&lt;em&gt;The modern admin center splits search indexing into two scopes; the first checkbox (&amp;quot;AI and agent experiences&amp;quot;) is the one Copilot Studio knowledge rides on.&lt;/em&gt;&lt;/div&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;PATCH /api/data/v9.2/organizations(&amp;lt;orgid&amp;gt;)
{ &quot;isexternalsearchindexenabled&quot;: true }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But budget real time for what happens next. On a freshly provisioned environment, &lt;strong&gt;initial index provisioning took about two hours&lt;/strong&gt; before my rows became searchable. And do not trust &lt;code&gt;GET /api/search/v1.0/status&lt;/code&gt; to tell you how it is going; it reported &quot;0 tables indexed&quot; &lt;em&gt;even while queries were returning hits&lt;/em&gt;. The only reliable readiness probe is an actual query:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;POST /api/search/v1.0/query
{ &quot;search&quot;: &quot;scanner&quot;, &quot;entities&quot;: [&quot;wrk_caseresolution&quot;], &quot;top&quot;: 5 }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For a table that already exists and needs the sync flag flipped, resist the urge to PATCH the entity definition, because &lt;strong&gt;metadata entities cannot be updated with PATCH&lt;/strong&gt;. Updates replace the whole definition: GET it, modify, PUT the &lt;em&gt;entire&lt;/em&gt; document back with an &lt;code&gt;MSCRM.MergeLabels: true&lt;/code&gt; header (or kiss your localized labels goodbye, since omitted properties reset to their defaults), then call the &lt;code&gt;PublishXml&lt;/code&gt; action. You may be asking whether all that ceremony is really necessary for one boolean. It is! Which is exactly why you set it at create time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha 3: find columns ARE the search index.&lt;/strong&gt; This is the one that separates &quot;source attached&quot; from &quot;agent grounded.&quot; Dataverse search indexes the columns configured as &lt;strong&gt;find columns on the table&#39;s Quick Find view&lt;/strong&gt;, and a fresh custom table&#39;s Quick Find view has exactly one: the primary name. Your beautiful Symptom and Resolution text? Invisible to search, and therefore to your agent, until they are added.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; and here is the kicker. Updating the view&#39;s &lt;code&gt;fetchxml&lt;/code&gt; via the Web API fails with an opaque &lt;code&gt;0x80040216&lt;/code&gt; on every route I tried (record PATCH, single-property PUT), &lt;strong&gt;in two different orgs&lt;/strong&gt;, while &lt;code&gt;layoutxml&lt;/code&gt; on the very same record updates fine. Whatever message the maker UI sends, the Web API&#39;s &lt;code&gt;savedquery&lt;/code&gt; update path is not it. Budget one manual click-step: go to Power Apps, then &lt;strong&gt;Tables&lt;/strong&gt;, then your table, then &lt;strong&gt;Views&lt;/strong&gt;, open the Quick Find view, click &lt;strong&gt;Edit find table columns&lt;/strong&gt;, add your text columns, and &lt;strong&gt;Save and publish&lt;/strong&gt;. That is the fastest route, and it is the one I used here. Now, it is not the only route: the same change can be made at the solution level, by exporting the solution, editing the view definition inside it, and importing it back, which automates cleanly. That belongs to a bigger story about treating agents as source-controlled artifacts, and it is where I am headed next!&lt;/p&gt;

&lt;p&gt;Seed a few rows while you are here. An empty table grounds nothing!&lt;/p&gt;

&lt;h2&gt;Step 1: create the &lt;code&gt;dvtablesearch&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;First surprise: the entity-set name is &lt;code&gt;dvtablesearchs&lt;/code&gt;. Yes, really, that plural! Ask &lt;code&gt;$metadata&lt;/code&gt; if you do not believe me; I did, twice:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;POST /api/data/v9.2/dvtablesearchs
MSCRM.SolutionUniqueName: WorkbenchSupportAssistant

{ &quot;name&quot;: &quot;wrk_case_resolutions_search&quot; }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That single property is genuinely the whole payload; verified. Machine-style name, remember: this exact string gets referenced by the component YAML in Step 3. And keep an eye on that &lt;code&gt;MSCRM.SolutionUniqueName&lt;/code&gt; header, because it is doing quiet but important work in every call in this article. It lands each row in &lt;strong&gt;your solution&lt;/strong&gt; instead of the default one, which is the whole ALM point of the exercise.&lt;/p&gt;

&lt;h2&gt;Step 2: add the table(s) to it&lt;/h2&gt;

&lt;p&gt;One &lt;code&gt;dvtablesearchentity&lt;/code&gt; per table the source searches, bound to its parent via the single-valued navigation property, as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;POST /api/data/v9.2/dvtablesearchentities
MSCRM.SolutionUniqueName: WorkbenchSupportAssistant

{
  &quot;entitylogicalname&quot;: &quot;wrk_caseresolution&quot;,
  &quot;DVTableSearch@odata.bind&quot;: &quot;/dvtablesearchs(&amp;lt;dvtablesearch-guid&amp;gt;)&quot;
}&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Step 3: the &lt;code&gt;botcomponent&lt;/code&gt; that makes it a knowledge source&lt;/h2&gt;

&lt;p&gt;This is the piece that surprises people: the knowledge source your agent sees is a &lt;code&gt;botcomponent&lt;/code&gt; row of componenttype 16 whose &lt;code&gt;data&lt;/code&gt; column is... YAML. A &lt;code&gt;KnowledgeSourceConfiguration&lt;/code&gt; document whose &lt;code&gt;skillConfiguration&lt;/code&gt; property names the &lt;code&gt;dvtablesearch&lt;/code&gt; from Step 1, and whose &lt;code&gt;parentbotid&lt;/code&gt; lookup attaches it to your agent, all in one create:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;POST /api/data/v9.2/botcomponents
MSCRM.SolutionUniqueName: WorkbenchSupportAssistant

{
  &quot;name&quot;: &quot;Curated Case Resolutions&quot;,
  &quot;componenttype&quot;: 16,
  &quot;schemaname&quot;: &quot;wrk_WorkbenchSupportAssistant20.knowledge.wrk_case_resolutions&quot;,
  &quot;data&quot;: &quot;kind: KnowledgeSourceConfiguration\nsource:\n  kind: DataverseStructuredSearchSource\n  skillConfiguration: wrk_case_resolutions_search\n&quot;,
  &quot;parentbotid@odata.bind&quot;: &quot;/bots(&amp;lt;bot-guid&amp;gt;)&quot;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That &lt;code&gt;data&lt;/code&gt; YAML, unfolded so you can actually read it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;kind: KnowledgeSourceConfiguration
source:
  kind: DataverseStructuredSearchSource
  skillConfiguration: wrk_case_resolutions_search&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note here. The &lt;code&gt;schemaname&lt;/code&gt; follows the convention &lt;code&gt;&amp;lt;botSchemaName&amp;gt;.knowledge.&amp;lt;componentName&amp;gt;&lt;/code&gt;, and that is the &lt;strong&gt;bot&#39;s&lt;/strong&gt; schemaname, which you should read rather than guess: the same &lt;code&gt;GET /bots&lt;/code&gt; from the harness check gives it to you, and agents created in the new experience even carry a random suffix in theirs. And the friendly &lt;code&gt;name&lt;/code&gt; is what your makers will see in the Knowledge tab, so make it read like a knowledge source, not like a database object.&lt;/p&gt;

&lt;h2&gt;Step 4: tie the component to the search config&lt;/h2&gt;

&lt;p&gt;The N:N association that closes the loop:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;POST /api/data/v9.2/botcomponents(&amp;lt;component-guid&amp;gt;)/botcomponent_dvtablesearch/$ref

{ &quot;@odata.id&quot;: &quot;https://yourorg.crm.dynamics.com/api/data/v9.2/dvtablesearchs(&amp;lt;dvtablesearch-guid&amp;gt;)&quot; }&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Verify like the maker UI is watching&lt;/h2&gt;

&lt;p&gt;Open the agent in Copilot Studio and go to the &lt;strong&gt;Knowledge&lt;/strong&gt; page. Your source should be listed exactly as if you had clicked it together: name, table, status. Then comes the real test, and no publish is needed. Go straight into the test canvas and ask a question only your table can answer.&lt;/p&gt;

&lt;p&gt;When it works, it &lt;em&gt;really&lt;/em&gt; works! My test agent answered a scanner-connectivity question with the exact resolution from the seeded row, three citations pointing at &lt;code&gt;wrk_caseresolution&lt;/code&gt; records, and the canvas&#39;s activity map showing the knowledge searches with &quot;Curated Case Resolutions&quot; as the referenced source. Grounded, cited, and not one of those records touched by a mouse.&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;The standard-harness test canvas showing the activity map with completed knowledge searches, the Referenced sources panel quoting the Curated Case Resolutions row, and the grounded answer with three wrk_caseresolution citations&quot; height=&quot;1069&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/images/post-08/fig4-grounded-answer.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1846&quot; /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center; font-size: 0.9em; margin: 0.4em 0 1.4em;&quot;&gt;&lt;em&gt;The payoff: the activity map traces three knowledge searches, the inspection panel quotes the seeded resolution verbatim, and the answer carries three citations into wrk_caseresolution; every one of those records created by the Web API.&lt;/em&gt;&lt;/div&gt;

&lt;p&gt;Two behavioral notes for Dataverse sources generally, both documented but easy to miss:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Same environment only.&lt;/strong&gt; Copilot Studio&#39;s Dataverse knowledge reads the agent&#39;s own environment. If your data lives in environment A, the agent lives in environment A. Plan placement before you scaffold.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;End-user authentication must be &quot;Authenticate with Microsoft.&quot;&lt;/strong&gt; Dataverse sources ride the end user&#39;s identity; &quot;No authentication&quot; and &quot;Authenticate manually&quot; agents will not search them, and the docs are explicit about this one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The bigger picture&lt;/h2&gt;

&lt;p&gt;Everything Copilot Studio&#39;s maker portal does lands in Dataverse tables, and a surprising amount of the &quot;UI-only&quot; surface is only UI-only until you look at what the UI writes. The same technique has bailed me out more than once: find where the platform stores it, mirror the shape, create it in your solution. In turn, it converts &quot;click this checklist in every environment&quot; into &quot;run the deployment,&quot; and that is the difference between an ALM story with an asterisk and one without.&lt;/p&gt;

&lt;p&gt;One more time, because it matters: these are undocumented shapes, subject to change, so verify in the portal after every deployment. But with that caveat honored, a source-controlled agent is rebuildable end to end, knowledge sources included, and that is always a good thing.&lt;/p&gt;

&lt;p&gt;If you have automated your own way around a &quot;UI-only&quot; corner of Copilot Studio, or if these shapes have already drifted by the time you read this, please drop a note in the comments describing what you found; undocumented territory is exactly where comparing notes pays the most.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;Mariano Gomez Bent&lt;br /&gt;Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/08/copilot-studio-adding-dataverse.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-5531898008819768436</guid><pubDate>Mon, 24 Aug 2026 11:00:00 +0000</pubDate><atom:updated>2026-08-24T10:55:37.069-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Application Insights</category><category domain="http://www.blogger.com/atom/ns#">Azure</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">Telemetry</category><title>Power Automate | Cloud Flow Telemetry with Azure Application Insights, Down to the Action Level</title><description>&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Power Automate cloud flow telemetry in Azure Application Insights, down to the action level&quot; height=&quot;630&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-06-appinsights.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1200&quot; /&gt;&lt;/div&gt;
&lt;p&gt;Longtime readers may remember that the very last article I published before this blog went quiet, back in August of 2021, covered monitoring &lt;a href=&quot;https://www.theworkbench.blog/2021/08/power-apps-application-monitoring-with.html&quot; target=&quot;_blank&quot;&gt;Power Apps with Azure Application Insights&lt;/a&gt;. So it is only fitting that I return to the subject from the other side of the platform: getting cloud flow telemetry out of Power Automate and into Application Insights, down to the action level.&lt;/p&gt;

&lt;p&gt;I will be honest about why I am writing this one. When I went looking for how this integration works, the picture I pieced together from searching around was incomplete, and once I configured it and read the actual tables, I understood why: the feature is admin-gated where makers cannot see it, and the telemetry schema is not what instinct suggests. I made the wrong assumption myself before the data corrected me! So, in this article I will walk through how the integration actually works, the schema surprise that changes how you query it, and the &lt;a href=&quot;https://learn.microsoft.com/en-us/kusto/?view=microsoft-fabric&quot; target=&quot;_blank&quot;&gt;Kusto queries&lt;/a&gt; that turn &quot;the flow failed&quot; into &quot;the flow failed at this action, with this error.&quot;&lt;/p&gt;

&lt;h2&gt;First things first: yes, the integration exists&lt;/h2&gt;

&lt;p&gt;Power Automate cloud flow telemetry can be exported to Azure Application Insights, and keep in mind, this is not a maker feature -- which is the source of a lot of the confusion. Canvas apps let a maker paste an instrumentation key into the app and start calling &lt;i&gt;&lt;b&gt;Trace()&lt;/b&gt;&lt;/i&gt;. Cloud flows offer nothing of the sort, and for a sound reason: flows have no client runtime to instrument. They execute server-side on shared infrastructure, so the integration was built as a platform-level export instead.&lt;/p&gt;

&lt;p&gt;The setup lives in the &lt;strong&gt;Power Platform admin center&lt;/strong&gt;, under &lt;strong&gt;Data export&lt;/strong&gt;. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEii9WQxdgAykdSYgUhfp2ZM_5SH0AR4ddRhmq3AdVEnuxRxRlbp9oJVxUvKTVM1T4JTtfV_G2Zz6hjs0Xvki3N9MBzXBRDhWO0hF-h6UHy2mwad_USZ4lOHy5GxSmjzdEnAr6EpxjAs44_gt7Q_GcU-hBpmnLZ1qiAr5K4c6AG8UQJxu4UVqnKaaHawNPaE&quot;&gt;&lt;img style=&quot;width: 100%; height: auto;&quot; alt=&quot;&quot; data-original-height=&quot;818&quot; data-original-width=&quot;1622&quot; height=&quot;818&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEii9WQxdgAykdSYgUhfp2ZM_5SH0AR4ddRhmq3AdVEnuxRxRlbp9oJVxUvKTVM1T4JTtfV_G2Zz6hjs0Xvki3N9MBzXBRDhWO0hF-h6UHy2mwad_USZ4lOHy5GxSmjzdEnAr6EpxjAs44_gt7Q_GcU-hBpmnLZ1qiAr5K4c6AG8UQJxu4UVqnKaaHawNPaE=s1600&quot; width=&quot;1622&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center; font-size: 0.9em; margin: 0.4em 0 1.4em;&quot;&gt;&lt;em&gt;Admin Center &amp;gt; Manage &amp;gt; Data Export&lt;/em&gt;&lt;/div&gt;&lt;br /&gt;An administrator creates an export package, selects Power Automate as the data type, chooses the environment, and points it at an Application Insights resource. Three requirements to check before you start, because each one can stop you cold:&lt;p&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The environment must be a Managed Environment.&lt;/strong&gt; The feature is gated behind this governance tier, which is exactly why a maker who goes looking for it at the flow level concludes it does not exist. It does; it just lives upstairs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need admin rights, not maker rights.&lt;/strong&gt; Power Platform administrator or Dynamics 365 administrator at the tenant level, plus environment or system administrator in the Dataverse environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need Contributor rights or better on the Application Insights resource&lt;/strong&gt; itself, over on the Azure side.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; once configured, expect up to 24 hours before telemetry starts appearing. Initial patience is required; ongoing latency is much lower. Do not spend that first afternoon rewriting your export package because the tables look empty!&lt;/p&gt;

&lt;h2&gt;The schema surprise: two tables, not one&lt;/h2&gt;

&lt;p&gt;Here is the assumption I walked in with: every action a flow executes, including the trigger, lands as an entry in the Application Insights &lt;code&gt;requests&lt;/code&gt; table. It seems reasonable. It is also not how the schema works, and the difference matters more than any other detail in this article. As it turns out, the export splits telemetry across two tables:&lt;/p&gt;

&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Table&lt;/th&gt;&lt;th&gt;Contains&lt;/th&gt;&lt;th&gt;signalCategory value&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Cloud flow runs&lt;/td&gt;&lt;td&gt;&quot;Cloud flow runs&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dependencies&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Cloud flow triggers and actions&lt;/td&gt;&lt;td&gt;&quot;Cloud flow triggers&quot; / &quot;Cloud flow actions&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;In turn, if your monitoring queries only touch &lt;code&gt;requests&lt;/code&gt;, you are monitoring at the run level. You will know a flow failed. You will not know which action failed, how long each action took, or whether a specific connector call is degrading over time. All of that lives in &lt;code&gt;dependencies&lt;/code&gt;, waiting to be queried.&lt;/p&gt;

&lt;p&gt;There is a second, related detail that took me a moment to appreciate. When you configure the export package, you explicitly choose whether to export cloud flow runs, triggers, or actions. These are separate checkboxes! If you only selected runs during setup, action telemetry never leaves the platform, and no Kusto query will conjure it afterward. Granularity is decided at configuration time, not query time.&lt;/p&gt;

&lt;h2&gt;Run-level monitoring: the baseline&lt;/h2&gt;

&lt;p&gt;Run-level failure alerting is the right starting point, and the query looks as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;requests
| where customDimensions.signalCategory == &quot;Cloud flow runs&quot;
| where success == false
| extend flowId = tostring(customDimensions[&quot;resourceId&quot;]),
         environmentId = tostring(customDimensions[&quot;environmentId&quot;])
| project timestamp, name, resultCode, duration, flowId, environmentId, operation_Id&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note here. Filtering on &lt;code&gt;signalCategory&lt;/code&gt; matters because your Application Insights instance may be collecting telemetry from many sources, and this keeps the flow signals separated from everything else. Filtering on &lt;code&gt;environmentId&lt;/code&gt; matters when multiple environments export to the same resource. Wire this query to an Azure Monitor alert rule, and you have real-time failure notifications by email, SMS, or webhook.&lt;/p&gt;

&lt;h2&gt;Action-level monitoring: where the real value is&lt;/h2&gt;

&lt;p&gt;Now, with the actions checkbox enabled in your export package, the &lt;code&gt;dependencies&lt;/code&gt; table gives you per-action telemetry:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;dependencies
| where customDimensions.signalCategory == &quot;Cloud flow actions&quot;
| where success == false
| extend flowId = tostring(customDimensions[&quot;resourceId&quot;])
| project timestamp, name, resultCode, duration, flowId, operation_Id&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; field carries the action name exactly as it appears in the flow designer. This is the query that turns &quot;the invoice approval flow failed&quot; into &quot;the invoice approval flow failed at the vendor validation HTTP call with a 429.&quot;&lt;/p&gt;

&lt;p&gt;Correlation is what makes the two tables work together. The &lt;code&gt;operation_Id&lt;/code&gt; on an action&#39;s dependency row matches the &lt;code&gt;operation_Id&lt;/code&gt; on the parent run&#39;s request row, so you can join them:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;requests
| where customDimensions.signalCategory == &quot;Cloud flow runs&quot;
| where success == false
| join kind=inner (
    dependencies
    | where customDimensions.signalCategory == &quot;Cloud flow actions&quot;
    | where success == false
  ) on operation_Id
| project runTime = timestamp, flowRun = name,
          failedAction = name1, actionResult = resultCode1, actionDuration = duration1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What this join produces is a failure report at the granularity your support team actually needs: which run, which action, what error, and how long it ran before dying. The &lt;code&gt;name1&lt;/code&gt;, &lt;code&gt;resultCode1&lt;/code&gt;, and &lt;code&gt;duration1&lt;/code&gt; columns are Kusto&#39;s automatic renames for the joined table&#39;s fields; the projection gives them names a human can read.&lt;/p&gt;

&lt;p&gt;Beyond failures, the same table supports performance work. Percentile queries over &lt;code&gt;duration&lt;/code&gt; by action &lt;code&gt;name&lt;/code&gt; will surface connector calls that are slowly degrading long before they start timing out, which is exactly the kind of early signal run-level monitoring can never provide.&lt;/p&gt;

&lt;h2&gt;Three caveats before you turn everything on&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;NOTE 1:&lt;/strong&gt; ingestion cost scales with granularity. Application Insights bills per GB ingested, and action-level export on a busy flow with Apply to each loops generates a row per action, per iteration, per run. A flow processing a few thousand records nightly can produce telemetry volume that surprises you at invoice time. Scope the export deliberately: enable action-level export for the flows that justify it rather than blanketing the environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE 2:&lt;/strong&gt; validate scope nesting behavior empirically. If your flows use the Try/Catch pattern built on Scope containers, test how nested actions surface before you write production alert queries. Build a flow with a deliberately failing action inside a scope, run it, and inspect what lands in &lt;code&gt;dependencies&lt;/code&gt;. Ten minutes with a test flow will teach you more than any amount of reading, and your failure queries should be written against observed behavior rather than assumptions. I know so as I&#39;ve done so myself!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE 3:&lt;/strong&gt; treat the export as telemetry, not as a system of record. Microsoft is explicit that small data losses can occur due to transient service issues. The flow run history inside the Power Automate portal remains the transactional, authoritative record. Application Insights is for alerting, dashboards, and trend analysis, not for audit-grade completeness.&lt;/p&gt;

&lt;h2&gt;What about custom telemetry from inside a flow?&lt;/h2&gt;

&lt;p&gt;The export covers runs, triggers, and actions, but you may be asking, &quot;where is the Trace() function for flows?&quot; Very simple: there is no native equivalent. If you need business-level events -- &quot;vendor matched,&quot; &quot;payment batch released&quot; -- the pattern is an HTTP action posting directly to the Application Insights ingestion endpoint at &lt;code&gt;https://dc.services.visualstudio.com/v2/track&lt;/code&gt;, or preferably the regional endpoint from your resource&#39;s connection string. No authentication header is required; the instrumentation key inside the payload identifies the target resource:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;name&quot;: &quot;Microsoft.ApplicationInsights.Event&quot;,
  &quot;time&quot;: &quot;@{utcNow()}&quot;,
  &quot;iKey&quot;: &quot;&amp;lt;your-instrumentation-key&amp;gt;&quot;,
  &quot;data&quot;: {
    &quot;baseType&quot;: &quot;EventData&quot;,
    &quot;baseData&quot;: {
      &quot;name&quot;: &quot;InvoiceApprovalFlow.Step3.VendorMatched&quot;,
      &quot;properties&quot;: {
        &quot;flowRunId&quot;: &quot;@{workflow()[&#39;run&#39;][&#39;name&#39;]}&quot;,
        &quot;flowName&quot;: &quot;@{workflow()[&#39;name&#39;]}&quot;,
        &quot;environment&quot;: &quot;@{workflow()[&#39;tags&#39;][&#39;environmentName&#39;]}&quot;,
        &quot;vendorId&quot;: &quot;@{variables(&#39;vendorId&#39;)}&quot;
      },
      &quot;measurements&quot;: {
        &quot;recordsProcessed&quot;: 42,
        &quot;durationMs&quot;: 1830
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note about this payload. Events posted this way land in the &lt;code&gt;customEvents&lt;/code&gt; table. Swap &lt;code&gt;baseType&lt;/code&gt; to &lt;code&gt;TraceData&lt;/code&gt; with a &lt;code&gt;message&lt;/code&gt; and &lt;code&gt;severityLevel&lt;/code&gt; for trace-style logging, or to &lt;code&gt;ExceptionData&lt;/code&gt; for structured errors. And carrying the flow run ID in the properties gives you a correlation key back to the platform-exported tables, so your business events join cleanly against the runs and actions they belong to.&lt;/p&gt;

&lt;h3&gt;Centralize it in a child flow&lt;/h3&gt;

&lt;p&gt;Do not scatter this HTTP action across every flow you own! Build it once as a child flow -- call it something like &quot;LogTelemetry&quot; -- and have every parent flow call it as a single action. The child flow takes three inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Event name&lt;/strong&gt; (text): the dotted event identifier, such as &lt;code&gt;InvoiceApprovalFlow.Step3.VendorMatched&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Properties&lt;/strong&gt; (text): a JSON string of custom dimensions, parsed and merged into the payload inside the child&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Severity&lt;/strong&gt; (text or number): drives whether the child posts EventData, TraceData, or ExceptionData&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In turn, the child flow owns the instrumentation key, the endpoint URL, and the payload envelope. When the ingestion endpoint changes, when you rotate the key, or when you decide to enrich every event with the environment name, you change one flow instead of forty. Parent flows stay clean: one &quot;Run a child flow&quot; action per telemetry point, and no HTTP plumbing in sight.&lt;/p&gt;

&lt;p&gt;The same child flow pairs naturally with Scope-based error handling. Wrap your business logic in a Try scope, follow it with a Catch scope configured to run after &quot;has failed&quot; and &quot;has timed out,&quot; and inside the Catch use &lt;code&gt;result(&#39;Try&#39;)&lt;/code&gt; to extract the failed action details and pass them to LogTelemetry as an ExceptionData payload. That gives you structured failure telemetry carrying the actual action error, not just a run that shows red in the portal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; two constraints to know before you commit to this pattern. The HTTP connector requires premium licensing, and the raw post does not work if your Application Insights resource enforces Entra ID-only ingestion. In that case, a small Azure Function relay running the real SDK is the better shape, since a flow cannot easily perform the token acquisition against Azure Monitor scopes.&lt;/p&gt;

&lt;p&gt;And to save you the scaffolding: I built LogTelemetry exactly as described and published it as an importable solution on GitHub, over at &lt;a href=&quot;https://github.com/dgpblogster/power-automate-logtelemetry&quot;&gt;github.com/dgpblogster/power-automate-logtelemetry&lt;/a&gt;. It uses no connectors that require authentication, so the import prompts for nothing; you replace two clearly-marked CONFIG values, turn it on, and start logging. The README walks the import click by click.&lt;/p&gt;

&lt;h2&gt;The bottom line&lt;/h2&gt;

&lt;p&gt;Power Automate telemetry in Application Insights is real, admin-configured, and gated behind Managed Environments. Runs live in &lt;code&gt;requests&lt;/code&gt;; triggers and actions live in &lt;code&gt;dependencies&lt;/code&gt;. If your monitoring stops at the &lt;code&gt;requests&lt;/code&gt; table, you have built a smoke detector that tells you the building is on fire without telling you which room. The &lt;code&gt;dependencies&lt;/code&gt; table, an export package with the actions checkbox enabled, and one join on &lt;code&gt;operation_Id&lt;/code&gt; are all it takes to do better.&lt;/p&gt;

&lt;p&gt;If you have wired up this export yourself, or found other signals hiding in these tables worth querying, please drop a note in the comments describing your experience; telemetry patterns get better every time somebody shares what they found in the data.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;Mariano Gomez Bent&lt;br /&gt;Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/08/power-automate-cloud-flow-telemetry.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEii9WQxdgAykdSYgUhfp2ZM_5SH0AR4ddRhmq3AdVEnuxRxRlbp9oJVxUvKTVM1T4JTtfV_G2Zz6hjs0Xvki3N9MBzXBRDhWO0hF-h6UHy2mwad_USZ4lOHy5GxSmjzdEnAr6EpxjAs44_gt7Q_GcU-hBpmnLZ1qiAr5K4c6AG8UQJxu4UVqnKaaHawNPaE=s72-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-8241138433724031971</guid><pubDate>Fri, 21 Aug 2026 11:00:00 +0000</pubDate><atom:updated>2026-08-21T07:00:00.121-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Business Central</category><category domain="http://www.blogger.com/atom/ns#">Integration</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><title>Power Automate | Design Every Flow So a Resubmit Is Always Safe</title><description>&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Design every Power Automate flow so a resubmit is always safe&quot; height=&quot;630&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-05-resubmit.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1200&quot; /&gt;&lt;/div&gt;
&lt;p&gt;If there is one question I have learned to ask of every single action in every Power Automate flow I build, it is this one: &lt;b&gt;what happens if this runs twice?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Throughout our Business Central to Dynamics 365 CE billing integration, the same project from my previous articles in this series, we made the answer to that question a design requirement. Every flow had to produce the same correct end state whether an event arrived once, twice, or five times, and whether the runs came from the webhook, a retry, or a human clicking resubmit weeks later. So, in this article I will walk through why that requirement pays for itself many times over, the patterns that satisfy it, and the two match-key mistakes we made on the way to getting it right. Yes, it took us three attempts!&lt;/p&gt;
&lt;!--On publish: link &quot;my previous articles&quot; to the FlowAgent post--&gt;

&lt;h2&gt;Why events arrive more than once&lt;/h2&gt;

&lt;p&gt;Keep in mind, if your integration is triggered by webhooks, replays are not an edge case. They are the operating environment!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The source system fires on modification, not creation.&lt;/strong&gt; Our flows trigger on Business Central&#39;s customer ledger, where a single business event can touch several entries, and each touch fires the trigger. Guards filter the noise, but the same document can legitimately come through the front door repeatedly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repairs happen by resubmission.&lt;/strong&gt; When a run fails -- a permissions gap, a defect, an outage -- the natural fix is: repair the cause, resubmit the stored run. The trigger payload replays against the flow as it exists now.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testing happens by resubmission.&lt;/strong&gt; The fastest way to verify a flow change against real data is to resubmit a known run and inspect the result. If reprocessing old events corrupts data, you have lost your best testing tool.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Late events reprocess old ground.&lt;/strong&gt; A payment applied to an invoice months after posting triggers a reconcile over records your flow already created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, you may be asking, &quot;&lt;b&gt;&lt;i&gt;can I not just guard against each of these individually?&lt;/i&gt;&lt;/b&gt;&quot; You certainly can, and you will be maintaining those guards forever. Or you can adopt the single stronger property that covers all of them at once: every run converges the target system to the source system&#39;s current truth, no matter how many times it executes.&lt;/p&gt;

&lt;h2&gt;Sync the state, not the event&lt;/h2&gt;

&lt;p&gt;The foundational pattern is a mental shift. An event-applying flow says &quot;an invoice was posted, so create an invoice.&quot; A state-converging flow says &quot;an invoice exists in the source; make the target match it.&quot; The first duplicates on replay. The second cannot, because its writes are defined relative to what is already there.&lt;/p&gt;

&lt;p&gt;Concretely, our invoice sync is a reconciling upsert. It looks up the target invoice by the source system&#39;s document number. If it does not exist, it creates it with its lines. If it does exist, it updates the header and then reconciles the lines: match each source line to a target line, update the matches in place, create the missing, and delete the orphans that no longer exist in the source. The payment sync works exactly the same way, reconciling the payment&#39;s application detail rows against what the source says is currently applied, deleting rows the source no longer has, right down to deleting the payment header itself when zero applications remain.&lt;/p&gt;

&lt;p&gt;In turn, a reconcile has a property an append never has: it is self-healing. When we later fixed a line-mapping defect, the reconcile did not just handle new invoices correctly; rerunning it against previously damaged invoices replaced the malformed lines with correct ones. The repair tool was the flow itself!&lt;/p&gt;

&lt;h2&gt;Let the source system name things&lt;/h2&gt;

&lt;p&gt;Idempotency needs a key, and the right key is the source system&#39;s own identity for the record, carried into the target where the flow can find it again. Our payment headers are named by the Business Central document number, which makes the name double as the idempotency key: any rerun finds the header it created before. Invoices are looked up by the posted invoice number. Nothing is keyed by anything the flow generates, because a generated key is different on every run, which is precisely the property you do not want.&lt;/p&gt;

&lt;p&gt;Getting this right at the line level took us three attempts, and the two failures are worth studying, because they will save you from repeating them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt one: match lines by name.&lt;/strong&gt; As it turns out, this failed immediately, because the target system overwrites the line description with the product name on product-based lines. Our matching field was being silently rewritten by the platform after every create, so matches always missed, and every reconcile deleted and recreated every line. The lesson: never match on a field the target system considers its own to modify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt two: match lines by product ID.&lt;/strong&gt; This one worked for months. Then it failed structurally the day we met an invoice with two lines sharing one product -- a maintenance credit billed as a negative line on the same product code it credits. The reconcile saw the product already present and concluded the credit line was already synced. It was not a bug in the matching code; the key itself could not distinguish the rows. Worse, the failure mode was silent: the reconcile ran, reported success, and structurally could never repair the missing line. Suffice to say, a key that is merely usually unique is a defect with a delayed fuse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt three: match lines by the source system&#39;s line number,&lt;/strong&gt; stamped into a dedicated field on every line the flow writes. Business Central&#39;s line numbers are the source&#39;s own identity for the row: unique within the document, stable across time, and meaningless for the target platform to overwrite. Every line create and update stamps it; matching and orphan detection key on it. This is the version that survived every scenario we could throw at it.&lt;/p&gt;

&lt;p&gt;The general rule that falls out: &lt;strong&gt;the match key must be the source system&#39;s identity for the row, persisted in the target, and owned by nobody else.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A quick aside before moving on: both failures were diagnosed in minutes rather than an afternoon of clicking through run history, because we develop these flows with Claude Code reading run actions directly through FlowAgent. The agent walked the failed runs, found the exact action and input responsible each time, and in the second case also exposed that the product-keyed reconcile could never have repaired the damage. That workflow is a story of its own, and I told it in my FlowAgent article; here it is enough to say that resubmit-safe design and run forensics compose beautifully -- one gives you a safe repair tool, and the other tells you precisely when to use it.&lt;/p&gt;
&lt;!--On publish: link &quot;my FlowAgent article&quot; to the Building Power Automate Flows with Claude Code and FlowAgent post--&gt;

&lt;h2&gt;Gate the side effects on change&lt;/h2&gt;

&lt;p&gt;Data writes converge naturally under a reconcile, but side effects -- notifications, timeline notes, cascade triggers -- duplicate cheerfully unless you design them not to. Two patterns handled every case we had:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attach side effects to transitions, not to runs.&lt;/strong&gt; Our settlement timeline notes are written only when a detail row is actually created, only when a synced row is actually deleted, and only on the first sighting of a cancellation, guarded by &quot;the invoice is not already cancelled.&quot; A resubmitted run that changes nothing writes no note, because no transition occurred. We proved this on a live rerun: identical resubmit, zero writes, zero duplicate notes. The note trail reads like a history precisely because it records transitions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write only when the value differs.&lt;/strong&gt; Our bundle cascade flow updates a child record only if its expiration differs from the parent&#39;s or the row is inactive. That single guard makes the cascade convergent: reprocessing is free, and a chain of cascading updates terminates on its own -- five runs, converged, no runaway, in our live verification. As a bonus we did not initially design for, the flow can safely react to writes made by other flows sharing its connection identity, because reacting to an already-correct value is a no-op.&lt;/p&gt;

&lt;h2&gt;The payoff: resubmit becomes your universal tool&lt;/h2&gt;

&lt;p&gt;Once every flow held the property, resubmission quietly became the answer to almost everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repairs.&lt;/strong&gt; When the credit-line defect left two invoices wrong in the target system, the repair was: deploy the fix, resubmit the two failed runs. Both invoices converged to the source&#39;s truth to the penny, replacing the malformed legacy lines on the way. No repair script, no manual edits!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environment fixes.&lt;/strong&gt; When a run failed on a missing privilege in a fresh environment, the fix was the role assignment plus one resubmit, which completed the scenario and re-proved reconcile idempotence in that environment for free.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verification.&lt;/strong&gt; Every flow change was tested by resubmitting a stored run and reading the results, precisely because reprocessing was guaranteed harmless.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Locked-record handling.&lt;/strong&gt; Even where the target system makes records read-only -- paid invoices, in our staging environment -- the reconcile wraps its work in a capture-state, reopen, sync, restore sequence, so a resubmit against a paid invoice succeeds and leaves the record exactly as it found it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Two caveats from the field&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; a resubmit replays the trigger payload against the &lt;em&gt;current&lt;/em&gt; flow definition. That is exactly what makes fix-then-resubmit work, but it has a sharp edge: if a deployment has left the flow stopped, a resubmit silently replays against the old definition, and the result can masquerade as a test outcome. It happened to us exactly once, which was enough to add &quot;verify the flow is active and read the definition back&quot; to the deployment checklist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; idempotency does not replace concurrency control. Convergent runs racing each other can still interleave reads and writes. We run our webhook-triggered flows at concurrency one, not because the design needs it to be correct in sequence, but as cheap insurance that runs actually execute in sequence. The two properties compose: idempotency makes replays safe, and serialization makes overlaps impossible.&lt;/p&gt;

&lt;h2&gt;The checklist&lt;/h2&gt;

&lt;p&gt;For every flow, before it ships, walk through the following five questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Can I resubmit any historical run right now with no damage? If not, why not? Fix that first.&lt;/li&gt;
&lt;li&gt;Is every record the flow writes findable by a key the source system owns?&lt;/li&gt;
&lt;li&gt;Does the flow reconcile to current source truth, including deleting what the source no longer has?&lt;/li&gt;
&lt;li&gt;Is every notification and note attached to a transition, not to a run?&lt;/li&gt;
&lt;li&gt;Does every cascading write fire only when the value actually differs?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When it&#39;s all said and done, the cost is a habit of mind during design, and the return is an integration where the scariest phrase in operations, &quot;just run it again,&quot; is not scary at all. It is the standard procedure, and it is always safe.&lt;/p&gt;

&lt;p&gt;If you have your own resubmit war story, or a match key that failed you in a way I did not list here, please drop a note in the comments describing your experience; idempotency lessons are expensive to learn firsthand and free to learn from each other.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;Mariano Gomez Bent&lt;br /&gt;Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/08/power-automate-design-every-flow-so.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-7677422031119209399</guid><pubDate>Wed, 19 Aug 2026 11:00:00 +0000</pubDate><atom:updated>2026-08-19T07:00:00.121-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Azure Key Vault</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><category domain="http://www.blogger.com/atom/ns#">Security</category><title>Power Automate | Getting Secrets Out of Your Flows with Azure Key Vault</title><description>&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Getting secrets out of your Power Automate flows with Azure Key Vault&quot; height=&quot;630&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-04-keyvault.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1200&quot; /&gt;&lt;/div&gt;
&lt;p&gt;The flow we inherited at the start of our Business Central to Dynamics 365 CE billing integration, the same project from my FlowAgent article, had a problem so common it barely registers as a problem anymore: the OAuth client secret it used to call Business Central&#39;s OData services was sitting in plaintext, inside a String environment variable, referenced by the flow as an ordinary parameter. Everything worked. Nothing was on fire. And that secret was quietly everywhere!&lt;/p&gt;
&lt;!--On publish: link &quot;my FlowAgent article&quot; to the Building Power Automate Flows with Claude Code and FlowAgent post--&gt;

&lt;p&gt;So, in this article I will walk through where &quot;everywhere&quot; turns out to be, and the migration we ran to fix it: a secret-type environment variable backed by Azure Key Vault, runtime retrieval inside the flow, secured inputs and outputs, and a cleanup pass that chased the old secret out of every place it had settled. I will also cover the one gotcha that failed our first live run, because keep in mind, it will fail yours too if you do not know about it.&lt;/p&gt;

&lt;h2&gt;Where a plaintext secret actually lives&lt;/h2&gt;

&lt;p&gt;When a secret sits in a flow definition or a plaintext environment variable, it does not live in one place. It lives in every place the definition travels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Every solution export.&lt;/strong&gt; The environment variable&#39;s value rides along in the zip. Email that zip to a colleague, attach it to a ticket, or drop it in a shared folder, and the secret goes with it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run history.&lt;/strong&gt; If the secret flows through an ordinary action, every run&#39;s inputs and outputs display it to anyone with permission to read run history -- and that audience is usually much larger than the audience you would knowingly hand a credential to.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source control.&lt;/strong&gt; The moment you bring the solution under version control, which you absolutely should, the plaintext secret is in a commit, and commits are forever. Rotating the secret later does not un-commit the old one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backups and working files.&lt;/strong&gt; Any tooling that snapshots flow definitions -- designer copies, local backups, agent working files -- multiplies the copies further.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these is hypothetical. We found our inherited secret in the solution export, in the flow definition, in run history via the token request&#39;s visible inputs, and, once we started working, in the local backup snapshots our own tooling captured. The secret had more copies than the flow had actions!&lt;/p&gt;

&lt;p&gt;The fix Microsoft provides for exactly this scenario is the &lt;strong&gt;secret-type environment variable&lt;/strong&gt;: instead of storing a value, it stores a pointer to a secret in Azure Key Vault, and the flow retrieves the value at runtime. In turn, the vault becomes the only place the secret exists. Everything that travels -- the solution, the source tree, the definition -- carries only the pointer.&lt;/p&gt;

&lt;h2&gt;The migration, in the order that worked&lt;/h2&gt;

&lt;p&gt;We did this as a single day&#39;s remediation, and as it turns out, the sequencing mattered as much as the steps. Here is the order, with the reasoning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Set up Key Vault RBAC first.&lt;/strong&gt; Secret-type environment variables only support Azure Key Vault as the store, and two identities need roles on the vault before anything else works: the person doing the setup needs to write the secret and pass the environment variable&#39;s save-time validation (Key Vault Secrets Officer covers both), and the Dataverse service principal needs Key Vault Secrets User so the platform can retrieve the value at runtime. Also confirm the Power Platform resource provider is registered on the subscription that owns the vault; it is a one-time thing, and a confusing failure if it is missing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Rotate by appending, and never look at the new secret.&lt;/strong&gt; We did not migrate the old secret; we replaced it. The new client secret was created on the app registration with an append, leaving the old credential intact so the running flow never broke during the migration, and piped directly from the creation command into the vault in a single step. The value was never displayed on screen, never in a file, never in shell history. Keep in mind: if your new secret is ever visible, you have created another copy to worry about. The pipe means there is nothing to clean up afterward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) Create the secret-type environment variable, and get the reference format right.&lt;/strong&gt; The variable lives in the solution like any other environment variable, but its value record contains only a pointer to the secret, and the form of that pointer is the part that stopped us cold, because it is not what instinct suggests. It is not the secret&#39;s URL from the Azure portal, and it is not a vault name and secret name pair. It is the secret&#39;s full Azure &lt;strong&gt;resource ID path&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.KeyVault/vaults/{vault-name}/secrets/{secret-name}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note here. Every segment is required, including the &lt;code&gt;providers/Microsoft.KeyVault&lt;/code&gt; in the middle that nobody types from memory. If you create the variable through the maker portal, the form collects the pieces separately and assembles the path for you; if you create it through the Web API, or find yourself editing the value record directly, you supply the whole path yourself, and anything else fails validation. The save is also more than a format check: Dataverse resolves the path against Azure with your permissions at save time, so a typo in any segment, or a missing role on the vault, surfaces right there rather than at the first flow run. That is a kindness once you understand it, and a mystifying save error until you do!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; export the solution afterward and inspect it; you should see the resource path and nothing else. We made this check part of the verification, not an assumption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4) Prove retrieval with a throwaway flow before touching the real one.&lt;/strong&gt; You may be asking, &quot;can I just test the retrieval from the Web API?&quot; Categorically no! Secrets in secret-type environment variables are only resolvable from inside flows and custom connectors, and that is by design. So we built a disposable test flow whose only job was to call &lt;code&gt;RetrieveEnvironmentVariableSecretValue&lt;/code&gt; and succeed, ran it, confirmed the retrieval, and deleted it. Two minutes of scaffolding, and the real flow&#39;s rewire started from a known-good vault path instead of debugging two things at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5) Rewire the flow, and secure both ends.&lt;/strong&gt; The real flow gained one action: a Dataverse unbound action call to &lt;code&gt;RetrieveEnvironmentVariableSecretValue&lt;/code&gt; for the new variable, with &lt;strong&gt;secured inputs and outputs&lt;/strong&gt; turned on. The token request was repointed to consume that action&#39;s output, and it got secured inputs and outputs as well. That second part is easy to forget and matters just as much: the client secret passes through the token request, and the bearer token that comes back is itself a credential. With both actions secured, neither the secret nor the token appears in run history anymore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6) Add a graceful failure path.&lt;/strong&gt; A vault outage or a permissions change now has a single, well-defined failure point, so we gave it a dedicated handler: an alert email carrying the run ID and the likely causes, then a Terminate with a named error code. Without this, a retrieval failure dies mid-run with secured -- and therefore blank -- diagnostics, which brings us to the gotcha in a moment.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhiwa9cvh8TajkcxBTT-T_F0b_6Udz46RdQ9RkijSVxKcSKn7-xFORQwlqMLJ1v08Jzx63RmHuqx3ATjZpj81pHV3r4774fxZ2_CRflcx6XqOCPcjUG5UT9JhirT9g92hDVvJHZRz1zft3GpmGkr_FuPjyGfFwMvYo4RrWGH93b5djY8CAdmnYLLJiyMmyb&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1048&quot; data-original-width=&quot;762&quot; height=&quot;419&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhiwa9cvh8TajkcxBTT-T_F0b_6Udz46RdQ9RkijSVxKcSKn7-xFORQwlqMLJ1v08Jzx63RmHuqx3ATjZpj81pHV3r4774fxZ2_CRflcx6XqOCPcjUG5UT9JhirT9g92hDVvJHZRz1zft3GpmGkr_FuPjyGfFwMvYo4RrWGH93b5djY8CAdmnYLLJiyMmyb=w306-h419&quot; width=&quot;306&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center; font-size: 0.9em; margin: 0.4em 0 1.4em;&quot;&gt;&lt;em&gt;Graceful failure path&lt;/em&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;strong&gt;7) Clean up until a search proves you are done.&lt;/strong&gt; The old plaintext environment variable and the flow parameter that referenced it were deleted; a forgotten draft copy of the flow held the last dependency and had to go first, which the dependency checker told us. Then we searched the entire synced source tree for any fragment of the old secret and did not stop until the search came back empty. Local backup snapshots that predated the fix still contained it, so they went into &lt;code&gt;.gitignore&lt;/code&gt;. Only after the tree was provably secret-free did the repository get its first commit. That ordering is worth stating plainly: &lt;strong&gt;git init comes after the secret hunt, not before.&lt;/strong&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8) Hand the old secret off for rotation.&lt;/strong&gt; The old credential was left working throughout the migration and then handed to the system administrator to rotate, after checking whether anything else used it. In our case, something else probably did, which is its own small lesson: plaintext secrets get shared around precisely because they are visible, and you cannot assume you are the only consumer.&lt;/p&gt;

&lt;h2&gt;The gotcha: runtime RBAC follows the connection owner&lt;/h2&gt;

&lt;p&gt;Our first live-fire test failed at the secret retrieval with a BadRequest and no details, because secured outputs hide details by design. The error handling worked beautifully -- alert sent, run terminated cleanly, zero partial writes -- but the diagnosis took some actual thought, so here it is for free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Dataverse validates the vault RBAC of the calling user, and the calling user is the owner of the Dataverse &lt;em&gt;connection&lt;/em&gt; the flow uses, not the person who built the flow. As it turns out, our earlier test flow had succeeded because it ran on the author&#39;s own connection, and the author had vault roles. The production flow ran on a shared connection owned by a service account that had none. Granting Key Vault Secrets User to that service account fixed it, and the resubmitted run passed end to end.&lt;/p&gt;

&lt;p&gt;The practical rule: enumerate every identity that will ever own a connection your flow runs on, in every environment, and grant each one Secrets User on the vault. And when the retrieval fails with hidden diagnostics, check connection ownership before anything else. It is the most likely cause and the least visible one.&lt;/p&gt;

&lt;h2&gt;The payoff shows up at deployment time&lt;/h2&gt;

&lt;p&gt;Weeks later, when we deployed the solution to a staging environment through a Power Platform pipeline, the secret story was the part that just worked. The secret-type environment variable&#39;s vault reference traveled with the solution; no secret value needed to be supplied at import, because there is no secret value in the solution. The only per-environment chore is the RBAC grant for that environment&#39;s connection-owning identity, and the first live run tells you immediately whether you missed it, through the graceful failure path built in step 6.&lt;/p&gt;

&lt;p&gt;Now, compare that with the plaintext alternative, where every deployment either carries the secret in the zip or prompts someone to paste it in. Both of those mint fresh copies. It just doesn&#39;t work!&lt;/p&gt;

&lt;h2&gt;The other half: everything else into environment variables too&lt;/h2&gt;

&lt;p&gt;The secret was the dangerous case, but the same remediation pass moved every per-environment value out of the flow definition and into ordinary environment variables: tenant ID, company ID, environment name, target system record IDs, alert recipients, and a set of sandbox-only test toggles. Two decisions there proved right in hindsight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ship no values in the solution for anything environment-specific.&lt;/strong&gt; An import that prompts is a feature; a value that silently travels to the wrong environment is a defect waiting to be discovered in production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make the flow&#39;s behavior mode explicit.&lt;/strong&gt; A Sandbox/Production mode variable, with test toggles honored only in Sandbox mode, means production can never accidentally run with a test configuration. The gate rule lives in the flow once, not scattered across conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When it&#39;s all said and done, you end up with a flow definition that has no secrets, no environment names, no GUIDs, and no email addresses in it. Everything that varies is a variable, and the one thing that must not leak is a pointer to a vault. That is the whole trick, and a day of careful sequencing is all it costs.&lt;/p&gt;

&lt;p&gt;If you run this migration yourself, or if you have chased a plaintext secret through more hiding places than the ones I listed here, please drop a note in the comments describing your experience; these war stories are how the community keeps each other&#39;s credentials out of run history.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;Mariano Gomez Bent&lt;br /&gt;Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/08/power-automate-getting-secrets-out-of.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEhiwa9cvh8TajkcxBTT-T_F0b_6Udz46RdQ9RkijSVxKcSKn7-xFORQwlqMLJ1v08Jzx63RmHuqx3ATjZpj81pHV3r4774fxZ2_CRflcx6XqOCPcjUG5UT9JhirT9g92hDVvJHZRz1zft3GpmGkr_FuPjyGfFwMvYo4RrWGH93b5djY8CAdmnYLLJiyMmyb=s72-w306-h419-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-8965672142025405958</guid><pubDate>Mon, 17 Aug 2026 11:00:00 +0000</pubDate><atom:updated>2026-08-17T07:00:00.177-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ALM</category><category domain="http://www.blogger.com/atom/ns#">DevOps</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><title>One Solution, Two Source Trees: The Maker Portal&#39;s Git Integration vs pac</title><description>&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;One Solution, Two Source Trees: maker portal Git integration versus pac&quot; height=&quot;630&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-03-git-pac.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1200&quot; /&gt;&lt;/div&gt;
&lt;p&gt;Early in our Business Central to Dynamics 365 CE billing integration, the same project I wrote about in my &lt;a href=&quot;https://www.theworkbench.blog/2026/08/building-power-automate-flows-with.html&quot; target=&quot;_blank&quot;&gt;FlowAgent article&lt;/a&gt;, we ran into a lesson that Microsoft&amp;#39;s own documentation only caught up to this spring, and that I have not seen written up from the trenches: there are now two official ways to put a Power Platform solution under source control, and they do not mix. At all! We learned this the day we put the solution source pac had cloned next to the solution source the maker portal&#39;s Git integration had committed, and found two completely different structures staring back at us.&lt;/p&gt;


&lt;p&gt;So, in this article I will walk through the two formats, how the collision showed up in our project, and why we picked the CLI side, with a couple of smaller git-versus-pac frictions at the end that you will want to know about before you start.&lt;/p&gt;

&lt;h2&gt;Two formats, one solution&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The classic XML format&lt;/strong&gt; is what &lt;code&gt;pac solution clone&lt;/code&gt;, &lt;code&gt;pac solution sync&lt;/code&gt;, and the traditional &lt;a href=&quot;https://learn.microsoft.com/power-platform/alm/solution-packager-tool&quot;&gt;SolutionPackager&lt;/a&gt; workflow produce. The solution&#39;s identity lives in &lt;code&gt;Other\Solution.xml&lt;/code&gt; and &lt;code&gt;Other\Customizations.xml&lt;/code&gt;, and the component files (workflow JSON, environment variable definitions, connection references) sit in a folder hierarchy alongside them. Keep in mind this is the format that pairs with the round-trip commands: &lt;code&gt;pac solution pack&lt;/code&gt; builds an importable zip from the folder, &lt;code&gt;pac solution import&lt;/code&gt; pushes it to the environment, and &lt;code&gt;pac solution sync&lt;/code&gt; pulls the environment&#39;s current state back down.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjVJtSD3ss43jgqAPw8AeYT3fO0BYpiChiqAqLmYQ18yTOGKgiwmbu2q4drMnjWHunrOUZsLZ-svgOsW_mzy-tvQPG5F9UsUKhjkNCZaBitiaio2EIawsk5nPznaBIYVGOpXStoM7OVsKwOHYecT1tkGbijuftmW81Kzhn8jxCfNOxIi4VbV0_2KF0agVKb&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;693&quot; data-original-width=&quot;633&quot; height=&quot;570&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjVJtSD3ss43jgqAPw8AeYT3fO0BYpiChiqAqLmYQ18yTOGKgiwmbu2q4drMnjWHunrOUZsLZ-svgOsW_mzy-tvQPG5F9UsUKhjkNCZaBitiaio2EIawsk5nPznaBIYVGOpXStoM7OVsKwOHYecT1tkGbijuftmW81Kzhn8jxCfNOxIi4VbV0_2KF0agVKb=w521-h570&quot; width=&quot;521&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 0.9em; margin: 0.4em 0px 1.4em; text-align: center;&quot;&gt;&lt;em&gt;Classic XML Format&lt;/em&gt;&lt;/div&gt;&lt;br /&gt;&lt;strong&gt;The &lt;a href=&quot;https://learn.microsoft.com/power-platform/alm/solution-source-control-yaml-format&quot;&gt;YAML source control format&lt;/a&gt;&lt;/strong&gt; is what the maker portal&#39;s native &lt;a href=&quot;https://learn.microsoft.com/power-platform/alm/git-integration/overview&quot;&gt;Git integration&lt;/a&gt; writes. When you connect an environment or a solution to Azure DevOps from within Power Apps, every commit lands as a &lt;code&gt;solutions\&amp;lt;name&amp;gt;\solution.yml&lt;/code&gt; manifest with component folders at the repository root. I will be the first to tell you it is a genuinely nicer format to read: compact YAML, small focused diffs, and support for canvas apps and modern flows that the XML layout never handled. It is also, and this is the entire point of this article, a different representation that the classic tooling chain does not interoperate with.&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjsbZTOjRDQMljVlwCsdza-yWxMUBTwiRt0v4V9beS7O6Z6SUwbpMRDoyFnIq5eGw6b-OVk7kRmtdbguUAIg1kdMpyEN3IbsXKiCYDoqwntqOcF2p1B9AnnWiHiQYZ3_Bblg1naYGx4R1vnFAazygpMwXkq7_oz86honTi7x8gqGlKFDwBuEsYGKHoKIv-F&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;859&quot; data-original-width=&quot;671&quot; height=&quot;674&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjsbZTOjRDQMljVlwCsdza-yWxMUBTwiRt0v4V9beS7O6Z6SUwbpMRDoyFnIq5eGw6b-OVk7kRmtdbguUAIg1kdMpyEN3IbsXKiCYDoqwntqOcF2p1B9AnnWiHiQYZ3_Bblg1naYGx4R1vnFAazygpMwXkq7_oz86honTi7x8gqGlKFDwBuEsYGKHoKIv-F=w527-h674&quot; width=&quot;527&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 0.9em; margin: 0.4em 0px 1.4em; text-align: center;&quot;&gt;&lt;em&gt;YAML Format&lt;/em&gt;&lt;/div&gt;&lt;br /&gt;Now, here is the part that will save you an afternoon of head scratching. The packager tools decide which format they are looking at by folder shape. A &lt;code&gt;solutions\&lt;/code&gt; subdirectory containing &lt;code&gt;solution.yml&lt;/code&gt; files means YAML; no &lt;code&gt;solutions\&lt;/code&gt; subdirectory means classic XML, in which case the tool goes looking for &lt;code&gt;Other\Solution.xml&lt;/code&gt;. There is no flag that says &quot;this repo contains both, figure it out.&quot;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; a folder that mixes the two layouts, or that has YAML files in the wrong place, produces the format war&#39;s signature error: a complaint about a missing &lt;code&gt;Customizations.xml&lt;/code&gt; from a tool that has silently fallen back to the XML code path while staring at YAML files. If you have ever seen that error and thought &quot;but this is not an XML solution,&quot; congratulations, you have met the auto-detection rules! And as of this spring, Microsoft&amp;#39;s SolutionPackager documentation carries a troubleshooting entry for exactly this case, describing the silent fallback and calling the error misleading in so many words. It is good to see it written down; it would have been better to read it before we found it.&lt;/p&gt;

&lt;h2&gt;What happened to us&lt;/h2&gt;

&lt;p&gt;Our source control story started deliberately. On the first day, we ran &lt;code&gt;pac solution clone&lt;/code&gt; against the inherited invoice flow&#39;s solution, dropped the XML source tree into a folder, and began a discipline we have kept ever since: the cloud flow is the working copy, the local tree is the versioned mirror, and after every applied change we run &lt;code&gt;pac solution sync&lt;/code&gt;, write a changelog entry, and commit. That loop was not an accident. Our whole development approach, an AI coding agent editing flow definitions, packing them, and importing them, depends on having the real definition JSON locally and being able to round-trip it through &lt;code&gt;pac solution pack&lt;/code&gt; and &lt;code&gt;pac solution import&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then the maker portal&#39;s Git integration entered the picture, the way it enters most pictures: it is right there in the portal, connecting a solution to a repo takes a few clicks, and it feels like the officially blessed path. And it is a blessed path! It is just a different one, and it wants to own the repository in its own format.&lt;/p&gt;

&lt;p&gt;Now, the moment the incompatibility became real for us was not an error message; it was a side-by-side comparison. We put the tree pac had cloned next to the repository the portal&#39;s Git integration had committed, expecting two views of the same solution, and found two structures with almost nothing in common: different file names, different nesting, different serialization, and no file on one side corresponding one-to-one with a file on the other. This was not two dialects that a diff tool could reconcile. There was nothing to diff. Nothing! Keep in mind, that comparison is worth doing deliberately if you are facing the same choice, because it settles the question faster than any documentation will.&lt;/p&gt;

&lt;p&gt;And once you have seen it, the operational hazard is obvious: had both stayed connected, every portal commit and every &lt;code&gt;pac solution sync&lt;/code&gt; would have written its own divergent truth into the same repo, with the packager&#39;s auto-detection deciding which one it believed based on which folders it noticed first. Nothing about that fails loudly at the moment you set it up. It fails later, confusingly, in tooling errors that point at the wrong cause. A repository is going to hold one format or the other, and somebody has to choose.&lt;/p&gt;

&lt;p&gt;So we chose, and wrote it down: this solution is versioned in the classic XML format maintained by pac, the maker portal&#39;s Git integration was deliberately disconnected, and the README carries a standing instruction, in bold, that says do not reconnect it. That last part matters more than it looks. The portal integration is a checkbox any admin can re-enable in a moment of tidiness, and the person who re-enables it will genuinely believe they are improving your source control posture. Suffice to say, that one bolded line in the README is the cheapest insurance we bought all week.&lt;/p&gt;
&lt;h2&gt;Why we picked the pac side&lt;/h2&gt;

&lt;p&gt;You may be asking, &quot;so is the YAML format bad?&quot; Not at all. On a fresh project with canvas apps in the mix, the YAML format and the portal integration are very likely the right choice, and Microsoft&#39;s direction of travel is clearly toward it. We picked the XML side for three reasons specific to how we work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) The round-trip commands are our development loop, not just our backup.&lt;/strong&gt; Large flow edits in our project go through the solution route: edit the definition JSON locally, then &lt;code&gt;pac solution pack&lt;/code&gt;, &lt;code&gt;pac solution import&lt;/code&gt;, and publish. The clone and sync commands our loop depends on produce the classic XML format, and as I write this they still do not emit the YAML layout, whatever the documentation implies (there is &lt;a href=&quot;https://github.com/microsoft/powerplatform-build-tools/issues/1385&quot;&gt;an open issue&lt;/a&gt; on exactly that). Choosing the portal&#39;s format would have meant choosing away the loop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Commit cadence and commit meaning.&lt;/strong&gt; The portal integration commits when a maker clicks commit, at whatever granularity the portal batches. Our discipline is one commit per applied change, pushed immediately, with a changelog entry stating what changed, why, where it was applied, and how it was verified. In turn, that kind of history only happens when the same actor making the change also makes the commit, which in our case is the agent completing its edit-sync-log-commit ritual. The repository is not a backup of the solution; it is the audit trail of the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) One writer per repository.&lt;/strong&gt; Even if the formats had been compatible, two independent processes committing to the same branch on their own schedules is a merge conflict generator. A source control setup where you cannot predict who writes next is worse than either setup alone. It just doesn&#39;t work!&lt;/p&gt;

&lt;h2&gt;Two frictions that come with the pac side&lt;/h2&gt;

&lt;p&gt;Choosing pac did not end the git-versus-pac story. Two smaller frictions followed, both consequences of letting a CLI own the source tree, and both are worth knowing before you start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line endings.&lt;/strong&gt; Git on Windows helpfully converts line endings unless told otherwise, and pac-generated source trees do not want the help. Every &lt;code&gt;pac solution sync&lt;/code&gt; after a fresh clone produced walls of CRLF warnings and threatened noisy whitespace-only diffs. The fix was repo-local: set &lt;code&gt;core.autocrlf=input&lt;/code&gt; in the repository config, and add a &lt;code&gt;.gitattributes&lt;/code&gt; marking the pac-generated source trees as &lt;code&gt;-text&lt;/code&gt; so git stops converting them entirely. The solution source is machine-generated and machine-consumed; git should store it byte for byte and stay out of the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Byte order marks.&lt;/strong&gt; A later sync quietly restored UTF-8 byte order marks on files where our editing had stripped them, which showed up as mysterious whole-file diffs on files nobody had meaningfully changed. We widened the &lt;code&gt;.gitattributes&lt;/code&gt; coverage and learned the larger lesson: treat the pac tree as pac&#39;s territory. Our edits happen there when the loop requires it, but the formatting conventions are the tool&#39;s, and fighting them costs more than accepting them. Fence the pac tree off from git&#39;s text handling with &lt;code&gt;.gitattributes&lt;/code&gt; the day you create it, not the day the warnings annoy you.&lt;/p&gt;

&lt;h2&gt;What I would tell you to do&lt;/h2&gt;

&lt;p&gt;Whichever side you land on, two practices carry over to any project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Pick one format before the first commit, and never let both write to the same repository.&lt;/strong&gt; If your workflow lives in the CLI round-trip commands, take the classic XML format. If you are starting fresh, especially with canvas apps or a team of makers committing from the portal, take the YAML format and let the portal integration own the repo. Either way, if someone has already connected the other one, disconnect it before it writes a single commit. Divergence is silent, and cleanup is manual.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write the decision down where the next admin will trip over it.&lt;/strong&gt; A bolded &quot;do not reconnect the Git integration for this solution&quot; in the README, with one sentence of why, will save a future colleague from an afternoon of &lt;code&gt;Customizations.xml&lt;/code&gt; errors on a repository full of YAML.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The two-format situation is a snapshot of a platform mid-transition, and it should resolve as the newer format&#39;s tooling support fills in. Until it does, keep in mind the failure mode is not that either path is broken. Both paths work, both look official, and nothing warns you that they cannot coexist in the same repository. Consider yourself warned!&lt;/p&gt;
&lt;p&gt;If you have hit the two-format collision yourself, or found a cleaner way through it, please drop a note in the comments describing your experience; this corner of Power Platform ALM has very little written about it, and the community learns fastest when we compare scars.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;Mariano Gomez Bent&lt;br /&gt;Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/08/one-solution-two-source-trees-maker.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEjVJtSD3ss43jgqAPw8AeYT3fO0BYpiChiqAqLmYQ18yTOGKgiwmbu2q4drMnjWHunrOUZsLZ-svgOsW_mzy-tvQPG5F9UsUKhjkNCZaBitiaio2EIawsk5nPznaBIYVGOpXStoM7OVsKwOHYecT1tkGbijuftmW81Kzhn8jxCfNOxIi4VbV0_2KF0agVKb=s72-w521-h570-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-7409906273057442616</guid><pubDate>Thu, 13 Aug 2026 11:00:00 +0000</pubDate><atom:updated>2026-08-13T07:00:00.121-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">AI</category><category domain="http://www.blogger.com/atom/ns#">Claude Code</category><category domain="http://www.blogger.com/atom/ns#">MCP</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><title>Building Power Automate Flows with Claude Code and FlowAgent</title><description>&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Building Power Automate Flows with Claude Code and FlowAgent&quot; height=&quot;630&quot; src=&quot;https://raw.githubusercontent.com/dgpblogster/theworkbench-assets/main/covers/cover-02-flowagent.png&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1200&quot; /&gt;&lt;/div&gt;
&lt;!--Cover hosted on GitHub; optionally re-upload via the Blogger editor for Google-hosted images--&gt;
&lt;p&gt;For the past week, my team and I have been heads-down building a Business Central to Dynamics 365 CE billing integration: posted sales invoices, applied cash receipts, subscription cancellations, and the product registry automation that ties them all together. Every one of those integrations is a Power Automate cloud flow, and every one of them was developed, debugged, and verified with &lt;b&gt;Claude Code&lt;/b&gt; driving Power Automate directly, through a tool called &lt;b&gt;FlowAgent&lt;/b&gt;. Suffice to say, this changed how I think about building flows, so I figured I would write up what we learned while it is still fresh.&lt;/p&gt;

&lt;p&gt;Now, keep in mind this is not a review written after a demo. This is written after shipping three production-bound flows through dozens of iterations, a full test campaign, and a healthy number of defects found and fixed along the way. The scars are real!&lt;/p&gt;

&lt;h2&gt;What FlowAgent is&lt;/h2&gt;

&lt;p&gt;FlowAgent is an MCP server that ships inside the &lt;strong&gt;power-automate&lt;/strong&gt; plugin from the good folks at Microsoft, published in the open source &lt;a href=&quot;https://github.com/microsoft/power-platform-skills&quot;&gt;power-platform-skills&lt;/a&gt; repository. MCP, the Model Context Protocol, is the standard that lets an AI coding assistant call real tools instead of just talking about them. Once the plugin is installed, Claude Code gains a set of Power Automate operations it can invoke on its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List environments and flows, and set a working environment and current flow&lt;/li&gt;
&lt;li&gt;Read a flow&#39;s full definition -- this is, the JSON under the designer&lt;/li&gt;
&lt;li&gt;Edit, validate, and publish flows&lt;/li&gt;
&lt;li&gt;Read run history, run details, and per-action inputs and outputs from any run&lt;/li&gt;
&lt;li&gt;Inspect connections, connectors, and operation schemas&lt;/li&gt;
&lt;li&gt;Search connector operations and get expression help&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plugin also bundles a Microsoft Learn MCP server, so the assistant can pull official documentation while it works, plus a set of skills -- guided workflows -- for creating, debugging, and diagnosing flows.&lt;/p&gt;

&lt;p&gt;You may be asking, &quot;why does this matter when the assistant can already tell me what to build?&quot; Very simple: without FlowAgent, the AI describes a flow and you go click it together in the designer. With FlowAgent, the assistant reads the actual flow, makes the actual edit, publishes it, watches the actual run, and reads the actual error. The feedback loop that used to run through your eyes and your mouse now runs at tool speed.&lt;/p&gt;

&lt;h2&gt;Setting it up&lt;/h2&gt;

&lt;p&gt;The prerequisites are modest: Claude Code, Node.js, the Azure CLI logged into your tenant -- FlowAgent uses it for authentication -- and ideally the Power Platform CLI (&lt;code&gt;pac&lt;/code&gt;) for solution work. Installation is two commands from within Claude Code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude plugin marketplace add microsoft/power-platform-skills
claude plugin install power-automate@power-platform-skills&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note before moving on. The first command registers Microsoft&#39;s repository as a plugin marketplace; the second installs the power-automate plugin from it. After both commands complete, restart your Claude Code session, because plugins attach at session start. Then run the plugin&#39;s setup skill once: it verifies Node, the Azure CLI login, and the Power Automate token, and lets you pin a working environment so every later operation lands where you expect.&lt;/p&gt;

&lt;p&gt;Two lessons from our own installation that may save you an afternoon:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; check which Claude Code binary you are actually running. We had an old standalone CLI on the PATH that predated the plugin system entirely, and it silently swallowed the &lt;code&gt;plugin&lt;/code&gt; subcommands as if they were prompts. The VS Code extension ships a current CLI in its &lt;code&gt;resources\native-binary&lt;/code&gt; folder; that one worked immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; do not hand-edit the plugin registration files. Our first attempt at manual registration produced a &quot;marketplace configuration corrupted&quot; state that even blocked removal. Resetting the marketplace file and using the real CLI commands fixed it in minutes.&lt;/p&gt;

&lt;h2&gt;Debugging: the single biggest win&lt;/h2&gt;

&lt;p&gt;When a flow fails, the assistant pulls the run, walks the failed action, reads its exact inputs and outputs, and correlates all of it with the flow definition in one pass. Early in the project, this alone paid for the whole setup. As it turns out, our invoice flow had been silently broken for about two weeks, because the web services it called no longer existed, and the failure was masked by trigger noise. Two weeks! Nobody noticed, and frankly, nobody was going to: reading run histories systematically across hundreds of runs is exactly the kind of work a human never quite gets around to. Claude Code found it, remapped both HTTP calls to the replacement services, and verified the fix against a live run.&lt;/p&gt;

&lt;p&gt;The same loop caught subtler things. A negative credit line on an invoice was failing because the CRM connector rejects negative discount amounts. The failed runs told the whole story: header created, positive line created, credit line refused. Reading the actual action outputs turned a vague &quot;totals are off in CRM&quot; report into a precise defect, a designed fix, and a verified repair, all inside one working session.&lt;/p&gt;

&lt;h2&gt;Edits go where edits belong&lt;/h2&gt;

&lt;p&gt;Our standing rule became: the cloud flow is the working copy, and the local solution source is the versioned mirror. Small, surgical changes go through FlowAgent&#39;s edit and publish tools. After every applied change, &lt;code&gt;pac solution sync&lt;/code&gt; pulls the new definition into a git repository and the change gets a changelog entry. The assistant does all of this in one motion, so the discipline actually holds. Every flow change in this project, and there have been many dozens, is in version control with a written rationale.&lt;/p&gt;

&lt;p&gt;For large edits, there is a practical workaround worth knowing: tool payloads truncate somewhere around 5 KB, so a big definition rewrite goes through the solution route instead. Edit the definition JSON locally, then &lt;code&gt;pac solution pack&lt;/code&gt;, &lt;code&gt;pac solution import&lt;/code&gt;, and publish. Same destination, different door. The assistant learned to choose the route based on the size of the change.&lt;/p&gt;

&lt;h2&gt;Verification stopped being optional&lt;/h2&gt;

&lt;p&gt;Because the assistant can resubmit a stored run and then read the new run&#39;s results, &quot;deploy and hope&quot; turned into &quot;deploy and prove.&quot; Our habit became: make the change, resubmit a known trigger event, read every action&#39;s output, compare the CRM records against Business Central truth, and only then call it done.&lt;/p&gt;

&lt;p&gt;During the test campaign, this cadence caught a deployment race where a managed export picked up a stale version and the target environment silently skipped the import as already installed. In turn, a resubmit against what turned out to be the old definition briefly looked like a test result. The lesson is now procedure: after every deployment, read the definition back from the target before trusting any run.&lt;/p&gt;

&lt;h2&gt;The rough edges, honestly&lt;/h2&gt;

&lt;p&gt;FlowAgent is genuinely useful and genuinely version one. Things we hit, and how we worked around them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solution-aware flows do not appear in the flow list&lt;/strong&gt;, which only shows personal-scope flows. The workaround is to address your flow by its ID directly. Once pinned as the current flow, everything else works.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The resubmit and diagnose tools had bugs&lt;/strong&gt; in the version we used; both threw type errors. We resubmitted runs through the underlying Power Automate REST API instead, which the assistant handles just fine, and filed the issues upstream with the plugin&#39;s built-in report-issue skill.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Importing a solution leaves flows stopped&lt;/strong&gt;, and validation errors surface at activation time, not import time. Publishing or activating after import is a required step, not a nicety.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connection authorization is per connection, not per flow.&lt;/strong&gt; A brand new flow referencing a shared connection needs one activation by the connection&#39;s owner; after that, other makers can deactivate, edit, and reactivate freely. Knowing this pattern saved us from repeatedly misdiagnosing authorization failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these were blockers. All of them are the kind of thing you want written down before you start, which is exactly why they are written down here.&lt;/p&gt;

&lt;h2&gt;What it added up to&lt;/h2&gt;

&lt;p&gt;In a bit under a week of working sessions, this setup carried us through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remediation of six pre-existing defects in an inherited flow, including moving a plaintext secret into Azure Key Vault and parameterizing every environment-specific value into environment variables&lt;/li&gt;
&lt;li&gt;A ground-up rebuild of the invoice flow onto a customer ledger trigger, eliminating an entire class of draft-noise and race-condition bugs&lt;/li&gt;
&lt;li&gt;A cash receipts flow built from a feasibility stub to feature complete in a single day, across four live-verified iterations&lt;/li&gt;
&lt;li&gt;A registry automation flow that replaced two hardcoded legacy flows with one table-driven design&lt;/li&gt;
&lt;li&gt;A full staging test campaign in which every planned scenario across three flows fired live, with every defect found along the way fixed and re-verified&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Could a person do all of that in the portal designer? Eventually. But the honest answer is that the verification depth is what a person would not do. Reading every action output of every test run, reconciling every synced record against the source system to the penny, and writing it all down as you go is precisely the tedious, high-value work that an agent with real tool access does without fatigue.&lt;/p&gt;

&lt;h2&gt;If you try it&lt;/h2&gt;

&lt;p&gt;Three practices made the difference for us, and none of them are about the tool itself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Keep a changelog and a git mirror from day one.&lt;/strong&gt; The agent moves fast; the paper trail is what lets you trust the speed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decide your edit routing up front.&lt;/strong&gt; Cloud as working copy, local as mirror, one commit per applied change. Ambiguity here is how definitions drift.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Insist on live verification.&lt;/strong&gt; The agent can prove its work against real runs. Make it do so every time, and &quot;it should work&quot; disappears from your vocabulary.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One last thing, because it matters: FlowAgent will not design your integration for you, and it should not. The design conversations, the business rulings, and the judgment calls stayed firmly human in our project. What it collapses is the distance between a decision and a verified, versioned, running flow -- a distance that used to be measured in hours of clicking and is now measured in minutes of reading the agent&#39;s evidence.&lt;/p&gt;

&lt;p&gt;If you take FlowAgent for a spin, please drop a note in the comments describing your experience, including the rough edges you find; that feedback is exactly what makes open source tooling like this get better.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;Mariano Gomez Bent&lt;br /&gt;Former Microsoft BizApps MVP&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/08/building-power-automate-flows-with.html</link><author>noreply@blogger.com (Mariano Gomez)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-1641915574014671123</guid><pubDate>Tue, 11 Aug 2026 13:35:27 +0000</pubDate><atom:updated>2026-08-11T09:35:27.912-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Agents</category><category domain="http://www.blogger.com/atom/ns#">Copilot Studio</category><category domain="http://www.blogger.com/atom/ns#">GitHub</category><category domain="http://www.blogger.com/atom/ns#">MCP</category><title>Same Agent, Two Architectures: When MCP Wins (and When It Doesn&#39;t)</title><description>&lt;div class=&quot;separator&quot; style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Same Agent, Two Architectures: connector agent versus MCP agent in Copilot Studio&quot; data-original-height=&quot;630&quot; data-original-width=&quot;1200&quot; height=&quot;630&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhkrl_litjnFdt-K1B-RXfDbnqeOFbPKUavvAqZ_s8W6v2QSwg2rdSYO-u3tGq2fkly3hmI53LiaSHhAR0bP54Ge2JZkylSDT82dIO7QbcTWSuuoy5o2aZMLBPViSW7-O38QTAfPS920iYhLkpxmKWlEgLNqXq_kT3QY-sg2HqZogzoEt-z_Mz0kAG5BP9j&quot; style=&quot;height: auto; max-width: 100%;&quot; width=&quot;1200&quot; /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhkrl_litjnFdt-K1B-RXfDbnqeOFbPKUavvAqZ_s8W6v2QSwg2rdSYO-u3tGq2fkly3hmI53LiaSHhAR0bP54Ge2JZkylSDT82dIO7QbcTWSuuoy5o2aZMLBPViSW7-O38QTAfPS920iYhLkpxmKWlEgLNqXq_kT3QY-sg2HqZogzoEt-z_Mz0kAG5BP9j&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I know, I know. It has been almost five years since my last post, and in that time the masthead changed, the name changed, and frankly, the entire technology landscape changed with them. But I did not want to relaunch this blog with a ceremonial hello-world post, so instead, this first post from &lt;b&gt;The Workbench&lt;/b&gt; starts out the way many of my posts have over the years: with a question.&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The question comes up in just about every architecture review I sit in these days, whether in my day job as CTO or in conversations with folks in the community, and it goes something like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&quot;Should we be using MCP for our Copilot Studio agents?&quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I will be the first to tell you this is the wrong question. And rather than argue the point in the abstract, I built the same agent twice to prove it. Let&#39;s see how it&#39;s done!&lt;/p&gt;

&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;Model Context Protocol -- MCP for short, introduced by the folks at Anthropic -- has gone from curiosity to checklist item in record time, much like microservices did a few years back, and just like then, everyone wants to know where it fits before anyone has agreed on when it should. So, I put together a lab around a fictional but very realistic engineering program called &lt;strong&gt;Project Orion&lt;/strong&gt;: a customer-facing web application mid-way through a major release cycle, with its operational truth split across two systems, the way it always is in real life:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub Issues&lt;/strong&gt; holds the code-level activity: 35 issues covering bugs, feature work, blockers, and performance problems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A SQL Server database&lt;/strong&gt; holds the delivery truth: five sprints of history, 70 work items, and 30 days of health metrics, including a release readiness score, critical bug counts, blocker counts, and velocity trend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, the seeded data tells a story on purpose. Sprint 3 completed 38 of 45 points. Sprint 4 dropped to 33 of 44 with 11 points of rollover. The latest health snapshot shows a release readiness score of 52, three critical bugs, three blockers, and a velocity trend of Declining. Suffice to say, this project is quietly going sideways, and the signals are scattered across two systems that do not talk to each other.&lt;/p&gt;

&lt;p&gt;With the stage set, I built the same agent twice in Microsoft Copilot Studio and asked both versions the same questions.&lt;/p&gt;

&lt;h2&gt;Version 1: the connector agent&lt;/h2&gt;

&lt;p&gt;The first agent uses nothing but the GitHub connector. Ten minutes of work, most of which is authentication, and here is the part that surprises people every time I demo it: this agent is &lt;strong&gt;good&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ask it &quot;What critical bugs are open in Project Orion?&quot; and it answers cleanly, with issue numbers, titles, and labels. Ask it &quot;What issues are labeled as blocked?&quot; and it nails that one too. For questions whose answer lives entirely inside GitHub, the connector agent is fast, correct, and required exactly zero infrastructure from me -- no server to provision, nothing to patch, and it sits comfortably inside the tenant&#39;s existing governance and data loss prevention story, which your IT department will certainly appreciate.&lt;/p&gt;

&lt;p&gt;Now, that&#39;s all cool, but then you ask it the ONE question your VP actually cares about: &lt;em&gt;&quot;What is blocking the Project Orion release?&quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And there it is -- the ceiling! The agent can see three critical bugs in GitHub, so it reports three critical bugs. It cannot see that the release readiness score sits at 52 and falling, it cannot see that velocity has declined two sprints in a row, and it cannot see that two of the blocked work items have been stalled for over a week. Keep in mind, its answer is not wrong. It is something worse than wrong: it is &lt;strong&gt;confidently incomplete&lt;/strong&gt;. A stakeholder reading that answer would walk away thinking the release has three bugs to fix, when the data says the release is structurally at risk.&lt;/p&gt;

&lt;p&gt;In the lab version of this agent I made the limitation explicit, and I recommend you do the same for any single-source agent you ship. Its instructions include the following line:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&quot;I can only see GitHub Issues data. For full project health including sprint metrics and release readiness, you would need access to the project health database.&quot;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;An agent that states its blind spots is an agent you can trust. An agent that answers everything with whatever fraction of the truth it can reach is a liability wearing a chat interface. It just doesn&#39;t work!&lt;/p&gt;

&lt;h2&gt;Version 2: the MCP agent&lt;/h2&gt;

&lt;p&gt;The second agent is the same Copilot Studio agent rebuilt on two MCP servers: the GitHub MCP Server for issue data, and a custom TypeScript MCP server I wrote that fronts the Project Orion SQL database.&lt;/p&gt;

&lt;p&gt;The custom server exposes seven tools, and I would encourage you to study the tool list closely, because this is where the real design work lives. These are not generic &quot;run a query&quot; endpoints; each one answers a question a human being would actually ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get_current_sprint&lt;/code&gt;: the active sprint with planned versus completed points&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_sprint_history&lt;/code&gt;: velocity and completion history across completed sprints&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_critical_work_items&lt;/code&gt;: open Critical and High priority items, including blocked ones&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_work_items_by_sprint&lt;/code&gt;: work items for a sprint, optionally filtered by status&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_latest_health_metrics&lt;/code&gt;: the current health snapshot, readiness score included&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_health_metrics_trend&lt;/code&gt;: readiness score over the last N days&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_stalled_work_items&lt;/code&gt;: items sitting in Active or New with no movement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two implementation details will save you a considerable amount of head scratching, so pay close attention. First, as it turns out, &lt;strong&gt;Copilot Studio speaks HTTP, not stdio&lt;/strong&gt;. Most MCP tutorials out there show the stdio transport, because that is what desktop clients use, but Copilot Studio requires the streamable HTTP transport running in stateless mode, with a fresh transport and server instance created for each incoming request. For brevity sake, I am only showing the shape of it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// Copilot Studio requires HTTP transport in stateless mode
const transport = new StreamableHTTPServerTransport({
  sessionIdGenerator: undefined, // stateless: critical for Copilot Studio
});
// a fresh server + transport pair is created per incoming request
app.post(&#39;/mcp&#39;, async (req, res) =&amp;gt; {
  const server = buildProjectOrionServer();
  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Second, validate your tool inputs. The model -- not you, not your code -- is choosing the parameter values at runtime, so every tool takes a schema, not a prayer:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;server.tool(
  &#39;get_health_metrics_trend&#39;,
  &#39;Returns the release readiness score trend over the last N days &#39; +
  &#39;to show whether project health is improving or declining.&#39;,
  { days: z.number().optional().default(14) },
  async ({ days }) =&amp;gt; {
    const rows = await getHealthMetricsTrend(days);
    return { content: [{ type: &#39;text&#39;, text: JSON.stringify(rows) }] };
  }
);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few things to note before moving on. That tool description string is not documentation for humans; it is the interface the model reasons over when deciding which tools to call and in what combination. Write your tool descriptions the way you would write requirements for a sharp new team member, because for all practical purposes, that is exactly what they are.&lt;/p&gt;

&lt;h2&gt;The moment it earns its keep&lt;/h2&gt;

&lt;p&gt;Now ask the rebuilt agent the same question: &lt;em&gt;&quot;What is blocking the Project Orion release?&quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This time the agent calls &lt;code&gt;get_critical_work_items&lt;/code&gt; and &lt;code&gt;get_latest_health_metrics&lt;/code&gt; on the SQL side, pulls the open critical issues from the GitHub side, and then does the thing no single-source agent can do: it correlates. The three critical GitHub bugs map to blocked work items in the sprint; the blockers explain the 11 points of rollover in Sprint 4; the rollover explains the declining velocity trend; and all of it together explains a readiness score of 52. And voila! The answer reads like something a good release manager would write, complete with a one-line risk summary at the end, because the agent finally has the same field of vision the release manager has.&lt;/p&gt;

&lt;p&gt;Ask it &quot;Are there any patterns between our open GitHub issues and our sprint health?&quot; and it produces an answer that did not have a data path to exist in Version 1. That is the difference, and it is worth being precise about it: not better answers to the old questions, but answers to questions that were previously UNANSWERABLE.&lt;/p&gt;

&lt;h2&gt;What MCP costs you&lt;/h2&gt;

&lt;p&gt;Here is the part the hype conveniently skips, and the part I lean on hardest whenever I present this material: everything above has a bill attached.&lt;/p&gt;

&lt;p&gt;With the connector agent, Microsoft runs the integration. With the MCP agent, I run the integration. In the lab, the server is a TypeScript process on my laptop reached through an Azure Dev Tunnel, which is perfectly fine for a demo and perfectly irresponsible for production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; the moment this architecture goes to production, you own hosting, authentication, TLS, availability, logging, patching the SDK, and the security review for a brand-new surface area that reaches directly into a database. The connector came pre-governed; your MCP server is governed by whatever you remembered to build.&lt;/p&gt;

&lt;p&gt;So the honest comparison is not &quot;MCP versus connector.&quot; It is &quot;cross-source reasoning versus operational simplicity.&quot; Sometimes that trade is spectacular, and sometimes it amounts to buying yourself a server bill to answer questions a connector already answered. It is your job as an architect to know which of the two situations you are standing in.&lt;/p&gt;

&lt;h2&gt;The decision signal&lt;/h2&gt;

&lt;p&gt;After building both versions side by side, the rule I trust fits in one sentence:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;When your agent needs to reason across sources it did not know about at design time, that is your MCP signal.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;In practice, I walk through the following four questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Does the answer live in one system?&lt;/strong&gt; Use the connector. You are done, and you inherited Microsoft&#39;s operations team for free.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Does the answer require correlating two or more systems in a single reasoning pass?&lt;/strong&gt; That is your MCP signal. No amount of prompt engineering will give a single-source agent data it cannot reach.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Will the source list grow?&lt;/strong&gt; MCP servers compose. Adding a third source to the Orion agent is another server registration, not a rebuild.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Can you operate a service?&lt;/strong&gt; If the answer is no, that is not a character flaw, but keep in mind the connector ceiling is your ceiling until that answer changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Build it yourself&lt;/h2&gt;

&lt;p&gt;Everything in this post is reproducible from the lab I published for my Community Summit NA 2026 session in Nashville, &lt;em&gt;&quot;Same Agent, Two Architectures: When MCP Wins (And When It Doesn&#39;t)&quot;&lt;/em&gt;. The repository contains the SQL schema and seed data, a script that creates all 35 GitHub issues, scaffold prompts for the MCP server and a Next.js health dashboard, and the Copilot Studio prompts for both agents -- including the intentionally limited one:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/dgpblogster/project-orion-lab&quot;&gt;github.com/dgpblogster/project-orion-lab&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VS Code&lt;/a&gt;, &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node 18+&lt;/a&gt;, &lt;a href=&quot;https://www.microsoft.com/en-us/sql-server/sql-server-downloads&quot;&gt;SQL Server Express&lt;/a&gt;, the &lt;a href=&quot;https://cli.github.com/&quot;&gt;GitHub CLI&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started&quot;&gt;Azure Dev Tunnels&lt;/a&gt;, and a &lt;a href=&quot;https://copilotstudio.microsoft.com&quot;&gt;Copilot Studio license&lt;/a&gt; -- a trial works just fine. Budget an afternoon, and make sure you build toward the moment where you ask both agents the release-blocker question back to back, because watching one agent hit the ceiling and the other reason straight through it will teach you more about agent architecture than any slide deck, including mine. The effort is well worth it!&lt;/p&gt;

&lt;p&gt;If there is interest, my next installment will walk through hardening this MCP server for real production use -- authentication, hosting, and telemetry -- so please drop a note in the comments if you would like to see that. It is good to be back at the bench.&lt;/p&gt;

&lt;p&gt;Until next post!&lt;/p&gt;

&lt;p&gt;MG.-&lt;br /&gt;Mariano Gomez Bent&lt;br /&gt;Former Microsoft BizApps MVP&amp;nbsp;&amp;nbsp;&lt;/p&gt;
</description><link>http://www.theworkbench.blog/2026/08/same-agent-two-architectures-when-mcp.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEhkrl_litjnFdt-K1B-RXfDbnqeOFbPKUavvAqZ_s8W6v2QSwg2rdSYO-u3tGq2fkly3hmI53LiaSHhAR0bP54Ge2JZkylSDT82dIO7QbcTWSuuoy5o2aZMLBPViSW7-O38QTAfPS920iYhLkpxmKWlEgLNqXq_kT3QY-sg2HqZogzoEt-z_Mz0kAG5BP9j=s72-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-8900068900384765487</guid><pubDate>Thu, 12 Aug 2021 19:09:00 +0000</pubDate><atom:updated>2026-08-19T10:59:34.591-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ALM</category><category domain="http://www.blogger.com/atom/ns#">Azure Application Insights</category><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><category domain="http://www.blogger.com/atom/ns#">Telemetry</category><title>Power Apps - Application Monitoring with Azure Application Insights</title><description>In this video, learn to enable Power Apps Application Monitoring with Azure Application Insights.&amp;nbsp;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/nISv1JHNRQY&quot; title=&quot;YouTube video player&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The following topics are covered in this video:&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=nISv1JHNRQY&amp;amp;t=0s&quot;&gt;0:00&lt;/a&gt;) - Intro&amp;nbsp;&lt;/div&gt;&lt;div&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=nISv1JHNRQY&amp;amp;t=36s&quot;&gt;0:36&lt;/a&gt;) - What is Azure Application Insights&amp;nbsp;&lt;/div&gt;&lt;div&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=nISv1JHNRQY&amp;amp;t=92s&quot;&gt;1:32&lt;/a&gt;) - The timesheet app&amp;nbsp;&lt;/div&gt;&lt;div&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=nISv1JHNRQY&amp;amp;t=132s&quot;&gt;2:12&lt;/a&gt;) - Creating an Application Insight for the timesheet application&amp;nbsp;&lt;/div&gt;&lt;div&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=nISv1JHNRQY&amp;amp;t=235s&quot;&gt;3:55&lt;/a&gt;) - Identify and copy the application instrumentation key&amp;nbsp;&lt;/div&gt;&lt;div&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=nISv1JHNRQY&amp;amp;t=249s&quot;&gt;4:09&lt;/a&gt;) - Enabling the timesheet application with the instrumentation key&amp;nbsp;&lt;/div&gt;&lt;div&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=nISv1JHNRQY&amp;amp;t=332s&quot;&gt;5:32&lt;/a&gt;) - Working with Application Insights&amp;nbsp;&lt;/div&gt;&lt;div&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=nISv1JHNRQY&amp;amp;t=486s&quot;&gt;8:06&lt;/a&gt;) - Outro&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For additional information on Azure Application Insights, please follow these resources:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Microsoft Docs - What is Azure Application Insights? &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview&quot;&gt;here&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Adam Marczak - Azure for Everyone: Azure Application Insights Tutorial, &lt;a href=&quot;https://youtu.be/A0jAeGf2zUQ&quot;&gt;here&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;
&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;div&gt;&lt;b&gt;LIKE AND SUBSCRIBE!!!&lt;br /&gt;&lt;/b&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP
&lt;br /&gt;
&lt;/div&gt;</description><link>http://www.theworkbench.blog/2021/08/power-apps-application-monitoring-with.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/nISv1JHNRQY/default.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-1316020312829870925</guid><pubDate>Tue, 03 Aug 2021 19:46:00 +0000</pubDate><atom:updated>2026-08-19T10:59:35.642-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ALM</category><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio</category><title>Power Platform ALM - Visual Studio Code Extensions</title><description>&lt;p&gt;Learn about Power Platform extension for Visual Studio Code and how this toolset is improving both the code first developer experience and strengthening the ALM story.&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/vfwYY6Aexeg&quot; title=&quot;YouTube video player&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The following topics are covered:&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=vfwYY6Aexeg&amp;amp;t=0s&quot;&gt;0:00&lt;/a&gt;) - Intro&amp;nbsp;&lt;/li&gt;&lt;li&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=vfwYY6Aexeg&amp;amp;t=76s&quot;&gt;1:16&lt;/a&gt;) - Installing the Power Platform extensions for Visual Studio Code&amp;nbsp;&lt;/li&gt;&lt;li&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=vfwYY6Aexeg&amp;amp;t=133s&quot;&gt;2:13&lt;/a&gt;) - Working with the Power Platform CLI inside of Visual Studio Code&amp;nbsp;&lt;/li&gt;&lt;li&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=vfwYY6Aexeg&amp;amp;t=222s&quot;&gt;3:42&lt;/a&gt;) - Authenticating to your environment from Power Platform CLI&amp;nbsp;&lt;/li&gt;&lt;li&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=vfwYY6Aexeg&amp;amp;t=438s&quot;&gt;7:18&lt;/a&gt;) - Saving your canvas app to your local machine&amp;nbsp;&lt;/li&gt;&lt;li&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=vfwYY6Aexeg&amp;amp;t=535s&quot;&gt;8:55&lt;/a&gt;) - Unpacking your canvas app&amp;nbsp;&lt;/li&gt;&lt;li&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=vfwYY6Aexeg&amp;amp;t=619s&quot;&gt;10:19&lt;/a&gt;) - Using Visual Studio Code to make changes to your application&amp;nbsp;&lt;/li&gt;&lt;li&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=vfwYY6Aexeg&amp;amp;t=710s&quot;&gt;11:50&lt;/a&gt;) - Packing and uploading your application changes&amp;nbsp;&lt;/li&gt;&lt;li&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=vfwYY6Aexeg&amp;amp;t=835s&quot;&gt;13:55&lt;/a&gt;) - Outro&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;
To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;
&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;div&gt;&lt;b&gt;LIKE AND SUBSCRIBE!!!&lt;br /&gt;&lt;/b&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP
&lt;br /&gt;
&lt;/div&gt;</description><link>http://www.theworkbench.blog/2021/08/power-platform-alm-visual-studio-code.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/vfwYY6Aexeg/default.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-2012731729105666213</guid><pubDate>Mon, 02 Aug 2021 21:31:00 +0000</pubDate><atom:updated>2026-08-19T10:59:36.588-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><title>Power Automate | Passing Collections from Power Automate to Power Apps (Revisited)</title><description>I revisit an old video I did couple years ago showing how to pass collections from Power Automate to Power Apps.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/qUmi3JwjLfI&quot; title=&quot;YouTube video player&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;This time around, I show how to leverage arrays to accomplish the same. This time around you will learn about:&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/using-logic-flows&quot; target=&quot;_blank&quot;&gt;Power Apps trigger in Power Automate&lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/connectors/sql/&quot; target=&quot;_blank&quot;&gt;Get Rows SQL action&lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/power-automate/create-variable-store-values&quot; target=&quot;_blank&quot;&gt;Variables action&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/power-automate/data-operations&quot; target=&quot;_blank&quot;&gt;Select action and Arrays&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Response action&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/create-update-collection&quot; target=&quot;_blank&quot;&gt;Power Apps Collections&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;
&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;div&gt;&lt;b&gt;LIKE AND SUBSCRIBE!!!&lt;br /&gt;&lt;/b&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP</description><link>http://www.theworkbench.blog/2021/08/power-automate-passing-collections-from.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/qUmi3JwjLfI/default.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-2212227777417175774</guid><pubDate>Tue, 10 Nov 2020 19:00:00 +0000</pubDate><atom:updated>2026-08-19T10:59:37.573-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">AI Builder</category><category domain="http://www.blogger.com/atom/ns#">FlowFam</category><category domain="http://www.blogger.com/atom/ns#">Form Processing</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><category domain="http://www.blogger.com/atom/ns#">PowerAddicts</category><title>AI Builder Form Processing: Multi-layout Form Processing</title><description>AI Builder Form Processing Multi-layout Form Processing has been one of the most requested features and is now available in preview for you to test. This feature allows you to process forms with a variety of different layouts (but similar in content) with a single model, which brings this feature one step closer to a scalable enterprise solution.&lt;br /&gt;&lt;br /&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/WL_eEOUK0fw&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;In this video I cover the following:&lt;br /&gt;&lt;br /&gt;- Creating a model&lt;br /&gt;- Form collections&lt;br /&gt;- Training the form processing model&lt;br /&gt;- Publishing the form processing model&lt;br /&gt;- Testing the model&lt;br /&gt;&lt;br /&gt;For additional information, please refer to:&lt;br /&gt;&lt;br /&gt;Create a form processing model - click &lt;a href=&quot;https://docs.microsoft.com/en-us/ai-builder/create-form-processing-model&quot;&gt;here&lt;/a&gt;&lt;br /&gt;AI Builder form processing announcement - click &lt;a href=&quot;https://flow.microsoft.com/en-us/blog/ai-builder-form-processing-models-can-now-train-using-documents-that-have-different-layouts/&quot;&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;
&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;div&gt;&lt;b&gt;LIKE AND SUBSCRIBE!!!&lt;br /&gt;&lt;/b&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP
&lt;br /&gt;
&lt;/div&gt;</description><link>http://www.theworkbench.blog/2020/11/ai-builder-form-processing-multi-layout.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/WL_eEOUK0fw/default.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-6690667304469326507</guid><pubDate>Tue, 20 Oct 2020 20:15:00 +0000</pubDate><atom:updated>2026-08-19T10:59:38.992-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ALM</category><category domain="http://www.blogger.com/atom/ns#">Flow</category><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><category domain="http://www.blogger.com/atom/ns#">PowerAddicts</category><title>Power Platform: Application Lifecycle Management (Part 3/3) - Build and Release Pipelines</title><description>Welcome to the final episode of Power Platform Application Lifecycle Management. In parts 1 and 2 you saw how to prepare your environments, set up an Azure DevOps project, and define Service Connections to your Power Platform environments.&amp;nbsp;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In this, the final installment of this 3-part series, you will learn how to create the Build and Release pipelines using the Power Platform Build Tools to take your Power Platform solution from an environment, through source code control, through staging and production deployments.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/NRLQeT0XP2M&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;
Topics covered:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;
- Power Platform source code control with Azure Repos&lt;br /&gt;
- Build and Release pipelines&lt;br /&gt;
- Sharing your solution&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
References:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;
Power Platform Build Tools webinar - &lt;a href=&quot;https://youtu.be/Qwue8fwetJA&quot;&gt;https://youtu.be/Qwue8fwetJA&lt;/a&gt;&amp;nbsp;&lt;div&gt;Solutions Overview and Limitations - click &lt;a href=&quot;https://www.youtube.com/redirect?event=video_description&amp;amp;v=q2j3QO0iBSs&amp;amp;redir_token=QUFFLUhqbnVxcjViRmR5LWlsRDY4bGY2SGw1dzIwdmMtUXxBQ3Jtc0trRU5LNlA0U0VLRVJoSDRJckhFTnhKNFlZbElyVzJscEtWVy0tRndHTWF3V1pMdTR4cDNGR09SWnA0YnhHa3dEbFdjNlU5dVhBTURwaE9UT3hRdTl0YzM5ZmpQbmpuaFNNWDRucEh4ak5wY1c2MWtyNA%3D%3D&amp;amp;q=https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fpowerapps%2Fmaker%2Fcommon-data-service%2Fsolutions-overview&quot;&gt;here&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
LIKE AND SUBSCRIBE!!!&lt;br /&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP
&lt;br /&gt;
&lt;/div&gt;&lt;/div&gt;</description><link>http://www.theworkbench.blog/2020/10/power-platform-application-lifecycle.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/NRLQeT0XP2M/default.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-5600519802411814652</guid><pubDate>Tue, 22 Sep 2020 21:00:00 +0000</pubDate><atom:updated>2026-08-19T10:59:39.958-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">Power BI</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><category domain="http://www.blogger.com/atom/ns#">Power Virtual Agents</category><category domain="http://www.blogger.com/atom/ns#">PowerAddicts</category><category domain="http://www.blogger.com/atom/ns#">Source Code Control</category><title>Power Platform: Application Lifecycle Management (Part 2/3) - Solutions and DevOps</title><description>In the previous installment, you saw how to work through a set of prerequisites to get you going in your Power Platform Application Lifecycle Management journey. In this video, I will work through building an app and adding it to a solution and show you some additional Azure DevOps configuration options to link your repository to your Power Platform development environment.&lt;br /&gt;&lt;br /&gt;
&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/q2j3QO0iBSs&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;br /&gt;
Topics Covered:&lt;br /&gt;&lt;br /&gt;
1. Building app based on template&lt;br /&gt;
2. Adding your app to a solution&lt;br /&gt;
3. Linking your DevOps project to your Power Platform environment&lt;br /&gt;&lt;br /&gt;
References:&lt;br /&gt;
Power Platform Build Tools webinar - &lt;a href=&quot;https://youtu.be/Qwue8fwetJA&quot;&gt;https://youtu.be/Qwue8fwetJA&lt;/a&gt;&amp;nbsp;&lt;div&gt;Solutions Overview and Limitations - click &lt;a href=&quot;https://www.youtube.com/redirect?event=video_description&amp;amp;v=q2j3QO0iBSs&amp;amp;redir_token=QUFFLUhqbnVxcjViRmR5LWlsRDY4bGY2SGw1dzIwdmMtUXxBQ3Jtc0trRU5LNlA0U0VLRVJoSDRJckhFTnhKNFlZbElyVzJscEtWVy0tRndHTWF3V1pMdTR4cDNGR09SWnA0YnhHa3dEbFdjNlU5dVhBTURwaE9UT3hRdTl0YzM5ZmpQbmpuaFNNWDRucEh4ak5wY1c2MWtyNA%3D%3D&amp;amp;q=https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fpowerapps%2Fmaker%2Fcommon-data-service%2Fsolutions-overview&quot;&gt;here&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
LIKE AND SUBSCRIBE!!!&lt;br /&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP
&lt;br /&gt;
&lt;/div&gt;</description><link>http://www.theworkbench.blog/2020/09/power-platform-application-lifecycle_22.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/q2j3QO0iBSs/default.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-7996061075346226070</guid><pubDate>Mon, 14 Sep 2020 19:42:00 +0000</pubDate><atom:updated>2026-08-19T10:59:40.860-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">Power BI</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><category domain="http://www.blogger.com/atom/ns#">PowerAddicts</category><category domain="http://www.blogger.com/atom/ns#">Source Code Control</category><title>Power Platform: Application Lifecycle Management (Part 1/3) - Prerequisites</title><description>This series is in response to multiple requests by my viewers to address the topic of Power Apps Application Lifecycle Management (ALM). This series is intended to breakdown the entire process in as much detail as possible, without lengthy explanations on how to get it done or, as often happens, little to no explanations on how you arrived at a particular step or result.&lt;br /&gt; 
&lt;br /&gt;My first installment will focus on Prerequisites, this is, what you need to have in place to get started. I will walk you through provisioning your Power Platform Dev, QA, and Production environments, along with installing the Power Platform Build Tools and setting up your Azure DevOps project. I also explain the concept of solutions in Power Platform and why they are important to your ALM strategy.&lt;br /&gt;&lt;br /&gt;
&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/6uQPDa4AxVA&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;
&lt;br /&gt;
&lt;br /&gt;
Topics covered:
&lt;br /&gt;
&lt;br /&gt;
1. Creating Power Platform Environments&lt;br /&gt;
2. Azure DevOps and Installing Power Platform Build Tools&lt;br /&gt;
3. Creating an Azure DevOps Project&lt;br /&gt;
4. Solutions&lt;br /&gt;
&lt;br /&gt;References:&lt;br /&gt;
Power Platform Build Tools webinar - &lt;a href=&quot;https://youtu.be/Qwue8fwetJA&quot;&gt;https://youtu.be/Qwue8fwetJA&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
Credits:&lt;br /&gt;
Summer - Bensound - Royalty free music at &lt;a href=&quot;https://www.bensound.com&quot;&gt;https://www.bensound.com&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
LIKE AND SUBSCRIBE!!!&lt;br /&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP</description><link>http://www.theworkbench.blog/2020/09/power-platform-application-lifecycle.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/6uQPDa4AxVA/default.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-3958098468401789063</guid><pubDate>Thu, 03 Sep 2020 15:29:00 +0000</pubDate><atom:updated>2026-08-19T10:59:42.005-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Azure</category><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">SharePoint</category><category domain="http://www.blogger.com/atom/ns#">SQL Server</category><title>Power Automate: Transfer records from SharePoint list to Azure SQL database</title><description>Majority of times, when we are working with various data sources, we want information to go from one source to another, conditioned to the occurrence of an event. Today, I will show you how to transfer records from a SharePoint list to Azure SQL database tables in response to a timesheet approval event. In the process, you will learn how I leveraged the existing Power Apps Expense template app and converted it into a Timesheet app for the purpose  of recording time for various activities&amp;nbsp;&lt;div&gt;&lt;br /&gt;
&lt;iframe allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/Xw4h7KECgNI&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Other topics covered:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;Working with SharePoint lists and Azure SQL databases&lt;/li&gt;&lt;li&gt;&quot;When an item is created or modified&quot; SharePoint connector trigger&lt;/li&gt;&lt;li&gt;&quot;Delete Item&quot; SharePoint connector action&lt;/li&gt;&lt;li&gt;&quot;Get Items&quot; SharePoint connector action&lt;/li&gt;&lt;li&gt;Conditional actions&lt;/li&gt;&lt;li&gt;Get Rows and Insert Row SQL connector actions&lt;/li&gt;&lt;li&gt;Apply to each action&lt;/li&gt;&lt;li&gt;substring(), formatDateTime()&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Please leave your comments below and let me know what you think. Also, please feel free to suggest topics you would like me to cover.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;References:
Reza Dorrani - Expense Tracking Sample Power App with Receipt Scanning AI - &lt;a href=&quot;https://youtu.be/1X8ihV_EGbE &quot; target=&quot;_blank&quot;&gt;Click here&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Credits:
Creative Minds - Bensound - Royalty free music at &lt;a href=&quot;https://www.bensound.com&quot;&gt;https://www.bensound.com
&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
LIKE AND SUBSCRIBE!!!&lt;br /&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP</description><link>http://www.theworkbench.blog/2020/09/power-automate-transfer-records-from.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/Xw4h7KECgNI/default.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-35492654567424500</guid><pubDate>Mon, 10 Aug 2020 18:57:00 +0000</pubDate><atom:updated>2026-08-19T10:59:42.991-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Mixed Reality</category><category domain="http://www.blogger.com/atom/ns#">Power Apps</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><category domain="http://www.blogger.com/atom/ns#">PowerAddicts</category><category domain="http://www.blogger.com/atom/ns#">PowerApps</category><category domain="http://www.blogger.com/atom/ns#">PowerPlatform</category><category domain="http://www.blogger.com/atom/ns#">Workflow</category><title>Power Apps: Save Mixed Reality pictures to SharePoint</title><description>In this video you will learn how to save pictures taken in Power Apps Mixed Reality or Augmented Reality viewer to a SharePoint document library.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; 
&lt;iframe allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/QDlN6CEHydk&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some topics covered include: Power Apps ForAll(), With(), Mid(), and Len() functions, the Self operator. Learn to use the Power Automate SharePoint connector and the Create File action, and the base64toBinary() function in an expression. Finally, you will see how you can call a flow from Power Apps to make it all work like a single application.&lt;/div&gt;
&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
LIKE AND SUBSCRIBE!!!&lt;br /&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP</description><link>http://www.theworkbench.blog/2020/08/power-apps-save-mixed-reality-pictures.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/QDlN6CEHydk/default.jpg" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>Roswell, GA, USA</georss:featurename><georss:point>34.0232431 -84.3615555</georss:point><georss:box>5.7130092638211565 -119.5178055 62.333476936178847 -49.205305499999994</georss:box></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5285970135510371565.post-911519613313195805</guid><pubDate>Wed, 29 Jul 2020 01:33:00 +0000</pubDate><atom:updated>2026-08-19T10:59:44.013-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Flow</category><category domain="http://www.blogger.com/atom/ns#">Power Automate</category><category domain="http://www.blogger.com/atom/ns#">Power Platform</category><title> Power Automate: Working with Microsoft Graph API and Teams Connector</title><description>In this video you will learn the basics of the Microsoft Graph API, how to use Graph Explorer, register an application to use Microsoft Graph in Azure Active Directory, and build a simple flow that will use the Teams Connector  and Graph API to list a set of tabs in a Teams channel.&amp;nbsp;&lt;div&gt;&amp;nbsp;
&lt;br /&gt;Other topics covered are: compose and HTTP actions, using the compose action as an alternative to variables, using the filter array action to filter the results in a JSON payload.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;iframe allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/E4Ve5frEO6s&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt; 
&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  
References: &lt;br /&gt;
Microsoft Graph: &lt;a href=&quot;https://graph.microsoft.com&quot;&gt;https://graph.microsoft.com&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Credits:&amp;nbsp;&lt;/div&gt;&lt;div&gt;Creative Minds - Bensound - Royalty free music at &lt;a href=&quot;https://www.bensound.com&quot;&gt;https://www.bensound.com
&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To check out my YouTube channel visit:
&lt;a href=&quot;https://www.youtube.com/@workbench-blog&quot;&gt;https://www.youtube.com/@workbench-blog&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
LIKE AND SUBSCRIBE!!!&lt;br /&gt;
&lt;br /&gt;
Until next post!&lt;br /&gt;
&lt;br /&gt;
MG.-&lt;br /&gt;
Mariano Gomez, MVP</description><link>http://www.theworkbench.blog/2020/07/power-automate-working-with-microsoft.html</link><author>noreply@blogger.com (Mariano Gomez)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/E4Ve5frEO6s/default.jpg" height="72" width="72"/><thr:total>0</thr:total></item></channel></rss>