<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='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'><id>tag:blogger.com,1999:blog-8675696861245191896</id><updated>2026-04-24T04:46:18.988-04:00</updated><category term="CRM 2011"/><category term="PowerApps"/><category term="PowerPlatform"/><category term="Dynamics"/><category term="SQL"/><category term="dataverse"/><category term="Error"/><category term="ADFS 2.0"/><category term="CRM"/><category term="CRM 4.0"/><category term="IIS"/><category term="SharePoint 2007"/><category term="PowerAutomate"/><category term="Security"/><category term="Javascript"/><category term="SharePoint 2007 Administration"/><category term="SharePoint 2010"/><category term="Visual Studio"/><category term="pcf"/><category term="Authentication"/><category term="Tools"/><category term="Windows Server 2008"/><category term="Windows Server 2008R2"/><category term="webapi"/><category term="Development"/><category term="Flow"/><category term="PowerShell"/><category term="Ribbon"/><category term="government"/><category term="SharePoint 2007 Development"/><category term="api"/><category term="canvas"/><category term="power platform"/><category term="Connectors"/><category term="CustomConnector"/><category term="Kerberos"/><category term="Reports"/><category term="SSRS"/><category term="automation"/><category term="azure"/><category term="data"/><category term="power automate"/><category term="AWS"/><category term="Active Directory"/><category term="CDS"/><category term="Certificates"/><category term="SharePoint"/><category term="TFS"/><category term="Testing"/><category term="Theatre"/><category term="Web Part"/><category term="d365"/><category term="dod"/><category term="powerbi"/><category term="powerpages"/><category term="raspberry"/><category term="raspberrypi"/><category term=".net"/><category term="ADFS 3.0"/><category term="Actions"/><category term="C#"/><category term="CAC"/><category term="Calendar"/><category term="Firewall"/><category term="Forefront"/><category term="Git"/><category term="Horde"/><category term="Internet Explorer"/><category term="LowCode"/><category term="PDF"/><category term="Plugin Development"/><category term="Remote Desktop"/><category term="S3"/><category term="SSIS"/><category term="Update Rollup"/><category term="User Control"/><category term="Web Application"/><category term="Web.Config"/><category term="Windows Server 2012"/><category term="ai"/><category term="azuredevops"/><category term="cPanel"/><category term="connector"/><category term="customconnectors"/><category term="dataflow"/><category term="dataflows"/><category term="devops"/><category term="etl"/><category term="gcc"/><category term="gcchigh"/><category term="github"/><category term="iPhone"/><category term="import"/><category term="integration"/><category term="microsoft"/><category term="modelapp"/><category term="modelapps"/><category term="performance"/><category term="portal"/><category term="portals"/><category term="powerquery"/><category term="react"/><category term="rpa"/><category term="unique"/><category term="url"/><category term=".netcore"/><category term="365"/><category term="3d"/><category term="3dprint"/><category term="ADF"/><category term="ADFS"/><category term="ADFS 2.1"/><category term="AMI"/><category term="ASP.NET"/><category term="Annotation"/><category term="AutomationTips"/><category term="Azure Data Factory"/><category term="AzureLogicApps"/><category term="AzureManagedIdentity"/><category term="AzureSecurity"/><category term="Backup"/><category term="Batch Files"/><category term="BestPractice"/><category term="Bookmarklet"/><category term="Buffering"/><category term="CC"/><category term="Cache"/><category term="CodePlex"/><category term="Component"/><category term="Custom Connectors"/><category term="Dashboard"/><category term="Data Flows"/><category term="DataModeling"/><category term="DataShaping"/><category term="DataversePlugins"/><category term="Debugging"/><category term="Demonstration"/><category term="DevTools"/><category term="DriftlessMerges"/><category term="Duplicates"/><category term="EC2"/><category term="Events"/><category term="Excel Services"/><category term="ExpressionInspector"/><category term="FetchXML"/><category term="FlowExpressions"/><category term="Grid"/><category term="Group Policy"/><category term="GroupBy"/><category term="Hyper-V"/><category term="ISV"/><category term="Integration Services"/><category term="JavaScriptSnippet"/><category term="Join"/><category term="LS"/><category term="Linked Services"/><category term="List"/><category term="LogicAppsConsumption"/><category term="M"/><category term="MI"/><category term="Makers"/><category term="Managed Identity"/><category term="Merge"/><category term="Migration"/><category term="Mode Apps"/><category term="Note"/><category term="OAuth2"/><category term="OData"/><category term="PA"/><category term="PKI"/><category term="PP"/><category term="Permissions"/><category term="PickOne"/><category term="Power Apps"/><category term="PowerAutomateV3"/><category term="QueryFolding"/><category term="RDG"/><category term="RDP"/><category term="RDS"/><category term="REST API"/><category term="RegEx"/><category term="Remote Desktop Gateway"/><category term="ResourceManagement"/><category term="Resources"/><category term="RetrievePrincipalAccess"/><category term="S2S Authentication"/><category term="SDK"/><category term="Scheduling"/><category term="Table.Buffer"/><category term="Templates"/><category term="TokenAuthentication"/><category term="Triggers"/><category term="UCI"/><category term="VHD"/><category term="VSTS"/><category term="View"/><category term="WAP"/><category term="Web Resources"/><category term="Windows"/><category term="Windows 10"/><category term="access"/><category term="accessdenied"/><category term="activedirectory"/><category term="adftips"/><category term="admin"/><category term="admin center"/><category term="administrator"/><category term="airgap"/><category term="android"/><category term="appregistration"/><category term="apps"/><category term="authenticated"/><category term="autogenate"/><category term="autogpt"/><category term="automate"/><category term="automateddata"/><category term="autonumber"/><category term="azuredatafactory"/><category term="azureintegration"/><category term="azureopenapi"/><category term="azurestorage"/><category term="b2c"/><category term="banner"/><category term="basicauthentication"/><category term="bound"/><category term="button"/><category term="catch"/><category term="chatgpt"/><category term="checker"/><category term="checkout"/><category term="classification"/><category term="cli"/><category term="client"/><category term="clientcredentials"/><category term="clierrors"/><category term="clone"/><category term="cloudflow"/><category term="code"/><category term="collectionformat"/><category term="compliance"/><category term="components"/><category term="connection"/><category term="connections"/><category term="consent"/><category term="context"/><category term="copilot"/><category term="crosscloud"/><category term="customaction"/><category term="customapi"/><category term="customization"/><category term="customprocess"/><category term="customprocessaction"/><category term="data security"/><category term="dataengineering"/><category term="dates"/><category term="deploy"/><category term="design"/><category term="desktop"/><category term="desktopflow"/><category term="devopssecurity"/><category term="dlp policies"/><category term="dnsspoofing"/><category term="docx"/><category term="dotnet"/><category term="dotnetcore"/><category term="download"/><category term="dynamics365"/><category term="email"/><category term="errror"/><category term="execute"/><category term="exmaple"/><category term="fbi"/><category term="federatedcredentials"/><category term="filetransfer"/><category term="finally"/><category term="fiscalyear"/><category term="flows"/><category term="formcontext"/><category term="fun"/><category term="function"/><category term="gallery"/><category term="gateway"/><category term="gcc high"/><category term="gcch"/><category term="govcloud"/><category term="govee"/><category term="governance"/><category term="government community cloud"/><category term="gpio"/><category term="graph"/><category term="graphapi"/><category term="gsa"/><category term="hobby"/><category term="indepdentconnector"/><category term="install"/><category term="iot"/><category term="ip"/><category term="iprestrictions"/><category term="json"/><category term="license"/><category term="licensing"/><category term="lighting"/><category term="llm"/><category term="login"/><category term="lookup"/><category term="lookups"/><category term="low code"/><category term="lowcodedev"/><category term="managedidentity"/><category term="maps"/><category term="mcp"/><category term="metadata"/><category term="microsoft 365"/><category term="microsoftcloud"/><category term="miliary"/><category term="mobile"/><category term="model"/><category term="model-context-protocol"/><category term="modules"/><category term="msdyn365"/><category term="netcore"/><category term="network"/><category term="npm"/><category term="nuget"/><category term="openai"/><category term="openapi"/><category term="opengovernment"/><category term="paccli"/><category term="paconn cli"/><category term="pagination"/><category term="parameter"/><category term="pat"/><category term="path"/><category term="pcf;canvas;dynamics;d365;powerapps"/><category term="perdiem"/><category term="pinout"/><category term="pins"/><category term="pipeline"/><category term="plugins"/><category term="power pages"/><category term="power-platform"/><category term="powerappscli"/><category term="powerappsportals"/><category term="powerautomatedesktop"/><category term="preferred-solution"/><category term="printing"/><category term="prompt"/><category term="ps"/><category term="publicsector"/><category term="query"/><category term="quick-tip"/><category term="registry"/><category term="remote"/><category term="remotedesktop"/><category term="remotedesktopgateway"/><category term="remotedevelopment"/><category term="remotessh"/><category term="reporting"/><category term="script"/><category term="scroll"/><category term="securepipelines"/><category term="sitemap"/><category term="solution-publisher"/><category term="sparse"/><category term="ssh"/><category term="storage account"/><category term="stringtype"/><category term="swagger"/><category term="systemnullreferenceexception"/><category term="table-prefix"/><category term="tables"/><category term="teammember"/><category term="teams"/><category term="telemetry"/><category term="template"/><category term="terminal"/><category term="tooling"/><category term="top10"/><category term="triggertime"/><category term="troubleshooting"/><category term="try"/><category term="trycatch"/><category term="trycatchfinally"/><category term="types"/><category term="typescript"/><category term="users"/><category term="usgov"/><category term="usgovernment"/><category term="v2"/><category term="v3"/><category term="vscode"/><category term="webreole"/><category term="webresource"/><category term="webtemplates"/><category term="word"/><category term="workflow"/><category term="workloadidentityfederation"/><category term="xrm"/><title type='text'>PowerApps RAW!</title><subtitle type='html'>Providing tips, tricks, and free stuff to the PowerApps community.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.richardawilson.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>230</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-4753704702389616284</id><published>2026-03-26T10:01:53.289-04:00</published><updated>2026-03-26T10:01:56.274-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ai"/><category scheme="http://www.blogger.com/atom/ns#" term="copilot"/><category scheme="http://www.blogger.com/atom/ns#" term="customization"/><category scheme="http://www.blogger.com/atom/ns#" term="dataverse"/><category scheme="http://www.blogger.com/atom/ns#" term="mcp"/><category scheme="http://www.blogger.com/atom/ns#" term="model-context-protocol"/><category scheme="http://www.blogger.com/atom/ns#" term="power-platform"/><category scheme="http://www.blogger.com/atom/ns#" term="preferred-solution"/><category scheme="http://www.blogger.com/atom/ns#" term="quick-tip"/><category scheme="http://www.blogger.com/atom/ns#" term="solution-publisher"/><category scheme="http://www.blogger.com/atom/ns#" term="table-prefix"/><title type='text'>Set Your Preferred Solution for the Dataverse MCP</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/blob/master/dataverse-mcp-preferred-solution/hero-image.png?raw=true&quot; alt=&quot;Set Your Preferred Solution for the Dataverse MCP&quot;&gt;&lt;/p&gt;
&lt;p&gt;I was working with the &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/data-platform/data-platform-mcp&quot;&gt;Dataverse MCP server&lt;/a&gt; yesterday and noticed that when I created new tables through it, they were all getting the default &lt;code&gt;cr***&lt;/code&gt; prefix from the Common Data Services Default Publisher. The MCP doesn’t give you an option to select a publisher or a prefix when creating table customizations — it just uses whatever the environment default is.&lt;/p&gt;
&lt;p&gt;If you’re like me and want your tables to have a consistent, meaningful prefix tied to your own publisher, there’s a simple fix: &lt;strong&gt;set a Preferred Solution&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;whats-a-preferred-solution&quot;&gt;What’s a Preferred Solution?&lt;/h2&gt;
&lt;p&gt;By default, any customizations you make outside the context of a specific solution land in the &lt;strong&gt;Common Data Services Default Solution&lt;/strong&gt;. The publisher on that solution has a randomly assigned prefix, so your tables end up with names like &lt;code&gt;cr8a3_project&lt;/code&gt; instead of something clean like &lt;code&gt;contoso_project&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When you set a &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/data-platform/preferred-solution&quot;&gt;Preferred Solution&lt;/a&gt;, any new objects you create — including tables created through the Dataverse MCP — automatically use the publisher and prefix from that solution. No extra configuration needed on the MCP side.&lt;/p&gt;
&lt;h2 id=&quot;setting-your-preferred-solution&quot;&gt;Setting Your Preferred Solution&lt;/h2&gt;
&lt;p&gt;You can set your preferred solution in two ways.&lt;/p&gt;
&lt;h3 id=&quot;option-1-when-creating-a-new-solution&quot;&gt;Option 1: When Creating a New Solution&lt;/h3&gt;
&lt;p&gt;When you &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/data-platform/create-solution&quot;&gt;create a new solution&lt;/a&gt;, there’s a checkbox right on the creation form to &lt;strong&gt;Set as your preferred solution&lt;/strong&gt;. Just check it and you’re good to go.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/blob/master/dataverse-mcp-preferred-solution/preferred-on-create.png?raw=true&quot; alt=&quot;Set preferred solution when creating a new solution&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;option-2-from-the-solutions-list&quot;&gt;Option 2: From the Solutions List&lt;/h3&gt;
&lt;p&gt;If you already have a solution you’d like to use, go to the &lt;strong&gt;Solutions&lt;/strong&gt; area in &lt;a href=&quot;https://make.powerapps.com&quot;&gt;Power Apps&lt;/a&gt;, select your unmanaged solution, and click &lt;strong&gt;Set preferred solution&lt;/strong&gt; on the command bar.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/blob/master/dataverse-mcp-preferred-solution/set-preferred-on-grid.png?raw=true&quot; alt=&quot;Set preferred solution from the solutions grid&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once it’s set, you’ll see a &lt;strong&gt;preferred solution&lt;/strong&gt; indicator in the Solutions area confirming which solution is active.&lt;/p&gt;
&lt;h2 id=&quot;thats-it&quot;&gt;That’s It&lt;/h2&gt;
&lt;p&gt;Now when you create tables through the &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/data-platform/data-platform-mcp&quot;&gt;Dataverse MCP&lt;/a&gt;, they’ll automatically get the prefix from your preferred solution’s publisher. No need to rename anything after the fact or manually move tables between solutions.&lt;/p&gt;
&lt;p&gt;For more details on preferred solutions and solution publishers, check out these Microsoft Learn articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/data-platform/preferred-solution&quot;&gt;Set the preferred solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/data-platform/create-solution&quot;&gt;Create a solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/data-platform/data-platform-mcp&quot;&gt;Dataverse MCP server overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Give it a try — it’s a small change that keeps your environment clean from the start!&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/4753704702389616284/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2026/03/set-your-preferred-solution-for_01187880513.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/4753704702389616284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/4753704702389616284'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2026/03/set-your-preferred-solution-for_01187880513.html' title='Set Your Preferred Solution for the Dataverse MCP'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-2012488540639272387</id><published>2026-02-01T14:47:30.443-05:00</published><updated>2026-02-01T14:47:29.854-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="clierrors"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="dod"/><category scheme="http://www.blogger.com/atom/ns#" term="gcchigh"/><category scheme="http://www.blogger.com/atom/ns#" term="govcloud"/><category scheme="http://www.blogger.com/atom/ns#" term="lowcodedev"/><category scheme="http://www.blogger.com/atom/ns#" term="microsoftcloud"/><category scheme="http://www.blogger.com/atom/ns#" term="paccli"/><category scheme="http://www.blogger.com/atom/ns#" term="portals"/><category scheme="http://www.blogger.com/atom/ns#" term="powerappscli"/><category scheme="http://www.blogger.com/atom/ns#" term="powerappsportals"/><category scheme="http://www.blogger.com/atom/ns#" term="powerpages"/><category scheme="http://www.blogger.com/atom/ns#" term="powerplatform"/><category scheme="http://www.blogger.com/atom/ns#" term="systemnullreferenceexception"/><category scheme="http://www.blogger.com/atom/ns#" term="telemetry"/><category scheme="http://www.blogger.com/atom/ns#" term="troubleshooting"/><title type='text'>Fixing PAC CLI “non-recoverable error” in GCC High and DoD by enabling telemetry</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/9104ef03-e3cc-4582-b8a3-dbc0cf2d3d2a&quot; alt=&quot;Fixing PAC CLI “non-recoverable error” in GCC High and DoD by enabling telemetry&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you use the Power Platform CLI (PAC CLI) in &lt;strong&gt;GCC High&lt;/strong&gt; or &lt;strong&gt;DoD&lt;/strong&gt; environments, you may run into a sudden crash that looks like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sorry, the app encountered a non-recoverable error and will need to terminate. The exception details have been captured and will be forwarded to the development team, if telemetry has been enabled. Session Id: 6e212345-df11-22a7-b633-42380ed22acd, Exception Type: System.NullReferenceException&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s especially confusing because the message mentions telemetry like it’s only about reporting diagnostics, but in the scenario I hit, the crash was tied to telemetry being &lt;strong&gt;disabled&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This post explains the pattern, how to confirm if you’re affected, and the quick fix.&lt;/p&gt;
&lt;h2 id=&quot;what-i-observed&quot;&gt;What I observed&lt;/h2&gt;
&lt;p&gt;In my environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PAC CLI &lt;strong&gt;1.34.1&lt;/strong&gt; worked reliably&lt;/li&gt;
&lt;li&gt;The crash started happening on &lt;strong&gt;versions after 1.34.1&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;This happened in &lt;strong&gt;GCC High&lt;/strong&gt; (and is relevant for &lt;strong&gt;DoD&lt;/strong&gt; tenants as well)&lt;/li&gt;
&lt;li&gt;I first noticed it while downloading and uploading Power Pages (Portals) sites, but I later found it can happen with &lt;strong&gt;other commands too&lt;/strong&gt;. The portal commands were just the first place it showed up consistently.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-surprising-trigger-telemetry-disabled&quot;&gt;The surprising trigger: telemetry disabled&lt;/h2&gt;
&lt;p&gt;If PAC CLI telemetry is disabled, some commands can hit a failure path that results in the CLI terminating with a &lt;code&gt;System.NullReferenceException&lt;/code&gt; and the “non-recoverable error” message.&lt;/p&gt;
&lt;p&gt;So while the message says telemetry would help forward the exception details, in this case telemetry being disabled was part of what caused the crash behavior.&lt;/p&gt;
&lt;h2 id=&quot;check-your-telemetry-status&quot;&gt;Check your telemetry status&lt;/h2&gt;
&lt;p&gt;Run:&lt;/p&gt;
&lt;pre class=&quot; language-bash&quot;&gt;&lt;code class=&quot;prism  language-bash&quot;&gt;pac telemetry status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If it reports telemetry is disabled, you’re a prime candidate for this issue (especially if you’re on a PAC CLI version newer than 1.34.1 in GCC High or DoD).&lt;/p&gt;
&lt;h2 id=&quot;fix-enable-telemetry-and-retry&quot;&gt;Fix: enable telemetry and retry&lt;/h2&gt;
&lt;p&gt;Enable telemetry:&lt;/p&gt;
&lt;pre class=&quot; language-bash&quot;&gt;&lt;code class=&quot;prism  language-bash&quot;&gt;pac telemetry enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then re-run the command that was failing.&lt;/p&gt;
&lt;p&gt;In my testing, simply enabling telemetry made the same commands that were terminating start working normally.&lt;/p&gt;
&lt;h2 id=&quot;why-the-error-is-misleading&quot;&gt;Why the error is misleading&lt;/h2&gt;
&lt;p&gt;The message frames telemetry as “only” a mechanism to forward exception details. In practice, what I experienced is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With telemetry &lt;strong&gt;disabled&lt;/strong&gt;, the CLI can crash with a null reference exception&lt;/li&gt;
&lt;li&gt;With telemetry &lt;strong&gt;enabled&lt;/strong&gt;, the crash path doesn’t occur (or is handled correctly), and the command proceeds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the wording is not wrong, but it doesn’t tell you that telemetry configuration may be directly related to the failure.&lt;/p&gt;
&lt;h2 id=&quot;quick-troubleshooting-checklist&quot;&gt;Quick troubleshooting checklist&lt;/h2&gt;
&lt;p&gt;If you see the “non-recoverable error” + &lt;code&gt;System.NullReferenceException&lt;/code&gt; in GCC High or DoD:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Confirm your PAC CLI version (and note if you upgraded recently)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check telemetry status&lt;/p&gt;
&lt;pre class=&quot; language-bash&quot;&gt;&lt;code class=&quot;prism  language-bash&quot;&gt;pac telemetry status
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If disabled, enable it&lt;/p&gt;
&lt;pre class=&quot; language-bash&quot;&gt;&lt;code class=&quot;prism  language-bash&quot;&gt;pac telemetry enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Retry the exact command that failed&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;If PAC CLI started crashing in GCC High or DoD with a “non-recoverable error” and &lt;code&gt;System.NullReferenceException&lt;/code&gt;, check whether telemetry is disabled. Enabling telemetry is a simple change that can get you unstuck, even though the message makes it sound like telemetry only affects error reporting.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/2012488540639272387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2026/02/fixing-pac-cli-non-recoverable-error-in.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/2012488540639272387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/2012488540639272387'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2026/02/fixing-pac-cli-non-recoverable-error-in.html' title='Fixing PAC CLI “non-recoverable error” in GCC High and DoD by enabling telemetry'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-4629352328439532416</id><published>2025-08-25T17:53:00.002-04:00</published><updated>2025-08-25T17:53:30.575-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="azuredevops"/><category scheme="http://www.blogger.com/atom/ns#" term="azurestorage"/><category scheme="http://www.blogger.com/atom/ns#" term="crosscloud"/><category scheme="http://www.blogger.com/atom/ns#" term="devopssecurity"/><category scheme="http://www.blogger.com/atom/ns#" term="federatedcredentials"/><category scheme="http://www.blogger.com/atom/ns#" term="filetransfer"/><category scheme="http://www.blogger.com/atom/ns#" term="gcchigh"/><category scheme="http://www.blogger.com/atom/ns#" term="managedidentity"/><category scheme="http://www.blogger.com/atom/ns#" term="securepipelines"/><category scheme="http://www.blogger.com/atom/ns#" term="workloadidentityfederation"/><title type='text'>Bridging Clouds: Secure Pipelines from Azure DevOps to GCC High</title><content type='html'>&lt;img width=&quot;1094&quot; height=&quot;619&quot; alt=&quot;Bridging Clouds: Secure Pipelines from Azure DevOps to GCC High&quot; src=&quot;https://github.com/user-attachments/assets/334ce5c9-e2db-474b-a453-c46db56d8726&quot;&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The goal of this setup is to allow an &lt;strong&gt;Azure DevOps pipeline running in the Commercial cloud&lt;/strong&gt; to move files (e.g., build artifacts, documentation, or deployment packages) into a &lt;strong&gt;Storage Account in GCC High&lt;/strong&gt;. Because these are two different clouds, the connection must be established carefully to remain &lt;strong&gt;secure, compliant, and tenant-scoped&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Although this guide is written for &lt;strong&gt;Commercial → GCC High&lt;/strong&gt;, the same approach can also be used for &lt;strong&gt;file transfers between Commercial environments&lt;/strong&gt; or even &lt;strong&gt;across tenants within Commercial Azure&lt;/strong&gt;. By relying on &lt;strong&gt;federated credentials&lt;/strong&gt; instead of secrets, the process ensures secure, governed transfers that honor existing Azure AD (Entra ID) boundaries.&lt;/p&gt;
&lt;p&gt;To achieve this, we use an &lt;strong&gt;Azure User Assigned Managed Identity (UAMI)&lt;/strong&gt; in the target environment, link it with &lt;strong&gt;Workload Identity Federation&lt;/strong&gt; from Azure DevOps (Commercial), and grant it the &lt;strong&gt;minimum necessary roles&lt;/strong&gt;. This way, files can flow between environments without storing long-lived secrets or keys.&lt;/p&gt;
&lt;h2 id=&quot;key-placeholders-to-fill-in&quot;&gt;Key Placeholders to Fill In&lt;/h2&gt;
&lt;p&gt;This is the list of the placeholder for all of the azure resources and connection string we will need during the setup process.  This can be helpful when going through the instructions below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;From GCC High Azure Portal (&lt;a href=&quot;https://portal.azure.us/&quot;&gt;https://portal.azure.us/&lt;/a&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-subscription-id&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-subscription-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-resource-group-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-storage-account-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-storage-container-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-container-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-managed-identity-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-managed-identity-client-id&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-federated-credential-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;gcc-tenant-id&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;From Azure DevOps / Commercial Azure Portal (&lt;a href=&quot;https://portal.azure.com/&quot;&gt;https://portal.azure.com/&lt;/a&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;commercial-issuer-url-from-ADO&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;commercial-subject-id-from-ADO&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;commercial-service-connection-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;step-1-—-create-a-storage-account-in-gcc-high&quot;&gt;Step 1 — Create a Storage Account in GCC High&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;&lt;a href=&quot;https://portal.azure.us/&quot;&gt;GCC High Azure Portal&lt;/a&gt;&lt;/strong&gt;, create a new &lt;strong&gt;Storage Account&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Resource Group: &lt;code&gt;&amp;lt;&amp;lt;gcc-resource-group-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type: &lt;strong&gt;Blob Storage (Gen2)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Name: &lt;code&gt;&amp;lt;&amp;lt;gcc-storage-account-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Note the &lt;strong&gt;subscription ID&lt;/strong&gt; (&lt;code&gt;&amp;lt;&amp;lt;gcc-subscription-id&amp;gt;&amp;gt;&lt;/code&gt;) and &lt;strong&gt;resource group name&lt;/strong&gt; for later use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a container within the storage acocunt.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &amp;lt;&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-2-—-create-a-managed-identity-in-gcc-high&quot;&gt;Step 2 — Create a Managed Identity in GCC High&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;&lt;a href=&quot;https://portal.azure.us/&quot;&gt;GCC High Azure Portal&lt;/a&gt;&lt;/strong&gt;, within the same &lt;strong&gt;Resource Group&lt;/strong&gt; (&lt;code&gt;&amp;lt;&amp;lt;gcc-resource-group-name&amp;gt;&amp;gt;&lt;/code&gt;), create a &lt;strong&gt;User Assigned Managed Identity (UAMI)&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;&amp;lt;&amp;lt;gcc-managed-identity-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy the &lt;strong&gt;Client ID&lt;/strong&gt; (&lt;code&gt;&amp;lt;&amp;lt;gcc-managed-identity-client-id&amp;gt;&amp;gt;&lt;/code&gt;) and &lt;strong&gt;Object ID&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-3-—-assign-roles-to-the-managed-identity&quot;&gt;Step 3 — Assign Roles to the Managed Identity&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;At the &lt;strong&gt;Subscription&lt;/strong&gt; level (&lt;code&gt;&amp;lt;&amp;lt;gcc-subscription-id&amp;gt;&amp;gt;&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Access Control (IAM)&lt;/strong&gt; → &lt;strong&gt;Add Role Assignment&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Role: &lt;strong&gt;Reader&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Assign to: &lt;code&gt;&amp;lt;&amp;lt;gcc-managed-identity-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;At the &lt;strong&gt;Storage Account&lt;/strong&gt; level (&lt;code&gt;&amp;lt;&amp;lt;gcc-storage-account-name&amp;gt;&amp;gt;&lt;/code&gt; in &lt;code&gt;&amp;lt;&amp;lt;gcc-resource-group-name&amp;gt;&amp;gt;&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add &lt;strong&gt;Role Assignment&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Role: &lt;strong&gt;Storage Blob Data Contributor&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Assign to: &lt;code&gt;&amp;lt;&amp;lt;gcc-managed-identity-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-4-—-begin-service-connection-setup-in-azure-devops-commercial&quot;&gt;Step 4 — Begin Service Connection Setup in Azure DevOps (Commercial)&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;&lt;a href=&quot;https://portal.azure.com/&quot;&gt;Commercial Azure Portal&lt;/a&gt;&lt;/strong&gt;, go to &lt;strong&gt;Azure DevOps → Project Settings → Service Connections&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new &lt;strong&gt;Azure Resource Manager&lt;/strong&gt; service connection.&lt;/p&gt;
&lt;img width=&quot;200&quot; height=&quot;200&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/4c165ce2-54b1-443e-b8a0-018f481d9288&quot;&gt;  
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the wizard as follows:&lt;/p&gt;
&lt;img width=&quot;300&quot; height=&quot;500&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/55035c6c-c253-48f3-b577-349a71077fc8&quot;&gt;  
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Identity Type:&lt;/strong&gt; &lt;em&gt;App registration or Managed Identity (Manual)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Credential:&lt;/strong&gt; &lt;em&gt;Workload Identity Federation&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environment:&lt;/strong&gt; &lt;em&gt;Azure US Government&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Directory Tenant ID:&lt;/strong&gt; &lt;code&gt;&amp;lt;&amp;lt;gcc-tenant-id&amp;gt;&amp;gt;&lt;/code&gt; (from GCC High tenant)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-5-—-configure-federated-credentials-exchange-between-ado--gcc-high&quot;&gt;Step 5 — Configure Federated Credentials (Exchange Between ADO &amp;amp; GCC High)&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;From the ADO wizard (Commercial), copy the:&lt;/p&gt;
 &lt;img width=&quot;300&quot; height=&quot;300&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/835fd852-d0f3-4ccb-992b-53cc75e4045d&quot;&gt;  
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Issuer URL&lt;/strong&gt; → &lt;code&gt;&amp;lt;&amp;lt;commercial-issuer-url-from-ADO&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subject Identifier&lt;/strong&gt; → &lt;code&gt;&amp;lt;&amp;lt;commercial-subject-id-from-ADO&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;&lt;a href=&quot;https://portal.azure.us/&quot;&gt;GCC High Azure Portal&lt;/a&gt;&lt;/strong&gt; → &lt;strong&gt;Managed Identity&lt;/strong&gt; (&lt;code&gt;&amp;lt;&amp;lt;gcc-managed-identity-name&amp;gt;&amp;gt;&lt;/code&gt; in &lt;code&gt;&amp;lt;&amp;lt;gcc-resource-group-name&amp;gt;&amp;gt;&lt;/code&gt;):&lt;/p&gt;
&lt;img width=&quot;500&quot; height=&quot;400&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/7f27586e-b395-424a-90fe-e7a578218ea5&quot;&gt;  
&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Federated Credentials → Add Credential&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Scenario: &lt;strong&gt;Other&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Issuer: &lt;code&gt;&amp;lt;&amp;lt;commercial-issuer-url-from-ADO&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Subject Identifier: &lt;code&gt;&amp;lt;&amp;lt;commercial-subject-id-from-ADO&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Name: &lt;code&gt;&amp;lt;&amp;lt;gcc-federated-credential-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Audience: keep default (&lt;code&gt;api://AzureADTokenExchange&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-6-—-complete-service-connection-in-ado-commercial&quot;&gt;Step 6 — Complete Service Connection in ADO (Commercial)&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Back in ADO’s &lt;strong&gt;Service Connection Wizard&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scope level: &lt;strong&gt;Subscription&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Subscription ID: &lt;code&gt;&amp;lt;&amp;lt;gcc-subscription-id&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Subscription Name: &lt;code&gt;&amp;lt;&amp;lt;gcc-subscription-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Authentication → Client ID: &lt;code&gt;&amp;lt;&amp;lt;gcc-managed-identity-client-id&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Uncheck &lt;em&gt;Grant access permissions to all pipelines&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Verify and Save&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-6a-—-approve-pipeline-to-use-the-service-connection&quot;&gt;Step 6a — Approve pipeline to use the service connection&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In ADO (Commercial) go to &lt;strong&gt;Project Settings → Service connections → &lt;code&gt;&amp;lt;&amp;lt;commercial-service-connection-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open &lt;strong&gt;Security&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;strong&gt;User permissions&lt;/strong&gt;, explicitly grant access to the &lt;strong&gt;project&lt;/strong&gt; and/or the &lt;strong&gt;specific pipeline&lt;/strong&gt; that will run this connection.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Option A (recommended): Add the &lt;strong&gt;build pipeline&lt;/strong&gt; or its &lt;strong&gt;build service account&lt;/strong&gt; (e.g., &lt;code&gt;Project Name Build Service (Organization)&lt;/code&gt;), set &lt;strong&gt;Use&lt;/strong&gt; permission to &lt;strong&gt;Allow&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Option B: Add the &lt;strong&gt;Project Contributors&lt;/strong&gt; group if you want broader use.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alternative: If you try to run the pipeline without this step, ADO will pause with “&lt;strong&gt;Needs approval&lt;/strong&gt;.” You can approve it from the run page, but configuring Security first is cleaner.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-7-—-test-the-connection&quot;&gt;Step 7 — Test the Connection&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In ADO (Commercial), create a new &lt;strong&gt;repository&lt;/strong&gt; with a single file &lt;code&gt;README.md&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new &lt;strong&gt;Pipeline&lt;/strong&gt; pointing to this repo.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agent pool: &lt;code&gt;windows-latest&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;Azure File Copy&lt;/strong&gt; task to the pipeline.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Source Path: &lt;code&gt;README.md&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Azure Subscription: &lt;code&gt;&amp;lt;&amp;lt;commercial-service-connection-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Destination: &lt;strong&gt;Azure Blob Storage&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Storage Account: &lt;code&gt;&amp;lt;&amp;lt;gcc-storage-account-name&amp;gt;&amp;gt;&lt;/code&gt; (in &lt;code&gt;&amp;lt;&amp;lt;gcc-resource-group-name&amp;gt;&amp;gt;&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Container: &lt;code&gt;&amp;lt;&amp;lt;gcc-container-name&amp;gt;&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Here is an example pipline.  Make sure to replace the placeholders in the AzureFileCopy@6 tasks based on the names you used earlier&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Example pipeline to copy README.MD file
 trigger:
 - master
 
 pool:
   vmImage: windows-latest
 
 steps:
 - script: echo Lets copy a file!
   displayName: &#39;Run a one-line script&#39;
 
 - task: AzureFileCopy@6
   inputs:
     SourcePath: &#39;README.MD&#39;
     azureSubscription: &#39;&amp;lt;&amp;lt;commercial-service-connection-name&amp;gt;&amp;gt;&#39;
     Destination: &#39;AzureBlob&#39;
     storage: &#39;&amp;lt;&amp;lt;gcc-storage-account-name&amp;gt;&amp;gt;&#39;
     ContainerName: &#39;&amp;lt;&amp;lt;gcc-storage-container-name&amp;gt;&amp;gt;&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the pipeline.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you did not complete Step 6a, approve the service connection usage when prompted.&lt;/li&gt;
&lt;li&gt;✅ Verify &lt;code&gt;README.md&lt;/code&gt; appears in the GCC High Storage Blob container.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/4629352328439532416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/08/bridging-clouds-secure-pipelines-from.html#comment-form' title='24 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/4629352328439532416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/4629352328439532416'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/08/bridging-clouds-secure-pipelines-from.html' title='Bridging Clouds: Secure Pipelines from Azure DevOps to GCC High'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>24</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-3843415809208819705</id><published>2025-08-22T13:01:00.001-04:00</published><updated>2025-08-22T13:01:40.549-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AzureLogicApps"/><category scheme="http://www.blogger.com/atom/ns#" term="AzureManagedIdentity"/><category scheme="http://www.blogger.com/atom/ns#" term="AzureSecurity"/><category scheme="http://www.blogger.com/atom/ns#" term="DataversePlugins"/><category scheme="http://www.blogger.com/atom/ns#" term="LogicAppsConsumption"/><category scheme="http://www.blogger.com/atom/ns#" term="OAuth2"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerPlatform"/><category scheme="http://www.blogger.com/atom/ns#" term="TokenAuthentication"/><title type='text'>Locking Down a Logic App (Consumption) with OAuth for Calls from Dataverse Plug-ins using Managed Identity</title><content type='html'>&lt;img width=&quot;1248&quot; height=&quot;685&quot; alt=&quot;Locking Down a Logic App (Consumption) with OAuth for Calls from Dataverse Plug-ins using Managed Identity&quot; src=&quot;https://github.com/user-attachments/assets/473e9312-febc-44c9-a391-a2d94abeef8c&quot;&gt;
&lt;h2 id=&quot;why-i-did-this&quot;&gt;Why I did this&lt;/h2&gt;
&lt;p&gt;I’m using &lt;strong&gt;managed identity&lt;/strong&gt; to let a &lt;a href=&quot;https://learn.microsoft.com/en-us/power-platform/admin/managed-identity-overview&quot;&gt;Dataverse plug-in&lt;/a&gt; call Azure resources without storing secrets. One of those calls hits a &lt;strong&gt;Logic App (Consumption)&lt;/strong&gt; via the &lt;em&gt;When an HTTP request is received&lt;/em&gt; trigger. I wanted to ensure the workflow can &lt;strong&gt;only&lt;/strong&gt; be invoked by callers from &lt;strong&gt;my tenant&lt;/strong&gt; using &lt;strong&gt;OAuth&lt;/strong&gt;—no shared access signature (SAS) keys. (If you’re on &lt;strong&gt;Logic Apps Standard&lt;/strong&gt;, you’d typically use App Service “Easy Auth”.)&lt;/p&gt;
&lt;p&gt;Microsoft’s docs say you can require OAuth and (critically) you must &lt;strong&gt;disable SAS&lt;/strong&gt; for request triggers in Consumption, otherwise a valid SAS bypasses OAuth. The official instructions work, but I found a simpler way to flip the SAS switch directly in code view.&lt;/p&gt;
&lt;h2 id=&quot;what-i-changed&quot;&gt;What I changed&lt;/h2&gt;
&lt;h3 id=&quot;disable-sas-for-the-http-trigger-consumption-only&quot;&gt;1) Disable SAS for the HTTP trigger (Consumption only)&lt;/h3&gt;
&lt;img width=&quot;1260&quot; height=&quot;526&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/b1c32b30-4139-454d-b3b9-6326ed089148&quot;&gt;
&lt;ol&gt;
&lt;li&gt;Open the Logic App (Consumption) in the Azure portal.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Development Tools ➜ Logic app code view&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the workflow JSON, add the following &lt;strong&gt;sibling&lt;/strong&gt; to &lt;code&gt;&quot;parameters&quot;&lt;/code&gt; (top level) and &lt;strong&gt;Save&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;accessControl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;triggers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;sasAuthenticationPolicy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;state&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Disabled&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This disables SAS so OAuth can’t be bypassed. (This is equivalent to what the docs recommend; adding it here is the fastest way.)&lt;/p&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;After you save, the &lt;code&gt;accessControl&lt;/code&gt; snippet will &lt;strong&gt;not appear&lt;/strong&gt; again the next time you open &lt;strong&gt;code view&lt;/strong&gt;. The setting still applies, it’s just hidden.&lt;/li&gt;
&lt;li&gt;If you try to reapply the JSON snippet again later, it will &lt;strong&gt;delete your existing OAuth profile&lt;/strong&gt;, and you’ll need to recreate it from scratch.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: If you automate deployments, include this in your ARM/Bicep/Template spec rather than patching after the fact.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;add-an-oauth-policy-on-the-logic-app&quot;&gt;2) Add an OAuth policy on the Logic App&lt;/h3&gt;
&lt;img width=&quot;1294&quot; height=&quot;774&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/a49e65d3-f1da-46f2-9ce5-de6868c991f4&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the Logic App, go to &lt;strong&gt;Authorization&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;+ Add policy&lt;/strong&gt; ➜ &lt;strong&gt;OAuth 2.0&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Issuer&lt;/strong&gt; (iss): use your tenant issuer, e.g.&lt;br&gt;
&lt;code&gt;https://sts.windows.net/&amp;lt;tenant-guid&amp;gt;/&lt;/code&gt; &lt;em&gt;(v1)&lt;/em&gt; or&lt;br&gt;
&lt;code&gt;https://login.microsoftonline.com/&amp;lt;tenant-id&amp;gt;/v2.0&lt;/code&gt; &lt;em&gt;(v2)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audience&lt;/strong&gt; (aud): the resource your token targets. In my case, I used &lt;code&gt;https://management.azure.com&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The OAuth policy validates the token’s &lt;code&gt;iss&lt;/code&gt; and &lt;code&gt;aud&lt;/code&gt; claims on inbound calls to the request trigger.&lt;/p&gt;
&lt;h2 id=&quot;narrowing-down-the-oauth-to-specific-managed-identity&quot;&gt;Narrowing Down the OAuth To Specific Managed Identity&lt;/h2&gt;
&lt;p&gt;If you want to ensure that only a specific managed identity can access this logic app you can additional add a custom claim onto the OAuth profile.  To do this add a custom claim in the OAuth Profile.  Set the claim name as &lt;code&gt;appid&lt;/code&gt; and set the value to the id of your managed identity.  This will ensure that only that managed identity can call this Logic App.  You can add multiple OAuth profiles to allow for more managed identities if you want.&lt;/p&gt;
&lt;img width=&quot;1271&quot; height=&quot;502&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/c53fd358-2de6-4925-a106-f1f07d05d3a3&quot;&gt;
&lt;h2 id=&quot;what-broke-and-how-i-fixed-it&quot;&gt;What broke (and how I fixed it)&lt;/h2&gt;
&lt;p&gt;On first run I got &lt;strong&gt;issuer or audience mismatch&lt;/strong&gt; errors. My Dataverse plug-in was acquiring a token whose &lt;strong&gt;issuer&lt;/strong&gt; looked like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://sts.windows.net/&amp;lt;tenant-guid&amp;gt;/&lt;/code&gt; (AAD v1 style)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;…but I had configured the Logic App policy with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://login.microsoftonline.com/&amp;lt;tenant-id&amp;gt;/&lt;/code&gt; (different issuer format)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To debug, I had my plug-in &lt;strong&gt;log the raw access token&lt;/strong&gt;, then pasted it into &lt;strong&gt;&lt;a href=&quot;https://jwt.ms&quot;&gt;https://jwt.ms&lt;/a&gt;&lt;/strong&gt; to inspect the claims. I updated the Logic App policy to use the &lt;strong&gt;exact&lt;/strong&gt; issuer from the token, and everything worked.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Quick refresher:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Issuer (&lt;code&gt;iss&lt;/code&gt;)&lt;/strong&gt; must match exactly, including trailing slash and version (v1 vs v2.0).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audience (&lt;code&gt;aud&lt;/code&gt;)&lt;/strong&gt; must match the resource you requested when you got the token (e.g., &lt;code&gt;https://management.azure.com&lt;/code&gt; for ARM).&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;minimal-plug-in-tracing-snippet-to-see-the-token&quot;&gt;Minimal plug-in tracing snippet (to see the token)&lt;/h2&gt;
&lt;p&gt;When you call your Logic App from the plug-in, capture and trace the bearer token you’re sending. For example:&lt;/p&gt;
&lt;pre class=&quot; language-csharp&quot;&gt;&lt;code class=&quot;prism  language-csharp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// inside Execute(IServiceProvider serviceProvider)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IPluginExecutionContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;serviceProvider&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IPluginExecutionContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; tracing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ITracingService&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;serviceProvider&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ITracingService&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Acquire the token with managed identity&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt; accessToken &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ManagedIdentityService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AcquireToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://management.azure.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Output the full token (needed for jwt.ms inspection)&lt;/span&gt;
tracing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Trace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;AccessToken: {0}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; accessToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// …then send HTTP request with Authorization: Bearer {accessToken}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note:&lt;/strong&gt; Output the &lt;strong&gt;entire token&lt;/strong&gt; (not truncated) if you want to paste it into &lt;strong&gt;&lt;a href=&quot;http://jwt.ms&quot;&gt;jwt.ms&lt;/a&gt;&lt;/strong&gt; for inspection of &lt;code&gt;iss&lt;/code&gt; and &lt;code&gt;aud&lt;/code&gt;.  Also make sure to remove this tracing before deployment.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/power-platform/admin/managed-identity-overview&quot;&gt;Power Platform managed identity overview (Dataverse plug-ins)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.azure.cn/en-us/logic-apps/logic-apps-securing-a-logic-app?tabs=azure-portal#disable-shared-access-signature-sas-authentication-consumption-only&quot;&gt;Securing Logic Apps &amp;amp; enabling OAuth (Consumption) + adding authorization policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jwt.ms&quot;&gt;Inspect tokens quickly with jwt.ms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/3843415809208819705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/08/locking-down-logic-app-consumption-with.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/3843415809208819705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/3843415809208819705'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/08/locking-down-logic-app-consumption-with.html' title='Locking Down a Logic App (Consumption) with OAuth for Calls from Dataverse Plug-ins using Managed Identity'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-6311118988225856554</id><published>2025-08-18T16:19:00.002-04:00</published><updated>2025-08-18T16:19:46.914-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="adftips"/><category scheme="http://www.blogger.com/atom/ns#" term="automateddata"/><category scheme="http://www.blogger.com/atom/ns#" term="azuredatafactory"/><category scheme="http://www.blogger.com/atom/ns#" term="azureintegration"/><category scheme="http://www.blogger.com/atom/ns#" term="dataengineering"/><category scheme="http://www.blogger.com/atom/ns#" term="dataflow"/><category scheme="http://www.blogger.com/atom/ns#" term="dataverse"/><category scheme="http://www.blogger.com/atom/ns#" term="LowCode"/><category scheme="http://www.blogger.com/atom/ns#" term="msdyn365"/><category scheme="http://www.blogger.com/atom/ns#" term="parameter"/><category scheme="http://www.blogger.com/atom/ns#" term="pipeline"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerPlatform"/><category scheme="http://www.blogger.com/atom/ns#" term="stringtype"/><category scheme="http://www.blogger.com/atom/ns#" term="triggertime"/><category scheme="http://www.blogger.com/atom/ns#" term="webapi"/><title type='text'>Passing Pipeline Trigger Time to Data Flows in Azure Data Factory: Use Strings, Not Timestamps!</title><content type='html'>&lt;img width=&quot;1613&quot; height=&quot;1068&quot; alt=&quot;Passing Pipeline Trigger Time to Data Flows in Azure Data Factory: Use Strings, Not Timestamps!&quot; src=&quot;https://github.com/user-attachments/assets/a43143f8-5ac0-4dde-96f6-cce54a341855&quot;&gt;
&lt;p&gt;When working with Azure Data Factory (ADF) and the &lt;strong&gt;Dataverse connector&lt;/strong&gt;, passing the pipeline trigger time into a Data Flow can be trickier than expected.&lt;/p&gt;
&lt;h3 id=&quot;the-scenario&quot;&gt;The Scenario&lt;/h3&gt;
&lt;p&gt;You want to pass the pipeline’s trigger time—using the &lt;code&gt;@pipeline().TriggerTime&lt;/code&gt; system variable—into a Data Flow. This is often needed for auditing, filtering, or other time-based logic.&lt;/p&gt;
&lt;p&gt;The catch? You’re using &lt;strong&gt;Dataverse&lt;/strong&gt;, which communicates over the Web API and handles datetime values as &lt;strong&gt;strings&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-common-mistake&quot;&gt;The Common Mistake&lt;/h3&gt;
&lt;p&gt;In Azure Data Factory, you might instinctively define the Data Flow parameter as a &lt;strong&gt;timestamp&lt;/strong&gt; or &lt;strong&gt;date&lt;/strong&gt; type. But ADF doesn’t have a dedicated &lt;strong&gt;datetime&lt;/strong&gt; type—only &lt;strong&gt;date&lt;/strong&gt; and &lt;strong&gt;timestamp&lt;/strong&gt;. So you choose one of those, thinking it aligns with your goal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Then you hit an error.&lt;/strong&gt;&lt;br&gt;
And to make matters worse, the error message doesn’t clearly explain the real issue—it can be vague or misleading, which only adds to the confusion. This tripped me up for a while, as I assumed the problem was elsewhere.&lt;br&gt;
&lt;img width=&quot;1020&quot; height=&quot;646&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/abbb0756-0507-4d4d-8673-e6bd21bbdbc9&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-solution&quot;&gt;The Solution&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Define the Data Flow parameter as a &lt;code&gt;string&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;
&lt;img width=&quot;1541&quot; height=&quot;774&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/5a88fdea-b987-4314-a75c-e30c609b7196&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the pipeline, pass the &lt;code&gt;@pipeline().TriggerTime&lt;/code&gt; system variable directly into this parameter using a pipeline expression.&lt;br&gt;
&lt;img width=&quot;1260&quot; height=&quot;774&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/c53057c5-f92c-4adc-8f88-18ba8a11426a&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This small change ensures compatibility with the Dataverse connector and avoids the cryptic conversion error.&lt;/p&gt;
&lt;h3 id=&quot;lesson-learned&quot;&gt;Lesson Learned&lt;/h3&gt;
&lt;p&gt;Even though it’s tempting to use date or timestamp types when dealing with datetime values in ADF, the &lt;strong&gt;correct approach for Dataverse is to use strings&lt;/strong&gt;. It aligns with how the Web API expects the data and helps you avoid hard-to-decipher errors.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/6311118988225856554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/08/passing-pipeline-trigger-time-to-data.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/6311118988225856554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/6311118988225856554'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/08/passing-pipeline-trigger-time-to-data.html' title='Passing Pipeline Trigger Time to Data Flows in Azure Data Factory: Use Strings, Not Timestamps!'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-708637569153156461</id><published>2025-08-11T13:36:00.002-04:00</published><updated>2025-08-11T13:36:39.920-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="BestPractice"/><category scheme="http://www.blogger.com/atom/ns#" term="Buffering"/><category scheme="http://www.blogger.com/atom/ns#" term="DataModeling"/><category scheme="http://www.blogger.com/atom/ns#" term="DataShaping"/><category scheme="http://www.blogger.com/atom/ns#" term="Debugging"/><category scheme="http://www.blogger.com/atom/ns#" term="DriftlessMerges"/><category scheme="http://www.blogger.com/atom/ns#" term="Duplicates"/><category scheme="http://www.blogger.com/atom/ns#" term="etl"/><category scheme="http://www.blogger.com/atom/ns#" term="GroupBy"/><category scheme="http://www.blogger.com/atom/ns#" term="Join"/><category scheme="http://www.blogger.com/atom/ns#" term="M"/><category scheme="http://www.blogger.com/atom/ns#" term="Merge"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="PickOne"/><category scheme="http://www.blogger.com/atom/ns#" term="powerbi"/><category scheme="http://www.blogger.com/atom/ns#" term="powerquery"/><category scheme="http://www.blogger.com/atom/ns#" term="QueryFolding"/><category scheme="http://www.blogger.com/atom/ns#" term="Table.Buffer"/><title type='text'>Power Query: Driftless Merges using Table.Buffer</title><content type='html'>&lt;img width=&quot;1027&quot; height=&quot;601&quot; alt=&quot;Power Query: Driftless Merges using Table.Buffer&quot; src=&quot;https://github.com/user-attachments/assets/a665d4aa-ae20-4998-a7ba-622ecb0dbd93&quot;&gt;
&lt;h2 id=&quot;what-happened&quot;&gt;What happened&lt;/h2&gt;
&lt;p&gt;Recently I was working on data where I needed to pick one best row per group, then merge that result with a lookup table. Here’s the head-scratcher I hit: the pick looked right in preview, but after the merge some groups showed different rows, like the merge had used the pre-pick data. What was happening is that Power Query re-evaluated and re-ordered things during the merge, which changed which row got selected. The fix was to freeze the picked result with &lt;code&gt;Table.Buffer&lt;/code&gt; right after the pick so the merge used exactly those rows. I also made the lookup one row per key to avoid duplicate expands. After that, everything stayed stable on refresh.&lt;/p&gt;
&lt;h2 id=&quot;why-and-how-table.buffer-works&quot;&gt;Why and how &lt;code&gt;Table.Buffer&lt;/code&gt; works&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Why the drift happens&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Power Query is lazy. It does not materialize intermediate steps until needed.&lt;/li&gt;
&lt;li&gt;A Merge can push work back to the source (folding). That re-evaluation can change row order.&lt;/li&gt;
&lt;li&gt;If your “pick one” depends on order, the selected row can change during the Merge.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What &lt;code&gt;Table.Buffer&lt;/code&gt; does&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Takes a snapshot of the current table and caches it in memory.&lt;/li&gt;
&lt;li&gt;Preserves the row order you produced before buffering.&lt;/li&gt;
&lt;li&gt;Acts like a barrier so later steps cannot change that selection.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Where to place it&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot; language-powerquery&quot;&gt;&lt;code class=&quot;prism  language-powerquery&quot;&gt;// After you have exactly the rows and columns you want to keep
KeptCols   = Table.SelectColumns(YourPickedTable, {&quot;GroupKey&quot;,&quot;ChosenCol1&quot;,&quot;ChosenCol2&quot;,&quot;TieBreaker&quot;});
LeftFrozen = Table.Buffer(KeptCols);

// Then do your join
RightOne   = Table.Distinct(RightTable, {&quot;RightKey&quot;});
Merged     = Table.NestedJoin(LeftFrozen, {&quot;GroupKey&quot;}, RightOne, {&quot;RightKey&quot;}, &quot;Right&quot;, JoinKind.LeftOuter);
Final      = Table.ExpandTableColumn(Merged, &quot;Right&quot;, {&quot;R1&quot;,&quot;R2&quot;}, {&quot;R1&quot;,&quot;R2&quot;});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Use it when&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You pick or rank one row per group, then Merge or Append&lt;/li&gt;
&lt;li&gt;Post-merge results do not match the pre-merge preview&lt;/li&gt;
&lt;li&gt;You branch the same picked result to multiple places and need consistency&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cautions&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Holds the data in memory. Avoid on very large tables.&lt;/li&gt;
&lt;li&gt;Steps after the buffer often will not fold back to the source. Use it only where correctness matters.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;demonstration-of-issue&quot;&gt;Demonstration of issue&lt;/h2&gt;
&lt;p&gt;Here is a side-by-side Power Query comparison showing why buffering matters. Both queries “pick” 4 rows before the merge. After the merge, the unbuffered query returns 5 rows and shows a changed pick, while the buffered query returns the expected 4 rows that match the pick.&lt;/p&gt;
&lt;img width=&quot;3513&quot; height=&quot;1526&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/df4c6655-3b52-4ff7-b757-f0e5c1387bfb&quot;&gt;
&lt;h2 id=&quot;reproduce-the-issue-and-the-fix&quot;&gt;Reproduce the issue and the fix&lt;/h2&gt;
&lt;h3 id=&quot;create-the-three-small-tables-with-enter-data&quot;&gt;Create the three small tables with Enter data&lt;/h3&gt;
&lt;p&gt;In Power Query, use &lt;strong&gt;Home &amp;gt; Enter data&lt;/strong&gt;, paste each block, check &lt;strong&gt;Use first row as headers&lt;/strong&gt;, click &lt;strong&gt;OK&lt;/strong&gt;. Name them &lt;strong&gt;Loans&lt;/strong&gt;, &lt;strong&gt;StatusReference&lt;/strong&gt;, and &lt;strong&gt;BranchDirectory&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Loans&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot; language-text&quot;&gt;&lt;code class=&quot;prism  language-text&quot;&gt;BranchName,Item Type,State,CopyAddedDate,State Change Date,CopyId
Downtown Branch,Circulating,Checked Out,2024-01-10,2024-01-12,CP001
Downtown Branch,Circulating,Available,2024-02-01,2024-02-15,CP002
Uptown Branch,Circulating,Reserved,,2024-03-01,CP010
Uptown Branch,Circulating,Available,2024-04-01,2024-04-10,CP011
West Branch,Circulating,Checked Out,2023-12-01,2023-12-05,CP020
West Branch,Circulating,Lost,2022-05-01,2024-05-10,CP021
Reference Branch,Reference,Available,2024-06-01,2024-06-10,CP030
South Branch,Circulating,Reserved,,2024-07-01,CP040
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;StatusReference&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot; language-text&quot;&gt;&lt;code class=&quot;prism  language-text&quot;&gt;State,Status,StatusOrder
Available,Available,3
Reserved,Reserved,2
Checked Out,Checked Out,1
Lost,Lost,0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;BranchDirectory&lt;/strong&gt;&lt;br&gt;
(contains a duplicate on purpose)&lt;/p&gt;
&lt;pre class=&quot; language-text&quot;&gt;&lt;code class=&quot;prism  language-text&quot;&gt;branch_name,branch_id,branch_current_status,branch_inventory_date
Downtown Branch,11111111-1111-1111-1111-111111111111,Available,2024-02-15
Uptown Branch,22222222-2222-2222-2222-222222222222,Available,2024-04-10
Uptown Branch,22222222-2222-2222-2222-222222222223,Available,2024-04-10
West Branch,33333333-3333-3333-3333-333333333333,Checked Out,2023-12-05
South Branch,55555555-5555-5555-5555-555555555555,Reserved,
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;query-1-pick-per-group-then-merge-unbuffered&quot;&gt;Query 1: pick per group, then merge (unbuffered)&lt;/h3&gt;
&lt;pre class=&quot; language-powerquery&quot;&gt;&lt;code class=&quot;prism  language-powerquery&quot;&gt;let
    Source = Loans,

    Types = Table.TransformColumnTypes(Source, {
        {&quot;BranchName&quot;, type text}, {&quot;Item Type&quot;, type text}, {&quot;State&quot;, type text},
        {&quot;CopyAddedDate&quot;, type date}, {&quot;State Change Date&quot;, type date}, {&quot;CopyId&quot;, type text}}),

    Circulating = Table.SelectRows(Types, each [Item Type] = &quot;Circulating&quot;),

    JoinStatus = Table.NestedJoin(Circulating, {&quot;State&quot;}, StatusReference, {&quot;State&quot;}, &quot;StatusReference&quot;, JoinKind.LeftOuter),
    ExpandStat = Table.ExpandTableColumn(JoinStatus, &quot;StatusReference&quot;, {&quot;Status&quot;,&quot;StatusOrder&quot;}, {&quot;Status&quot;,&quot;StatusOrder&quot;}),

    AddPriority   = Table.AddColumn(ExpandStat, &quot;Priority&quot;, each if [Status] = &quot;Available&quot; then 1 else 0, Int64.Type),
    SortedForPick = Table.Sort(AddPriority, {{&quot;BranchName&quot;, Order.Ascending}, {&quot;Priority&quot;, Order.Descending}, {&quot;StatusOrder&quot;, Order.Descending}, {&quot;State Change Date&quot;, Order.Descending}}),

    GroupPick  = Table.Group(SortedForPick, {&quot;BranchName&quot;}, {{&quot;Pick&quot;, each Table.FirstN(_, 1), type table}}),
    ExpandPick = Table.ExpandTableColumn(GroupPick, &quot;Pick&quot;, {&quot;Status&quot;,&quot;CopyAddedDate&quot;,&quot;State Change Date&quot;}, {&quot;Status&quot;,&quot;Date&quot;,&quot;State Change Date&quot;}),

    MergeBranch  = Table.NestedJoin(ExpandPick, {&quot;BranchName&quot;}, BranchDirectory, {&quot;branch_name&quot;}, &quot;BranchDirectory&quot;, JoinKind.LeftOuter),
    ExpandBranch = Table.ExpandTableColumn(MergeBranch, &quot;BranchDirectory&quot;, {&quot;branch_id&quot;,&quot;branch_current_status&quot;,&quot;branch_inventory_date&quot;}, {&quot;branch_id&quot;,&quot;branch_current_status&quot;,&quot;branch_inventory_date&quot;}),

    Final = Table.ReorderColumns(ExpandBranch, {&quot;BranchName&quot;,&quot;Status&quot;,&quot;Date&quot;,&quot;State Change Date&quot;,&quot;branch_id&quot;,&quot;branch_current_status&quot;,&quot;branch_inventory_date&quot;})
in
    Final
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What you may see&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some picked rows change after the merge&lt;/li&gt;
&lt;li&gt;Duplicate rows for a key that appears twice in the right table&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;query-2-same-logic-with-table.buffer-to-freeze-the-pick&quot;&gt;Query 2: same logic with &lt;code&gt;Table.Buffer&lt;/code&gt; to freeze the pick&lt;/h3&gt;
&lt;pre class=&quot; language-powerquery&quot;&gt;&lt;code class=&quot;prism  language-powerquery&quot;&gt;let
    Source = Loans,

    Types = Table.TransformColumnTypes(Source, {
        {&quot;BranchName&quot;, type text}, {&quot;Item Type&quot;, type text}, {&quot;State&quot;, type text},
        {&quot;CopyAddedDate&quot;, type date}, {&quot;State Change Date&quot;, type date}, {&quot;CopyId&quot;, type text}}),

    Circulating = Table.SelectRows(Types, each [Item Type] = &quot;Circulating&quot;),

    JoinStatus = Table.NestedJoin(Circulating, {&quot;State&quot;}, StatusReference, {&quot;State&quot;}, &quot;StatusReference&quot;, JoinKind.LeftOuter),
    ExpandStat = Table.ExpandTableColumn(JoinStatus, &quot;StatusReference&quot;, {&quot;Status&quot;,&quot;StatusOrder&quot;}, {&quot;Status&quot;,&quot;StatusOrder&quot;}),

    AddPriority   = Table.AddColumn(ExpandStat, &quot;Priority&quot;, each if [Status] = &quot;Available&quot; then 1 else 0, Int64.Type),
    SortedForPick = Table.Sort(AddPriority, {{&quot;BranchName&quot;, Order.Ascending}, {&quot;Priority&quot;, Order.Descending}, {&quot;StatusOrder&quot;, Order.Descending}, {&quot;State Change Date&quot;, Order.Descending}}),

    GroupPick  = Table.Group(SortedForPick, {&quot;BranchName&quot;}, {{&quot;Pick&quot;, each Table.FirstN(_, 1), type table}}),
    ExpandPick = Table.ExpandTableColumn(GroupPick, &quot;Pick&quot;, {&quot;Status&quot;,&quot;CopyAddedDate&quot;,&quot;State Change Date&quot;}, {&quot;Status&quot;,&quot;Date&quot;,&quot;State Change Date&quot;}),

    // Freeze the left side before merging
    KeptCols = Table.SelectColumns(ExpandPick, {&quot;BranchName&quot;,&quot;Status&quot;,&quot;Date&quot;,&quot;State Change Date&quot;}),
    Buffered = Table.Buffer(KeptCols),

    // Ensure the right side is one row per key
    BranchOne = Table.Distinct(BranchDirectory, {&quot;branch_name&quot;}),

    MergeBranch  = Table.NestedJoin(Buffered, {&quot;BranchName&quot;}, BranchOne, {&quot;branch_name&quot;}, &quot;BranchDirectory&quot;, JoinKind.LeftOuter),
    ExpandBranch = Table.ExpandTableColumn(MergeBranch, &quot;BranchDirectory&quot;, {&quot;branch_id&quot;,&quot;branch_current_status&quot;,&quot;branch_inventory_date&quot;}, {&quot;branch_id&quot;,&quot;branch_current_status&quot;,&quot;branch_inventory_date&quot;}),

    Final = Table.ReorderColumns(ExpandBranch, {&quot;BranchName&quot;,&quot;Status&quot;,&quot;Date&quot;,&quot;State Change Date&quot;,&quot;branch_id&quot;,&quot;branch_current_status&quot;,&quot;branch_inventory_date&quot;})
in
    Final
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Expected outcome&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Picked rows remain the same before and after the merge&lt;/li&gt;
&lt;li&gt;No duplicate rows after expand when the right side is made distinct&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/708637569153156461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/08/power-query-driftless-merges-using.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/708637569153156461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/708637569153156461'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/08/power-query-driftless-merges-using.html' title='Power Query: Driftless Merges using Table.Buffer'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-1714768903689318353</id><published>2025-05-07T18:29:00.003-04:00</published><updated>2025-05-07T18:30:03.129-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="admin center"/><category scheme="http://www.blogger.com/atom/ns#" term="compliance"/><category scheme="http://www.blogger.com/atom/ns#" term="data security"/><category scheme="http://www.blogger.com/atom/ns#" term="dlp policies"/><category scheme="http://www.blogger.com/atom/ns#" term="governance"/><category scheme="http://www.blogger.com/atom/ns#" term="low code"/><category scheme="http://www.blogger.com/atom/ns#" term="microsoft 365"/><category scheme="http://www.blogger.com/atom/ns#" term="power automate"/><category scheme="http://www.blogger.com/atom/ns#" term="power platform"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerApps"/><title type='text'>How to View DLP Policies Applied to a Power Platform Environment</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/08b245a4-c6f0-48e5-a497-d9032fef2feb&quot; alt=&quot;How to View DLP Policies Applied to a Power Platform Environment&quot;&gt;&lt;/p&gt;
&lt;p&gt;To quickly see which Data Loss Prevention (DLP) policies are applied to a specific Power Platform environment, you can use a direct URL. This article shows you how to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find your environment ID&lt;/li&gt;
&lt;li&gt;Use the DLP filter URL&lt;/li&gt;
&lt;li&gt;View results in both the old and new Power Platform Admin Center interfaces&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-1-locate-your-environment-id&quot;&gt;Step 1: Locate Your Environment ID&lt;/h3&gt;
&lt;p&gt;To get your environment ID:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href=&quot;https://admin.powerplatform.microsoft.com&quot;&gt;Power Platform Admin Center&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Environments&lt;/strong&gt; in the left-hand menu.&lt;/li&gt;
&lt;li&gt;Select the environment you want to inspect.&lt;/li&gt;
&lt;li&gt;Under the &lt;strong&gt;Details&lt;/strong&gt; or &lt;strong&gt;Overview&lt;/strong&gt; section, locate the &lt;strong&gt;Environment ID&lt;/strong&gt; (a GUID string).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/1318a95e-7fa4-4ea1-b5a1-5c8feabacb03&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-2-use-the-url-to-view-applied-dlp-policies&quot;&gt;Step 2: Use the URL to View Applied DLP Policies&lt;/h3&gt;
&lt;p&gt;There are two URL formats, depending on which version of the Admin Center you’re using.&lt;/p&gt;
&lt;h4 id=&quot;✅-new-admin-center&quot;&gt;✅ New Admin Center:&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;https://admin.powerplatform.microsoft.com/security/dataprotection/dlp/environmentFilter/{environmentId}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;🕹️-old-admin-center&quot;&gt;🕹️ Old Admin Center:&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;https://admin.powerplatform.microsoft.com/dlp/environmentFilter/{environmentId}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just replace &lt;code&gt;{environmentId}&lt;/code&gt; with the actual ID from Step 1.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://admin.powerplatform.microsoft.com/security/dataprotection/dlp/environmentFilter/f4834a12-5388-4f41-b755-cce6a52d38a0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/ed7086a9-5d03-48bf-9216-0197d1a94b5e&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/b2485972-3f21-4dd7-922f-4475cf5a940b&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;These URLs take you directly to the list of DLP policies scoped to that environment, saving you time from clicking into each policy manually.&lt;/p&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Using this method, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instantly view applied DLP policies per environment&lt;/li&gt;
&lt;li&gt;Bypass manual filtering through policies&lt;/li&gt;
&lt;li&gt;Easily audit security coverage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Pro tip: Save the URL format with a placeholder so you can quickly reuse it for other environments.&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/1714768903689318353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/05/how-to-view-dlp-policies-applied-to.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1714768903689318353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1714768903689318353'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/05/how-to-view-dlp-policies-applied-to.html' title='How to View DLP Policies Applied to a Power Platform Environment'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-1296304360420973103</id><published>2025-04-24T09:11:00.001-04:00</published><updated>2025-04-24T09:11:07.603-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Dynamics"/><category scheme="http://www.blogger.com/atom/ns#" term="Javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="modelapps"/><category scheme="http://www.blogger.com/atom/ns#" term="pcf"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerApps"/><title type='text'>Harnessing Host Form Data with PCF Controls in Model-Driven Applications</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/0308e67d-07e7-401a-b717-f8965d10bf2e&quot; alt=&quot;Harnessing Host Form Data with PCF Controls in Model-Driven Applications&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This tutorial delves into integrating PowerApps Component Framework (PCF) controls with host form data within Microsoft Power Platform’s model-driven apps. This article will guide you through the necessary scripting to expose and consume formContext and globalContext from a custom table called new_Competitor. Aimed at enhancing both custom and Microsoft Form Component PCF controls, this approach ensures dynamic interactions with the host form data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: It’s important to note that there are various methods to retrieve data within PCF controls, including the use of WebAPI. While WebAPI provides a versatile way to access data across different entities and contexts, the approach described in this tutorial focuses on directly integrating with host form data, which can be particularly beneficial in specific use cases where immediate context is crucial. This method allows for real-time data interactions that are essential for certain scenarios, providing a streamlined integration that may not always be achievable through WebAPI alone.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-javascript-on-host-form&quot;&gt;Setting up JavaScript on Host Form&lt;/h2&gt;
&lt;p&gt;To enable a PCF control to access data from its hosting form, JavaScript needs to be implemented on the host form. This will capture and expose crucial context data (&lt;code&gt;formContext&lt;/code&gt; and &lt;code&gt;globalContext&lt;/code&gt;) to the PCF control through global variables.&lt;/p&gt;
&lt;h3 id=&quot;javascript-code-implementation&quot;&gt;JavaScript Code Implementation&lt;/h3&gt;
&lt;p&gt;Here is code you can utilize within a webresource which has been loaded into your host form.  This example loads the &lt;code&gt;formContext&lt;/code&gt; and &lt;code&gt;globalContext&lt;/code&gt; but you can load additional information here as you need.&lt;/p&gt;
&lt;pre class=&quot; language-javascript&quot;&gt;&lt;code class=&quot;prism  language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; NEWCompetitor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NEWCompetitor &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;use strict&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onLoad&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;executionContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; formContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; executionContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFormContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; globalContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Xrm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Utility&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getGlobalContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;copyDataToWindowForPCF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;globalContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; formContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;copyDataToWindowForPCF&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;globalContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; formContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;NEWCompetitorInfo&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;undefined&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NEWCompetitorInfo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; __namespace&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NEWCompetitorInfo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;formContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; formContext&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NEWCompetitorInfo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;globalContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; globalContext&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NEWCompetitor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;deployment-and-configuration&quot;&gt;Deployment and Configuration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Add the Script&lt;/strong&gt;: Include the JavaScript as a web resource linked to the &lt;code&gt;new_Competitor&lt;/code&gt; table form.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modify the OnLoad Event&lt;/strong&gt;: Configure the entity form’s OnLoad event to trigger the &lt;code&gt;onLoad&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;getting-data-from-host-form-in-custom-pcf-control&quot;&gt;Getting Data from Host Form in Custom PCF Control&lt;/h2&gt;
&lt;p&gt;Once the host form data is made available globally, your custom PCF can access that information using &lt;code&gt;window.NEWCompetitorInfo.formContext&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;implementing-the-render-component&quot;&gt;Implementing the Render Component&lt;/h3&gt;
&lt;p&gt;I typically use the renderComponent function in PCF to make sure that the host data is loaded before the overall PCF is loaded, so that I make sure I can access this from everywhere within the PCF.  Within the renderComponent function is also where you might call the render of a React component.&lt;/p&gt;
&lt;pre class=&quot; language-javascript&quot;&gt;&lt;code class=&quot;prism  language-javascript&quot;&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;renderComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; self &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;//@ts-ignore for this._context.mode.contextInfo&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NEWCompetitorInfo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;formContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;			
			&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;		
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;accessing-in-react&quot;&gt;Accessing in React&lt;/h3&gt;
&lt;p&gt;If you are using a React control within your PCF you can declare the namespace for the top-level form within your typescript as an &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot; language-javascript&quot;&gt;&lt;code class=&quot;prism  language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;IInputs&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./generated/ManifestTypes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IProps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    pcfContext&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ComponentFramework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;IInputs&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

declare global &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Window&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        NEWCompetitorInfo&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; any
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;getting-data-from-host-form-in-microsoft-form-component-pcf&quot;&gt;Getting Data from Host Form in Microsoft Form Component PCF&lt;/h2&gt;
&lt;p&gt;If you are using the Form Component to load editable form into a host form you may want to access information and interact with the host form.  The onLoad function running on the host form as shown earlier gets us global variables we can use here as well.  These variables will enable you to call JavaScript on the form inside the component and access information from the hosing form.  More information about the Form Component can be found here &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/model-driven-apps/form-component-control&quot;&gt;Edit related table records directly from another table’s main form&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/7598bf4c-f269-4ba9-9876-313814049551&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;setting-up-javascript-in-the-child-form&quot;&gt;Setting up JavaScript in the Child Form&lt;/h3&gt;
&lt;p&gt;To access the &lt;code&gt;formContext&lt;/code&gt; from the host form, use a webresource and event in the form hosted within the Form Component. This script will reference the global variable provided by the host form’s script.&lt;/p&gt;
&lt;pre class=&quot; language-javascript&quot;&gt;&lt;code class=&quot;prism  language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; NEWCompetitorContact &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NEWCompetitorContact &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;use strict&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onLoad&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;executionContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// Access the formContext from the global variable set by the host form&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NEWCompetitorInfo &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; top&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NEWCompetitorInfo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;formContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; formContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; top&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NEWCompetitorInfo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;formContext&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		    
		    &lt;span class=&quot;token comment&quot;&gt;// Utilize formContext for further operations within the Form Component&lt;/span&gt;
		    &lt;span class=&quot;token comment&quot;&gt;// Example: Accessing data, manipulating form fields, etc.&lt;/span&gt;
		    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; someFieldValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; formContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fieldname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		    &lt;span class=&quot;token comment&quot;&gt;// Additional logic to manipulate or use the form data&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NEWCompetitorContact&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By implementing this method, the Form Component within your model-driven app can dynamically interact with the data from the host form, making it more responsive and capable of handling complex scenarios based on live data inputs.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/1296304360420973103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/04/pcf-access-parent-data-model-app.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1296304360420973103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1296304360420973103'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/04/pcf-access-parent-data-model-app.html' title='Harnessing Host Form Data with PCF Controls in Model-Driven Applications'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-1308544329130057645</id><published>2025-04-14T19:44:00.003-04:00</published><updated>2025-04-20T12:58:54.203-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AutomationTips"/><category scheme="http://www.blogger.com/atom/ns#" term="Bookmarklet"/><category scheme="http://www.blogger.com/atom/ns#" term="DevTools"/><category scheme="http://www.blogger.com/atom/ns#" term="ExpressionInspector"/><category scheme="http://www.blogger.com/atom/ns#" term="FlowExpressions"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScriptSnippet"/><category scheme="http://www.blogger.com/atom/ns#" term="LowCode"/><category scheme="http://www.blogger.com/atom/ns#" term="Makers"/><category scheme="http://www.blogger.com/atom/ns#" term="PA"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerAutomate"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerAutomateV3"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerPlatform"/><category scheme="http://www.blogger.com/atom/ns#" term="v2"/><category scheme="http://www.blogger.com/atom/ns#" term="v3"/><title type='text'>Copy Hidden Power Automate Expressions</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/47b4c591-c27b-4594-b84e-c0b01e1b22b2&quot; alt=&quot;Copy Hidden Power Automate Expressions&quot;&gt;&lt;/p&gt;
&lt;p&gt;While recently walking a colleague through Power Automate, I was reminded of one of my long-standing frustrations: how difficult it is to copy expressions once they’ve been inserted into actions like a &lt;code&gt;Compose&lt;/code&gt;, &lt;code&gt;Filter Array&lt;/code&gt;, or &lt;code&gt;For Each&lt;/code&gt;. For example:&lt;/p&gt;
&lt;pre class=&quot; language-powerautomate&quot;&gt;&lt;code class=&quot;prism  language-powerautomate&quot;&gt;workflow()[&#39;tags&#39;][&#39;environmentName&#39;]
item()?[&#39;logicalName&#39;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once fields are wrapped in certain expressions or are in certain actions, you can no longer open them in the expression popup—you or easily copy them out to reuse elsewhere. That makes it frustrating when you want to replicate logic in another flow or simply document what you’ve written. There is a copy action functionality but that copies the entire action and sometimes you just want a specific expression.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/ecb40951-2545-4c3c-b0e1-a554fbe9bb51&quot; alt=&quot;Power Automate Expression Inspector&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-workaround-until-now&quot;&gt;The Workaround (Until Now)&lt;/h3&gt;
&lt;p&gt;To deal with this, I used to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add expressions to a &lt;strong&gt;comment or note&lt;/strong&gt; in the action so I could reference them later&lt;/li&gt;
&lt;li&gt;Open DevTools and &lt;strong&gt;inspect the DOM&lt;/strong&gt; to grab the full &lt;code&gt;title&lt;/code&gt; attribute that contains the expression&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But neither of these approaches felt elegant. And since I work in the public sector, I can’t use browser extensions like a typical Power Platform developer might.&lt;/p&gt;
&lt;h3 id=&quot;bookmarklets-to-the-rescue&quot;&gt;Bookmarklets to the Rescue&lt;/h3&gt;
&lt;p&gt;This reminded me of the old-school technique of using bookmarklets to extract information from web apps—something I used to do to grab entity IDs in Dynamics CRM. That got me thinking: why not use a bookmarklet or browser snippet to extract expressions in Power Automate?&lt;/p&gt;
&lt;p&gt;So I built exactly that: a JavaScript snippet that works with &lt;strong&gt;both the classic and new editors&lt;/strong&gt; in Power Automate.&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;This tool only works when editing flows directly at &lt;a href=&quot;https://make.powerautomate.com&quot;&gt;https://make.powerautomate.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;It will &lt;strong&gt;not&lt;/strong&gt; work if you’re in &lt;a href=&quot;https://make.powerapps.com&quot;&gt;https://make.powerapps.com&lt;/a&gt;, because flows open in an iframe hosted on a different domain—which introduces cross-origin browser restrictions&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;where-this-is-useful&quot;&gt;Where This Is Useful&lt;/h2&gt;
&lt;p&gt;This tool is great when you’re:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Migrating expressions between flows&lt;/li&gt;
&lt;li&gt;Refactoring actions and need to reference earlier logic&lt;/li&gt;
&lt;li&gt;Working in shared environments and need to document flows&lt;/li&gt;
&lt;li&gt;Reviewing or debugging large flows with embedded expressions&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h2&gt;
&lt;p&gt;The script listens for clicks on expression tokens within the flow designer. Once you click a token, it pops open a dialog with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The full expression&lt;/li&gt;
&lt;li&gt;A “Copy” button&lt;/li&gt;
&lt;li&gt;A “Copy &amp;amp; Close” button&lt;/li&gt;
&lt;li&gt;A “Close” button&lt;/li&gt;
&lt;li&gt;And a “Turn Off” button to disable the click handler when you’re done&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It supports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;v2 (classic editor)&lt;/strong&gt; by inspecting the &lt;code&gt;title&lt;/code&gt; attribute on legacy token spans&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;v3 (new editor)&lt;/strong&gt; by locating the tooltip element associated with the clicked field&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-use-it&quot;&gt;How to Use It&lt;/h2&gt;
&lt;h3 id=&quot;option-1-bookmarklet&quot;&gt;Option 1: Bookmarklet&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create a new bookmark in your browser&lt;/li&gt;
&lt;li&gt;Edit the bookmark URL and paste the following code:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot; language-javascript&quot;&gt;&lt;code class=&quot;prism  language-javascript&quot;&gt;javascript&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; e&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URLSearchParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;v3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;t&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; t&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;expression-dialog&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;t&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; n&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;div&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;expression-dialog&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cssText&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;position: fixed; top: 20%; left: 50%; transform: translateX(-50%); background: white; border: 2px solid #0078d4; padding: 20px; z-index: 99999; box-shadow: 0 4px 12px rgba(0,0,0,0.2); font-family: sans-serif; border-radius: 8px; min-width: 400px;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHTML&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;`&amp;lt;div style=&quot;margin-bottom: 10px; font-weight: bold;&quot;&amp;gt;Power Automate Expression&amp;lt;/div&amp;gt;&amp;lt;input type=&quot;text&quot; id=&quot;expression-input&quot; value=&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/g,&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;quot&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&quot;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; style=&quot;width: 100%; padding: 8px; font-size: 14px;&quot; readonly /&amp;gt;&amp;lt;div style=&quot;margin-top: 10px; text-align: right;&quot;&amp;gt;&amp;lt;button id=&quot;turnoff-btn&quot; style=&quot;margin-right: 10px;&quot;&amp;gt;Turn Off&amp;lt;/button&amp;gt;&amp;lt;button id=&quot;copy-btn&quot; style=&quot;margin-right: 10px;&quot;&amp;gt;Copy&amp;lt;/button&amp;gt;&amp;lt;button id=&quot;close-btn&quot; style=&quot;margin-right: 10px;&quot;&amp;gt;Close&amp;lt;/button&amp;gt;&amp;lt;button id=&quot;copy-close-btn&quot;&amp;gt;Copy &amp;amp; Close&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; o&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;expression-input&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;copy-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onclick&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clipboard&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; e&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;copy-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Copied!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Copy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;copy-close-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onclick&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clipboard&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;close-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onclick&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;turnoff-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onclick&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;t&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Expression click handler turned off.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;SPAN&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tagName&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stopPropagation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parentElement&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parentElement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;msla-token&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;(no title found)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DIV&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tagName&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;span[data-automation-id^=&quot;flow-token&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-labelledby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-describedby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;span&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stopPropagation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;t&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Click on any token in the new editor (v3) to extract the expression. You can keep clicking.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Click on any expression token (v2) to extract the expression. You can keep clicking.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Navigate to &lt;a href=&quot;https://make.powerautomate.com&quot;&gt;https://make.powerautomate.com&lt;/a&gt;, open your flow, and click the bookmark&lt;/li&gt;
&lt;li&gt;Then click on any tokenized expression to extract it!&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;option-2-devtools-snippet&quot;&gt;Option 2: DevTools Snippet&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open your flow in Power Automate (must be at &lt;code&gt;make.powerautomate.com&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;F12&lt;/code&gt; to open Developer Tools&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;“Sources”&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Choose the &lt;strong&gt;“Snippets”&lt;/strong&gt; pane and click &lt;strong&gt;&quot;New snippet&quot;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Paste in the full script&lt;/li&gt;
&lt;li&gt;Right-click the snippet and choose &lt;strong&gt;&quot;Run&quot;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here is the full code:&lt;/p&gt;
&lt;pre class=&quot; language-javascript&quot;&gt;&lt;code class=&quot;prism  language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Combined widget for both v2 and v3 Power Automate editors&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; urlParams &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URLSearchParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; v3Param &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; urlParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;v3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isV3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; v3Param &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; v3Param &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleClickV2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tagName &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SPAN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; token &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parentElement&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parentElement&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;token &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;msla-token&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stopPropagation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; expression &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; token&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;(no title found)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;showDialog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleClickV3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tagName &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;DIV&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; token &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;span[data-automation-id^=&quot;flow-token&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; describedById &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-labelledby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-describedby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;describedById&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tooltipEl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;describedById&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; expression &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tooltipEl&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;span&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stopPropagation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;showDialog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;showDialog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;expression-dialog&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; existing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dialog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;div&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;expression-dialog&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cssText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;`
      position: fixed;
      top: 20%;
      left: 50%;
      transform: translateX(-50%);
      background: white;
      border: 2px solid #0078d4;
      padding: 20px;
      z-index: 99999;
      box-shadow: 0 4px 12px rgba(0,0,0,0.2);
      font-family: sans-serif;
      border-radius: 8px;
      min-width: 400px;
    `&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHTML &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;`
      &amp;lt;div style=&quot;margin-bottom: 10px; font-weight: bold;&quot;&amp;gt;Power Automate Expression&amp;lt;/div&amp;gt;
      &amp;lt;input type=&quot;text&quot; id=&quot;expression-input&quot; value=&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;/&quot;/g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;amp;quot;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; style=&quot;width: 100%; padding: 8px; font-size: 14px;&quot; readonly /&amp;gt;
      &amp;lt;div style=&quot;margin-top: 10px; text-align: right;&quot;&amp;gt;
        &amp;lt;button id=&quot;turnoff-btn&quot; style=&quot;margin-right: 10px;&quot;&amp;gt;Turn Off&amp;lt;/button&amp;gt;
        &amp;lt;button id=&quot;copy-btn&quot; style=&quot;margin-right: 10px;&quot;&amp;gt;Copy&amp;lt;/button&amp;gt;
        &amp;lt;button id=&quot;close-btn&quot; style=&quot;margin-right: 10px;&quot;&amp;gt;Close&amp;lt;/button&amp;gt;
        &amp;lt;button id=&quot;copy-close-btn&quot;&amp;gt;Copy &amp;amp; Close&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    `&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dialog&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;expression-input&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;copy-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onclick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clipboard&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; btn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;copy-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        btn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Copied!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; btn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Copy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;copy-close-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onclick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clipboard&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;close-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onclick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;turnoff-btn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onclick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isV3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleClickV3&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleClickV2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Expression click handler turned off.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isV3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Click on any token in the new editor (v3) to extract the expression. You can keep clicking.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleClickV3&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Click on any expression token (v2) to extract the expression. You can keep clicking.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleClickV2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once active, simply click any expression token in the designer to see the popup.&lt;/p&gt;
&lt;hr&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/1308544329130057645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/04/copy-hidden-power-automate-expressions.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1308544329130057645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1308544329130057645'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/04/copy-hidden-power-automate-expressions.html' title='Copy Hidden Power Automate Expressions'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-218629141166476484</id><published>2025-04-13T11:25:00.002-04:00</published><updated>2025-04-13T11:25:30.886-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ADF"/><category scheme="http://www.blogger.com/atom/ns#" term="Azure Data Factory"/><category scheme="http://www.blogger.com/atom/ns#" term="CC"/><category scheme="http://www.blogger.com/atom/ns#" term="Custom Connectors"/><category scheme="http://www.blogger.com/atom/ns#" term="Data Flows"/><category scheme="http://www.blogger.com/atom/ns#" term="dataverse"/><category scheme="http://www.blogger.com/atom/ns#" term="FetchXML"/><category scheme="http://www.blogger.com/atom/ns#" term="Linked Services"/><category scheme="http://www.blogger.com/atom/ns#" term="LS"/><category scheme="http://www.blogger.com/atom/ns#" term="Managed Identity"/><category scheme="http://www.blogger.com/atom/ns#" term="MI"/><category scheme="http://www.blogger.com/atom/ns#" term="OData"/><category scheme="http://www.blogger.com/atom/ns#" term="power platform"/><category scheme="http://www.blogger.com/atom/ns#" term="PP"/><category scheme="http://www.blogger.com/atom/ns#" term="REST API"/><category scheme="http://www.blogger.com/atom/ns#" term="S2S Authentication"/><title type='text'>Connecting to Dataverse from Azure Data Factory</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/d5f7a240-e1a7-472c-af1f-d62cde8fff8c&quot; alt=&quot;Connecting to Dataverse from Azure Data Factory&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Azure Data Factory (ADF) provides versatile ways to connect and interact with Dataverse. Understanding the connection options and configurations is crucial for securely and efficiently managing your data integration tasks. This guide walks through the primary methods for connecting Azure Data Factory to Dataverse, covering their benefits, best practices, and detailed walkthroughs to get you started. provides versatile ways to connect and interact with Dataverse. Understanding the connection options and configurations is crucial for securely and efficiently managing your data integration tasks. This guide walks through the primary methods for connecting Azure Data Factory to Dataverse, covering their benefits, best practices, and detailed walkthroughs to get you started.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Disclaimer: These thoughts are my own and based on my personal experience. If you have different ideas or approaches, I’d love to hear them—I’m always eager to learn more from others in the community.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;connection-types&quot;&gt;Connection Types&lt;/h2&gt;
&lt;p&gt;There are three main ways to connect Azure Data Factory to Dataverse: the REST API, the built-in Dataverse connector, and the OData connector. Each method offers unique advantages depending on your use case. Personally, I prefer using the REST API because it offers the greatest amount of flexibility. While it may require some additional configuration—like setting pagination rules or custom headers—it enables capabilities that are simply not possible with the Dataverse connector, such as returning additional metadata, bypassing plugins, or impersonating users.&lt;/p&gt;
&lt;h3 id=&quot;rest-api&quot;&gt;REST API&lt;/h3&gt;
&lt;p&gt;Connecting via the Dataverse REST API gives you detailed control over the data retrieval process, including the ability to return formatted values and metadata for lookups. More on Microsoft Learn:&amp;nbsp;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/data-factory/connector-rest?tabs=data-factory&quot;&gt;https://learn.microsoft.com/en-us/azure/data-factory/connector-rest?tabs=data-factory&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ability to invoke custom actions or functions on records, enabling powerful server-side operations within the same integration flow.&lt;/li&gt;
&lt;li&gt;Richer data retrieval with annotations.&amp;nbsp;&lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/compose-http-requests-handle-errors#request-annotations&quot;&gt;Request Annotations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Complete control over data requests.&lt;/li&gt;
&lt;li&gt;Returns all fields, including those with null values if you use specify those fields in the $select, this can be helpful when building projections if not all of your records contains data.&lt;/li&gt;
&lt;li&gt;Allows setting custom headers such as CallerObjectId for impersonating users (with appropriate permissions) and MSCRM.BypassCustomPluginExecution	 to bypass plugins. More info: &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/compose-http-requests-handle-errors#other-headers&quot;&gt;Other Headers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Supports FetchXML queries in addition to OData for advanced querying scenarios.&lt;/li&gt;
&lt;li&gt;FetchXML Builder in XrmToolBox can be used to craft FetchXML queries and even convert them into OData format.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Considerations:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generating the request body for POST or PATCH operations (such as updates) can be more cumbersome and error-prone compared to the built-in Dataverse connector.&lt;/li&gt;
&lt;li&gt;Requires handling JSON transformations.&lt;/li&gt;
&lt;li&gt;You must configure pagination rules to retrieve more than 5,000 records (to be discussed in a future article).&lt;/li&gt;
&lt;li&gt;Ideal for complex scenarios where pipeline lookups fall short.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;dataverse-connector&quot;&gt;Dataverse Connector&lt;/h3&gt;
&lt;p&gt;The built-in Dataverse connector simplifies connectivity and basic data operations with minimal configuration. More on Microsoft Learn:&amp;nbsp;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/data-factory/connector-dynamics-crm-office-365?tabs=data-factory&quot;&gt;https://learn.microsoft.com/en-us/azure/data-factory/connector-dynamics-crm-office-365?tabs=data-factory&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Easy setup with minimal configuration.&lt;/li&gt;
&lt;li&gt;Convenient for simple scenarios and basic CRUD operations.&lt;/li&gt;
&lt;li&gt;When used in Data Flows, it automatically handles pagination and retrieves more than 5,000 records without additional configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Considerations:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Limited control over annotations and formatted data.&lt;/li&gt;
&lt;li&gt;Fields with null values are not returned, making it difficult to detect missing data in pipeline activities.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;odata&quot;&gt;OData&lt;/h3&gt;
&lt;p&gt;OData offers a standardized protocol for interacting with Dataverse, beneficial for interoperability and standardized queries. More on Microsoft Learn:&amp;nbsp;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/data-factory/connector-odata&quot;&gt;https://learn.microsoft.com/en-us/azure/data-factory/connector-odata&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standardized query syntax since it is using the REST API.&lt;/li&gt;
&lt;li&gt;Interoperable with multiple tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Considerations:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Limited functionality compared to the REST API.&lt;/li&gt;
&lt;li&gt;Does not support Managed Identity authentication, limiting secure integration options.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;security-considerations&quot;&gt;Security Considerations&lt;/h2&gt;
&lt;p&gt;Each of the connector types discussed above supports different authentication methods. The Dataverse connector and OData connector primarily rely on Azure Active Directory-based service principal authentication. The REST API offers greater flexibility by supporting both service principal and Managed Identity configurations, and it allows you to include custom headers for additional control.&lt;/p&gt;
&lt;p&gt;In this article, I focus on using &lt;strong&gt;Managed Identity&lt;/strong&gt;, as it is my preferred method for securing connections. Managed Identity provides credential-free authentication, reduces the risk of secrets exposure, and integrates cleanly with Azure resources. The REST API allows you to use either a System-assigned or a User-assigned Managed Identity, giving flexibility based on your identity management preferences. The Dataverse connector, on the other hand, only supports User-assigned Managed Identities. I typically choose User-assigned identities regardless, as they provide clearer control and traceability across enterprise environments. This article will focus on how to configure and assign a User-assigned identity for this integration. as it is my preferred method for securing connections.&lt;/p&gt;
&lt;h3 id=&quot;managed-identities&quot;&gt;Managed Identities&lt;/h3&gt;
&lt;p&gt;Managed identities offer secure, credential-free access to Dataverse from ADF.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User-assigned Managed Identity:&lt;/strong&gt; Preferred due to clear management and reusability.&lt;/li&gt;
&lt;li&gt;Ensure appropriate Dataverse security roles are assigned directly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Walkthrough: Creating and Assigning a Managed Identity&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the Azure Portal, create a new &lt;strong&gt;User-assigned Managed Identity&lt;/strong&gt;.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/942a3dd3-e14c-4d86-9bae-d3a7e5e1f869&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigate to your Azure Data Factory resource.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;strong&gt;Settings&lt;/strong&gt;, select &lt;strong&gt;Managed identities&lt;/strong&gt; and then click &lt;strong&gt;+ Add user-assigned managed identity&lt;/strong&gt;.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/48532949-acd7-4552-b4a7-8898c13808d4&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the newly created identity and add it to your ADF instance.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/45978f65-2825-4156-87ee-96e43fcb5844&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to Azure Active Directory and assign the identity to your Dataverse environment if needed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Power Platform admin center, assign the identity a security role (e.g., System Administrator or a custom role with required privileges).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;security-roles-in-dataverse&quot;&gt;Security Roles in Dataverse&lt;/h3&gt;
&lt;p&gt;Assigning security roles in Dataverse is essential to ensure that your ADF-managed identities can access and perform the operations they require.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Walkthrough: Assigning a Security Role to a Managed Identity&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go to the &lt;strong&gt;Power Platform Admin Center&lt;/strong&gt; and open the &lt;strong&gt;Environments&lt;/strong&gt; section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on the environment you want to assign access to.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the &lt;strong&gt;S2S Apps&lt;/strong&gt; tab to manage Server-to-Server (S2S) app users.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/ed95b971-409f-49f2-9890-05ec68b85210&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;+ Add an app user&lt;/strong&gt; to begin adding your Managed Identity.&lt;br&gt;
&lt;strong&gt;Important:&lt;/strong&gt; When searching for your Managed Identity, search by &lt;strong&gt;Object ID&lt;/strong&gt;, not the display name, as it may not appear otherwise.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/b5023dca-4f60-49c1-b6d2-cfd5562e1274&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select a &lt;strong&gt;Business Unit&lt;/strong&gt; if prompted.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/7f7c4f1b-d664-4605-b8ac-73e55fbd6509&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose a &lt;strong&gt;Security Role&lt;/strong&gt; to grant the necessary permissions.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/bdfb2220-8a0e-457b-8cbb-cc932c80f210&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Although the screenshot example shows assigning the &lt;strong&gt;System Administrator&lt;/strong&gt; role, I typically recommend creating a tailored security role that grants only the permissions needed for your ADF activities. This promotes better security hygiene and minimizes risk.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure roles precisely to maintain a strong security posture.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;using-the-credentials-in-azure-data-factory&quot;&gt;Using the Credentials in Azure Data Factory&lt;/h3&gt;
&lt;p&gt;Once your User-assigned Managed Identity has been created and assigned the proper security role in Dataverse, the next step is to use it within Azure Data Factory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Walkthrough: Connecting with Managed Identity in ADF&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In Azure Data Factory, go to &lt;strong&gt;Manage &amp;gt; Linked services&lt;/strong&gt; and click &lt;strong&gt;+ New&lt;/strong&gt; to create a new connection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select your connector type (e.g., REST or Dataverse) and begin configuring the connection.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/dc72da9a-68a9-4b1a-ab3d-a5fa19e35294&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When prompted for authentication, choose &lt;strong&gt;Managed Identity&lt;/strong&gt; and click &lt;strong&gt;+ New&lt;/strong&gt; to create a credential.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/074e354b-12bd-4471-af49-9cd4081ac949&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select &lt;strong&gt;User-assigned managed identity&lt;/strong&gt; from the dropdown and pick the identity previously created and assigned roles.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/815e7076-dd6d-43b1-a474-b85371fe7c35&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With these steps, your ADF pipelines and data flows will be able to securely access Dataverse using the configured Managed Identity.&lt;/p&gt;
&lt;h2 id=&quot;best-practices&quot;&gt;Best Practices&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Choose REST API for detailed, annotation-rich data access and complex transformations, especially when you need access to all fields including nulls.&lt;/li&gt;
&lt;li&gt;Opt for Dataverse Connector for straightforward data integration scenarios and automatic pagination in Data Flows.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Selecting the right connection method and properly configuring security ensures efficient, secure, and robust data integrations between Azure Data Factory and Dataverse.&lt;/p&gt;
&lt;p&gt;This article includes detailed walkthroughs to guide you through setting up your Managed Identity and assigning security roles in Dataverse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Next Steps:&lt;/strong&gt;&lt;br&gt;
Stay tuned for hands-on examples and step-by-step configurations for each connection method.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Have questions or insights?&lt;/strong&gt; Drop your comments below and let’s discuss!&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/218629141166476484/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/04/connecting-to-dataverse-from-azure-data.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/218629141166476484'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/218629141166476484'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/04/connecting-to-dataverse-from-azure-data.html' title='Connecting to Dataverse from Azure Data Factory'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-5938799802444169466</id><published>2025-04-12T20:39:00.001-04:00</published><updated>2025-04-12T20:39:00.228-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="3d"/><category scheme="http://www.blogger.com/atom/ns#" term="3dprint"/><category scheme="http://www.blogger.com/atom/ns#" term="design"/><category scheme="http://www.blogger.com/atom/ns#" term="fun"/><category scheme="http://www.blogger.com/atom/ns#" term="hobby"/><category scheme="http://www.blogger.com/atom/ns#" term="printing"/><title type='text'>Fixing Temperature Fluctuations on the Creality CR-6 SE with PID Tuning</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/36673b49-f9c1-4c39-ba22-48c52303544d&quot; alt=&quot;Fixing Temperature Fluctuations on the Creality CR-6 SE with PID Tuning&quot;&gt;&lt;/p&gt;
&lt;p&gt;After installing a new hotend on my &lt;strong&gt;Creality CR-6 SE&lt;/strong&gt;, I ran into a frustrating issue: when printing above 210°C, the hotend temperature would swing wildly—fluctuating by 5–10°C. The printer wouldn’t even start the print due to this instability.&lt;/p&gt;
&lt;h2 id=&quot;🧠-the-fix-pid-tuning-thanks-to-community-firmware&quot;&gt;🧠 The Fix: PID Tuning (Thanks to Community Firmware)&lt;/h2&gt;
&lt;p&gt;This issue led me to discover &lt;strong&gt;PID tuning&lt;/strong&gt;, a way to calibrate how the printer regulates temperature using smarter controls. Out of the box, Creality’s firmware doesn’t always support this—but I’m running the excellent &lt;strong&gt;&lt;a href=&quot;https://github.com/CR6Community/Marlin&quot;&gt;CR-6 SE Community Firmware&lt;/a&gt;&lt;/strong&gt; based on Marlin, which includes &lt;strong&gt;PID autotuning support&lt;/strong&gt; via G-code commands.&lt;/p&gt;
&lt;h2 id=&quot;🔧-how-to-tune-the-hotend-using-octoprint&quot;&gt;🔧 How to Tune the Hotend Using OctoPrint&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open the &lt;strong&gt;Terminal tab&lt;/strong&gt; in OctoPrint.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/33200617-3dae-4a85-a20d-776f5d7e93d3&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Turn on the cooling fan&lt;/strong&gt; before tuning for accuracy, if you typically run the fan during your prints:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;M106 S255
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run PID autotune at a typical print temp (I used &lt;strong&gt;215°C&lt;/strong&gt; with 10 cycles):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;M303 E0 S215 C10
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After sending the &lt;code&gt;M303&lt;/code&gt; command, you’ll see a series of output logs in the terminal as the firmware performs multiple test cycles. Each cycle includes temperature data and candidate PID values.&lt;/p&gt;
&lt;p&gt;Look for a section similar to this near the end of the output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Recv:  bias: 137 d: 117 min: 208.7500 max: 222.1429 Ku: 22.2460 Tu: 30.7830
Recv:  Classic PID
Recv:  Kp: 13.3476 Ki: 0.8672 Kd: 51.3600
Recv: PID Autotune finished! Put the last Kp, Ki and Kd constants from below into Configuration.h
Recv: #define DEFAULT_Kp 13.3476
Recv: #define DEFAULT_Ki 0.8672
Recv: #define DEFAULT_Kd 51.3600
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;Important:&lt;/strong&gt; Use the &lt;strong&gt;last set of &lt;strong&gt;&lt;strong&gt;&lt;code&gt;Kp&lt;/code&gt;&lt;/strong&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;strong&gt;&lt;code&gt;Ki&lt;/code&gt;&lt;/strong&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;strong&gt;&lt;code&gt;Kd&lt;/code&gt;&lt;/strong&gt;&lt;/strong&gt; values&lt;/strong&gt; from the output. These are the optimized values to set in the next step.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Apply and save the values using:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;M301 P13.3476 I0.8672 D51.3600
M500
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This sets and saves the new hotend PID values to your printer’s EEPROM.&lt;/p&gt;
&lt;h3 id=&quot;🔥-want-to-tune-your-heated-bed-too&quot;&gt;🔥 Want to Tune Your Heated Bed Too?&lt;/h3&gt;
&lt;p&gt;You can tune your heated bed the same way, just use &lt;code&gt;E-1&lt;/code&gt; instead of &lt;code&gt;E0&lt;/code&gt;. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;M303 E-1 S60 C10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then apply the values with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;M304 P30.93 I2.13 D299.02
M500
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;✅-final-thoughts&quot;&gt;✅ Final Thoughts&lt;/h2&gt;
&lt;p&gt;Switching to the &lt;a href=&quot;https://github.com/CR6Community/Marlin&quot;&gt;CR-6 SE Community Firmware&lt;/a&gt; opened the door to making this kind of fine-tuning possible. After running PID tuning, my hotend holds temperature within ±1°C, prints kick off right away, and layer consistency has improved.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🔁 Don’t forget: jot down your &lt;strong&gt;original PID values&lt;/strong&gt; in case you need to roll back.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you’re using a CR-6 SE and have upgraded your hotend—or just want tighter temperature control—I highly recommend giving PID tuning a try.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/5938799802444169466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/04/fixing-temperature-fluctuations-on.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/5938799802444169466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/5938799802444169466'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/04/fixing-temperature-fluctuations-on.html' title='Fixing Temperature Fluctuations on the Creality CR-6 SE with PID Tuning'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-7061919095159216532</id><published>2025-03-18T17:32:00.001-04:00</published><updated>2025-03-18T17:32:17.837-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="automation"/><category scheme="http://www.blogger.com/atom/ns#" term="azure"/><category scheme="http://www.blogger.com/atom/ns#" term="ip"/><category scheme="http://www.blogger.com/atom/ns#" term="iprestrictions"/><category scheme="http://www.blogger.com/atom/ns#" term="power automate"/><category scheme="http://www.blogger.com/atom/ns#" term="Security"/><category scheme="http://www.blogger.com/atom/ns#" term="storage account"/><title type='text'>Automating Azure Storage Account IP Restrictions with Power Automate</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/f600f3a3-0796-4ccb-8a18-298ff158eb2d&quot; alt=&quot;Automating Azure Storage Account IP Restrictions with Power Automate&quot;&gt;&lt;/p&gt;
&lt;p&gt;When managing Azure Storage Accounts, it’s essential to control access by restricting allowed IP addresses. Manually updating these restrictions can be cumbersome, especially when dealing with frequently changing IP ranges. To address this challenge, I developed a Power Automate custom connector that automates fetching and processing Azure IP ranges using Microsoft’s &lt;strong&gt;Azure IP Ranges and Service Tags&lt;/strong&gt; JSON files.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.microsoft.com/en-us/download/details.aspx?id=56519&quot;&gt;Azure IP Ranges and Service Tags – Public Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.microsoft.com/en-us/download/details.aspx?id=57063&quot;&gt;Azure IP Ranges and Service Tags – US Government Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.microsoft.com/en-us/download/details.aspx?id=57062&quot;&gt;Azure IP Ranges and Service Tags – China Cloud&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While my initial use case focused on automating Azure IP Ranges and Service Tags, this solution can also be adapted to work with &lt;strong&gt;custom lists of IP addresses&lt;/strong&gt;. Many of the actions in this connector, such as reducing CIDR blocks and generating IP rules, can be applied to any list of IP addresses. This allows users to integrate their own IP management workflows and leverage the &lt;strong&gt;Azure Management API&lt;/strong&gt; to dynamically update firewall rules.&lt;/p&gt;
&lt;p&gt;I collaborated with &lt;a href=&quot;https://www.linkedin.com/in/chinchris/&quot;&gt;Chris Chin&lt;/a&gt; to refine this idea, ultimately simplifying the process of updating storage account firewall rules dynamically.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge&quot;&gt;The Challenge&lt;/h2&gt;
&lt;p&gt;I needed to update an &lt;strong&gt;Azure Storage Container’s&lt;/strong&gt; IP restrictions to allow specific Azure service IPs. The IP addresses I required were within Microsoft’s downloadable JSON file for Azure IP Ranges and Service Tags (&lt;a href=&quot;https://www.microsoft.com/en-us/download/details.aspx?id=56519&quot;&gt;available here&lt;/a&gt;). The problem?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The file name changes monthly, making it impossible to use a static link.&lt;/li&gt;
&lt;li&gt;The storage account IP restriction rules have a maximum CIDR prefix of &lt;strong&gt;/30&lt;/strong&gt;, requiring filtering.&lt;/li&gt;
&lt;li&gt;The JSON file includes overlapping CIDR ranges, which needed optimization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Storage Accounts only support 400 IP rules&lt;/strong&gt; (&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/storage/common/storage-network-security?tabs=azure-portal#grant-access-from-an-internet-ip-range&quot;&gt;limit reference&lt;/a&gt;), so it’s necessary to check for and eliminate overlapping CIDRs to reduce the number of rules.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-solution-a-power-automate-custom-connector&quot;&gt;The Solution: A Power Automate Custom Connector&lt;/h2&gt;
&lt;p&gt;To automate this process, I created a &lt;strong&gt;Power Automate custom connector&lt;/strong&gt; that performs the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fetches the latest download link&lt;/strong&gt; from the Microsoft website by scraping the URL dynamically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downloads the JSON file&lt;/strong&gt; and extracts the IP ranges associated with specified service tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filters CIDR blocks&lt;/strong&gt; to ensure no prefixes larger than &lt;code&gt;/30&lt;/code&gt; are included.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduces redundant CIDR ranges&lt;/strong&gt;, keeping only the most efficient set.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generates an array of IP Rules&lt;/strong&gt; formatted for use in Azure Management API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Updates the Azure Storage Account’s firewall rules&lt;/strong&gt; using an HTTP PATCH request.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h2&gt;
&lt;p&gt;The Power Automate flow consists of the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Retrieve the latest download URL&lt;/strong&gt; using the &lt;code&gt;GetDirectDownloadUrl&lt;/code&gt; action.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/322d96f9-8b60-45f1-bbd2-1de204c9f4a5&quot; alt=&quot;image&quot;&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extract service tags and IP addresses&lt;/strong&gt; using the &lt;code&gt;GetIPAddressesByServiceTag&lt;/code&gt; action.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/ee5268dd-4833-4392-9114-88501baddf8c&quot; alt=&quot;image&quot;&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filter CIDR ranges&lt;/strong&gt; using &lt;code&gt;CIDRReducer&lt;/code&gt;, ensuring only &lt;code&gt;/30&lt;/code&gt; or smaller prefixes are included.&amp;nbsp; This action also included an output for Reduced Count, so you can check to make sure your IP addresses are less than 400 at this point.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/284cd25c-aeaa-4d91-ae1e-f4b1df59de47&quot; alt=&quot;image&quot;&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate IP rules&lt;/strong&gt; using &lt;code&gt;GenerateIPRules&lt;/code&gt;, formatting them for Azure Storage firewall.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/233f5236-fa9a-4023-98ad-a6363df7d665&quot; alt=&quot;image&quot;&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compose the request body&lt;/strong&gt; for the Azure Management API with &lt;code&gt;defaultAction&lt;/code&gt; set to &lt;code&gt;Deny&lt;/code&gt; and &lt;code&gt;ipRules&lt;/code&gt; containing the allowed list.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/d02a764a-2a64-4c40-87b4-52f25fe4f26f&quot; alt=&quot;image&quot;&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Call the Azure Management API&lt;/strong&gt; via an HTTP PATCH request to update the storage account settings.&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/9d96ff8f-c52b-419a-8641-075b588e4b62&quot; alt=&quot;image&quot;&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Overall flow diagram generated using &lt;a href=&quot;https://github.com/modery/PowerDocu&quot;&gt;PowerDocu&lt;/a&gt;&lt;br&gt;
&lt;img src=&quot;https://github.com/user-attachments/assets/4ecf05a0-740e-455d-a0b8-5d75b508d22d&quot; alt=&quot;flow-detailed&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;api-call-example&quot;&gt;API Call Example&lt;/h3&gt;
&lt;p&gt;To update the &lt;strong&gt;storage account firewall&lt;/strong&gt;, I used the following API request:&lt;/p&gt;
&lt;pre class=&quot; language-http&quot;&gt;&lt;code class=&quot;prism  language-http&quot;&gt;PATCH https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}?api-version=2024-01-01
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For &lt;strong&gt;GCC or GCCH&lt;/strong&gt;, use:&lt;/p&gt;
&lt;pre class=&quot; language-http&quot;&gt;&lt;code class=&quot;prism  language-http&quot;&gt;PATCH https://management.usgovcloudapi.net/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}?api-version=2024-01-01
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The authentication method used was &lt;strong&gt;App Registration&lt;/strong&gt;, with the &lt;code&gt;Storage Account Contributor&lt;/code&gt; role assigned.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before using this solution, you’ll need to set up an &lt;strong&gt;App Registration&lt;/strong&gt; in Entra ID and assign it the necessary permissions on the Azure Storage Account.&lt;/p&gt;
&lt;h3 id=&quot;create-an-app-registration&quot;&gt;1. Create an App Registration&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Entra Id&lt;/strong&gt; in the Azure Portal.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;App registrations&lt;/strong&gt; &amp;gt; &lt;strong&gt;New registration&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter a name and select the appropriate supported account types.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Register&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;generate-client-credentials&quot;&gt;2. Generate Client Credentials&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;In the App Registration, navigate to &lt;strong&gt;Certificates &amp;amp; secrets&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New client secret&lt;/strong&gt;, enter a description, and set an expiration date.&lt;/li&gt;
&lt;li&gt;Copy the generated secret value (it won’t be shown again).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;assign-role-to-the-storage-account&quot;&gt;3. Assign Role to the Storage Account&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to your &lt;strong&gt;Azure Storage Account&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Access Control (IAM)&lt;/strong&gt; &amp;gt; &lt;strong&gt;Role assignments&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add role assignment&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Storage Account Contributor&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Assign the role to your App Registration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once set up, this App Registration will authenticate API calls to update storage firewall rules.&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-connector-in-power-platform&quot;&gt;Deploying the Connector in Power Platform&lt;/h2&gt;
&lt;p&gt;You can install this solution by downloading and importing the provided &lt;strong&gt;solution file&lt;/strong&gt; or by manually using the &lt;strong&gt;PACONN&lt;/strong&gt; or &lt;strong&gt;PAC CLI&lt;/strong&gt; tools.&lt;/p&gt;
&lt;h3 id=&quot;install-using-solution-file&quot;&gt;1. Install Using Solution File&lt;/h3&gt;
&lt;p&gt;You can directly download and import the Power Platform solution file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Download Solution File:&lt;/strong&gt; &lt;a href=&quot;https://github.com/rwilson504/PowerAutomateConnectors/raw/refs/heads/main/Azure%20IP%20And%20Service%20Tags/AzureIPAddressesCustomConnector_1_0_0_1.zip&quot;&gt;AzureIPAddressesCustomConnector_1_0_0_1.zip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Import into Power Automate:&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Power Apps&lt;/strong&gt; &amp;gt; &lt;strong&gt;Solutions&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Import Solution&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Upload the downloaded &lt;code&gt;.zip&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Follow the prompts to complete the import.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;manually-import-using-paconn&quot;&gt;2. Manually Import Using PACONN&lt;/h3&gt;
&lt;p&gt;If you prefer using the &lt;strong&gt;PACONN CLI&lt;/strong&gt; tool, follow these steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install the &lt;strong&gt;Power Platform CLI&lt;/strong&gt; (&lt;code&gt;paconn&lt;/code&gt;) following &lt;a href=&quot;https://learn.microsoft.com/en-us/connectors/custom-connectors/paconn-cli#create-a-new-custom-connector&quot;&gt;this guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use the following command to import the connector:&lt;pre class=&quot; language-sh&quot;&gt;&lt;code class=&quot;prism  language-sh&quot;&gt;paconn create --api-definition apiDefinition.swagger.json --icon icon.png --script script.c
&lt;/code&gt;&lt;/pre&gt;
This connector includes a &lt;strong&gt;code file&lt;/strong&gt;, so you must use the &lt;code&gt;--script&lt;/code&gt; option.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;manually-import-using-pac-cli&quot;&gt;3. Manually Import Using PAC CLI&lt;/h3&gt;
&lt;p&gt;Alternatively, you can use the &lt;strong&gt;Power Platform CLI (PAC CLI)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install the &lt;strong&gt;PAC CLI&lt;/strong&gt; following &lt;a href=&quot;https://learn.microsoft.com/en-us/power-platform/developer/cli/reference/connector#pac-connector-create&quot;&gt;this guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use the following command:&lt;pre class=&quot; language-sh&quot;&gt;&lt;code class=&quot;prism  language-sh&quot;&gt;pac connector create --api-definition apiDefinition.swagger.json --script-file script.c
&lt;/code&gt;&lt;/pre&gt;
The &lt;code&gt;--script-file&lt;/code&gt; option is required since this connector includes a custom script.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 &lt;a href=&quot;https://github.com/rwilson504/PowerAutomateConnectors/tree/main/Azure%20IP%20And%20Service%20Tags&quot;&gt;GitHub Repository&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By leveraging Power Automate and a custom connector, I eliminated the need for manual updates to Azure Storage firewall rules. This solution dynamically fetches the latest IP ranges, optimizes CIDR blocks, and seamlessly updates the storage account via API—all without requiring user intervention.&lt;/p&gt;
&lt;p&gt;Big thanks to &lt;a href=&quot;https://www.linkedin.com/in/chinchris/&quot;&gt;Chris Chin&lt;/a&gt; for helping refine this approach!&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/7061919095159216532/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/03/automating-azure-storage-account-ip.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/7061919095159216532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/7061919095159216532'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/03/automating-azure-storage-account-ip.html' title='Automating Azure Storage Account IP Restrictions with Power Automate'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-1692805850685575522</id><published>2025-02-24T19:29:00.004-05:00</published><updated>2025-02-24T19:29:31.699-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="api"/><category scheme="http://www.blogger.com/atom/ns#" term="Connectors"/><category scheme="http://www.blogger.com/atom/ns#" term="CustomConnector"/><category scheme="http://www.blogger.com/atom/ns#" term="fbi"/><category scheme="http://www.blogger.com/atom/ns#" term="government"/><category scheme="http://www.blogger.com/atom/ns#" term="indepdentconnector"/><category scheme="http://www.blogger.com/atom/ns#" term="power automate"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerPlatform"/><category scheme="http://www.blogger.com/atom/ns#" term="top10"/><title type='text'>FBI Top Ten Power Platform Connector</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/cfe0d57b-f2c7-4f86-9224-4f127c35aaea&quot; alt=&quot;Powering Justice: Unveil the FBI Most Wanted with the Power Platform Custom Connector&quot;&gt;&lt;/p&gt;
&lt;p&gt;Today’s digital landscape offers unprecedented opportunities to leverage technology in the service of public safety. The FBI’s open API, a comprehensive source of data on the nation’s most wanted individuals and significant art crimes, now seamlessly integrates into the Power Platform thanks to the FBI Most Wanted Custom Connector. This innovation enables low-code developers across federal agencies to quickly and easily repurpose critical law enforcement data for the greater good.&lt;/p&gt;
&lt;h3 id=&quot;inspiration-behind-the-connector&quot;&gt;Inspiration Behind the Connector&lt;/h3&gt;
&lt;p&gt;The inception of the FBI Most Wanted Custom Connector was driven by the untapped potential within the FBI’s publicly available data. Recognizing the wealth of information housed on the &lt;a href=&quot;https://www.fbi.gov/wanted/topten&quot;&gt;FBI’s Top Ten Most Wanted list&lt;/a&gt; and the broader &lt;a href=&quot;https://www.fbi.gov/wanted/api&quot;&gt;FBI’s Most Wanted API&lt;/a&gt;, the development of this connector was aimed at unlocking this data trove. By facilitating streamlined access to these resources through the Power Platform, the connector is designed to empower developers and agencies to build solutions that enhance public safety and awareness. This initiative not only simplifies the integration of critical law enforcement data into various applications but also supports the wider goal of keeping communities informed and safe.&lt;/p&gt;
&lt;h4 id=&quot;operations-overview&quot;&gt;Operations Overview:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;List Recent Wanted&lt;/strong&gt;: Fetches the latest list of individuals deemed most wanted by the FBI. This operation is perfect for applications or flows designed to provide timely updates on significant fugitives.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Get Wanted Person Details&lt;/strong&gt;: Allows for retrieving detailed information on a specific individual from the most wanted list. By supplying a unique identifier (UID), users can access in-depth profiles, including criminal charges, last known locations, and available rewards.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;List Art Crimes&lt;/strong&gt;: Accesses information on stolen art and artifacts, highlighting cases of significant cultural and historical value. This operation can be used to raise awareness about art theft and assist in recovery efforts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Get Art Crime Details&lt;/strong&gt;: Similar to the operation for individuals, this allows for detailed exploration of a specific art crime, providing descriptions, images, and details about the theft.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;demonstrating-the-connectors-capabilities&quot;&gt;Demonstrating the Connector’s Capabilities&lt;/h3&gt;
&lt;p&gt;To illustrate the practical use of the connector, a sample PowerApp and a flow have been developed:&lt;/p&gt;
&lt;h4 id=&quot;sample-powerapp&quot;&gt;Sample PowerApp&lt;/h4&gt;
&lt;p&gt;This application allows users to search and access detailed profiles of the FBI’s most wanted, designed to facilitate public engagement and support law enforcement efforts.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/8e2dc855-b040-4c59-a411-21fb1985f80e&quot; alt=&quot;Sample PowerApp&quot;&gt;&lt;/p&gt;
&lt;p&gt;Following the illustrative image in the article, let’s delve into how to effectively leverage the app with the FBI Most Wanted Custom Connector to display the top 10 most wanted individuals. By integrating real-time data directly into your Power App, you can create a dynamic and informative resource. Here’s a step-by-step guide to setting up your app:&lt;/p&gt;
&lt;h4 id=&quot;leveraging-the-fbi-most-wanted-custom-connector-in-your-app&quot;&gt;Leveraging the FBI Most Wanted Custom Connector in Your App&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add the Data Source&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the canvas app editor, navigate to the data table.&lt;/li&gt;
&lt;li&gt;Click the ‘Add data’ button and search for “FBI Most Wanted.”&lt;/li&gt;
&lt;li&gt;Select the FBI Most Wanted Custom Connector to add it as a data source to your app.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure the App to Display the Top 10&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access the properties for the app and locate the formulas property.&lt;/li&gt;
&lt;li&gt;Enter the following formula to retrieve the top 10 most wanted individuals based on the ‘ten’ poster classification:&lt;pre&gt;&lt;code&gt;Top10 = FBIMostWanted.ListWanted({poster_classification: &quot;ten&quot;}).items;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Adjust this formula as needed to match your specific display preferences.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set Up a Gallery&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a gallery to your app and set its items property to &lt;code&gt;Top10&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This gallery will dynamically display the top 10 most wanted individuals, pulling the latest data from the FBI’s database.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Display Individual Details&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To add an image for each individual within the gallery, use the following expression:&lt;pre&gt;&lt;code&gt;First(ThisItem.images).thumb
&lt;/code&gt;&lt;/pre&gt;
This expression fetches the thumbnail image from the available images for each person.&lt;/li&gt;
&lt;li&gt;To display the person’s name, add a text box to the gallery and set its text property to:&lt;pre&gt;&lt;code&gt;ThisItem.title
&lt;/code&gt;&lt;/pre&gt;
This will show the title or name associated with each wanted individual.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By following these instructions, you can create a powerful application that not only informs users about the FBI’s top 10 most wanted individuals but also keeps the information current with daily updates. This app serves as a valuable tool for raising awareness and aiding in the identification and reporting of suspects, showcasing the power of integrating real-time law enforcement data into custom applications.&lt;/p&gt;
&lt;h4 id=&quot;sample-flow&quot;&gt;Sample Flow&lt;/h4&gt;
&lt;p&gt;A scheduled daily flow designed to email users about the current FBI Top 10 Most Wanted. This automation ensures recipients are kept informed with the latest updates, directly contributing to heightened awareness and community safety.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The Power Platform Custom Connector for the FBI’s Most Wanted represents a significant step forward in the use of technology for public safety. By providing easy access to vital information, it enables a broad spectrum of developers to create applications that not only inform the public but also support the vital work of law enforcement agencies. It stands as a testament to the power of technology to make a real-world impact on safety and justice.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/1692805850685575522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/02/fbi-top-ten-power-platform-connector.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1692805850685575522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1692805850685575522'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/02/fbi-top-ten-power-platform-connector.html' title='FBI Top Ten Power Platform Connector'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-5027593922789144789</id><published>2025-02-19T12:18:00.001-05:00</published><updated>2025-02-19T12:18:18.862-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Annotation"/><category scheme="http://www.blogger.com/atom/ns#" term="Dashboard"/><category scheme="http://www.blogger.com/atom/ns#" term="Grid"/><category scheme="http://www.blogger.com/atom/ns#" term="List"/><category scheme="http://www.blogger.com/atom/ns#" term="Mode Apps"/><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><category scheme="http://www.blogger.com/atom/ns#" term="Power Apps"/><category scheme="http://www.blogger.com/atom/ns#" term="power platform"/><category scheme="http://www.blogger.com/atom/ns#" term="View"/><title type='text'>How to Show Notes (Annotations) on a Model-Driven App Dashboard</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/6340b6f4-df97-4a81-b1e4-813d671be6bb&quot; alt=&quot;How to Show Notes (Annotations) on a Model-Driven App Dashboard&quot;&gt;&lt;/p&gt;
&lt;p&gt;Model-driven apps in Power Apps allow users to create dashboards that display key data from different entities. By default, dashboards do not provide an easy way to display Notes (Annotations). However, using a combination of dashboard customization and XrmToolBox, you can modify a dashboard to include a list of Notes. This article provides a step-by-step guide to achieving this.&lt;/p&gt;
&lt;h3 id=&quot;step-1-create-a-new-dashboard&quot;&gt;&lt;strong&gt;Step 1: Create a New Dashboard&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Maker Portal&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create a new &lt;strong&gt;dashboard&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;When adding components to the dashboard, insert a &lt;strong&gt;List&lt;/strong&gt; for any entity (e.g., Accounts). The selected entity does not matter, as we will modify it later to display Notes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/1af606e3-919b-4441-82e6-537093a41f3e&quot; alt=&quot;Create new dashboard&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-2-obtain-the-notes-view-id&quot;&gt;&lt;strong&gt;Step 2: Obtain the Notes View ID&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;In the &lt;strong&gt;Maker Portal&lt;/strong&gt;, navigate to an existing &lt;strong&gt;View&lt;/strong&gt; for the &lt;strong&gt;Notes (Annotations)&lt;/strong&gt; entity or create a new custom view.&lt;/li&gt;
&lt;li&gt;Once the view is open, &lt;strong&gt;copy the View ID&lt;/strong&gt; as it will be needed later.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/8404f9d5-bd9a-4cc8-ba7d-599e4015d132&quot; alt=&quot;Copy view guid&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-3-install-xrmtoolbox-and-formxml-manager-plugin&quot;&gt;&lt;strong&gt;Step 3: Install XrmToolBox and FormXml Manager Plugin&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Download and install &lt;strong&gt;XrmToolBox&lt;/strong&gt; from &lt;a href=&quot;https://www.xrmtoolbox.com/&quot;&gt;https://www.xrmtoolbox.com/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install the &lt;strong&gt;FormXml Manager Plugin&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Connect to your &lt;strong&gt;Dataverse environment&lt;/strong&gt; where the dashboard was created.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/c56e5192-b18b-4823-90f2-09d00ff4c2d5&quot; alt=&quot;Install FormXml Manager&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: If you don’t have access to use XrmToolBox, you can also update this FormXml by creating a new unmanaged solution and adding in just the dashboard you created earlier. Then export and unzip the solution, you will find the FormXml within the customizations.xml file. Perform the updates as described in the next step, then re-zip all the files and reimport the solution.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-4-modify-the-dashboard’s-xml&quot;&gt;&lt;strong&gt;Step 4: Modify the Dashboard’s XML&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;FormXml Manager&lt;/strong&gt; in XrmToolBox.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Load Dashboards&lt;/strong&gt; and select &lt;strong&gt;Dashboard&lt;/strong&gt; in the entity list.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;FormXmls pane&lt;/strong&gt;, find and select your &lt;strong&gt;custom dashboard&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Edit FormXml&lt;/strong&gt; to open the editor.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/33c566ad-16f0-49fd-829d-77708cf9230e&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Locate the control corresponding to the &lt;strong&gt;List component&lt;/strong&gt; added in Step 1 (e.g., the Accounts list).&lt;/li&gt;
&lt;li&gt;Modify the XML as follows:
&lt;ul&gt;
&lt;li&gt;Change the label from:&lt;pre class=&quot; language-xml&quot;&gt;&lt;code class=&quot;prism  language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Accounts&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;languagecode&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1033&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
to:&lt;pre class=&quot; language-xml&quot;&gt;&lt;code class=&quot;prism  language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Notes&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;languagecode&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1033&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Change the target entity from:&lt;pre class=&quot; language-xml&quot;&gt;&lt;code class=&quot;prism  language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;TargetEntityType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;account&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;TargetEntityType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
to:&lt;pre class=&quot; language-xml&quot;&gt;&lt;code class=&quot;prism  language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;TargetEntityType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;annotation&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;TargetEntityType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Update the View ID with the one copied earlier:&lt;pre class=&quot; language-xml&quot;&gt;&lt;code class=&quot;prism  language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ViewId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;{e7b7272b-dcee-ef11-be21-00224804c479}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ViewId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Update&lt;/strong&gt; and &lt;strong&gt;Publish&lt;/strong&gt; the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/86bdf98a-a0d8-4ea2-9aae-4877a4b318db&quot; alt=&quot;Steps to update FormXml&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-5-verify-changes-in-the-model-driven-app&quot;&gt;&lt;strong&gt;Step 5: Verify Changes in the Model-Driven App&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Return to your &lt;strong&gt;Model-Driven App&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Dashboard&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The list that previously displayed &lt;strong&gt;Accounts&lt;/strong&gt; should now display &lt;strong&gt;Notes&lt;/strong&gt; instead.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/ac62d077-12b7-44ca-bdfc-f6a75b270edd&quot; alt=&quot;Notes list now in dashboard&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;By following these steps, you have successfully modified a Model-Driven App Dashboard to display Notes (Annotations) using XrmToolBox. This method allows for greater customization of dashboards to meet business requirements.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/5027593922789144789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/02/how-to-show-notes-annotations-on-model.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/5027593922789144789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/5027593922789144789'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/02/how-to-show-notes-annotations-on-model.html' title='How to Show Notes (Annotations) on a Model-Driven App Dashboard'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-7049330464247089532</id><published>2025-02-19T10:34:00.004-05:00</published><updated>2025-04-21T10:28:35.802-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="banner"/><category scheme="http://www.blogger.com/atom/ns#" term="classification"/><category scheme="http://www.blogger.com/atom/ns#" term="components"/><category scheme="http://www.blogger.com/atom/ns#" term="power pages"/><category scheme="http://www.blogger.com/atom/ns#" term="power platform"/><category scheme="http://www.blogger.com/atom/ns#" term="powerpages"/><category scheme="http://www.blogger.com/atom/ns#" term="Templates"/><category scheme="http://www.blogger.com/atom/ns#" term="webtemplates"/><title type='text'>Using Web Templates as Custom Components in Power Pages: A Classification Banner Example</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/a6f535ee-94d3-4439-b5e3-664d10524feb&quot; alt=&quot;Using Web Templates as Custom Components in Power Pages: A Classification Banner Example&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Web templates in Power Pages offer a powerful way to create reusable components that can be used across multiple pages, headers, and footers. This approach simplifies development and maintenance by allowing common elements, such as banners or data tables, to be managed centrally. In this article, we will explore how to use web templates as custom components, focusing on a practical example: a classification banner that can be placed in the header or footer of a Power Pages site.&lt;/p&gt;
&lt;h2 id=&quot;what-are-web-templates-in-power-pages&quot;&gt;What Are Web Templates in Power Pages?&lt;/h2&gt;
&lt;p&gt;Web templates are Liquid-based templates that allow developers to structure and render dynamic content within Power Pages. They are commonly used for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Custom layouts&lt;/strong&gt;: Defining reusable structures for pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reusable components&lt;/strong&gt;: Creating elements like banners, notifications, and data tables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic content&lt;/strong&gt;: Injecting data dynamically using Dataverse and Liquid expressions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Microsoft has provided comprehensive guidance on using web templates as components in Power Pages. You can read more about it in the &lt;a href=&quot;https://learn.microsoft.com/en-us/power-pages/configure/web-templates-as-components&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;creating-a-reusable-classification-banner-component&quot;&gt;Creating a Reusable Classification Banner Component&lt;/h2&gt;
&lt;p&gt;A classification banner is a useful element in government or security-focused applications, where content must be labeled according to its classification level (e.g., Unclassified, Confidential, Top Secret). Instead of hardcoding this banner on multiple pages, we can create a reusable web template component.&lt;/p&gt;
&lt;h3 id=&quot;step-1-creating-the-web-template&quot;&gt;Step 1: Creating the Web Template&lt;/h3&gt;
&lt;p&gt;Below is the web template code for a classification banner component that allows users to specify its position (top or bottom), text, and background color. Once you have the code, you need to add the web template to Power Pages.&amp;nbsp; You can quickly do this using the Power Pages Management app.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to the Power Pages Management App via the Power Pages Maker Portal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/9fb49f6a-093f-49b0-86a4-03218599b974&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a new Web Template record.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste the code into the Source field and save the record.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/4c6ff8ae-ccf2-4076-ba0d-365006b25f8c&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;pre class=&quot; language-liquid&quot;&gt;&lt;code class=&quot;prism  language-liquid&quot;&gt;{% manifest %}
{
    &quot;type&quot;: &quot;Functional&quot;,
    &quot;displayName&quot;: &quot;Classification Banner&quot;,
    &quot;description&quot;: &quot;Used to display the classification banner in the header and footer with customizable text and background color.&quot;,
    &quot;params&quot;: [
        {
            &quot;id&quot;: &quot;position&quot;,
            &quot;displayName&quot;: &quot;Position&quot;,
            &quot;description&quot;: &quot;Enter the position of the banner: either &#39;top&#39; or &#39;bottom&#39;.&quot;
        },
        {
            &quot;id&quot;: &quot;text&quot;,
            &quot;displayName&quot;: &quot;Banner Text&quot;,
            &quot;description&quot;: &quot;Enter the classification text to display. Examples: &#39;Unclassified&#39;, &#39;Controlled (CUI)&#39;, &#39;Confidential&#39;, &#39;Secret&#39;, &#39;Top Secret&#39;, &#39;Top Secret//SCI&#39;.&quot;
        },
        {
            &quot;id&quot;: &quot;backgroundColor&quot;,
            &quot;displayName&quot;: &quot;Background Color&quot;,
            &quot;description&quot;: &quot;Choose a background color based on classification level: Unclassified: #007a33, Controlled (CUI): #502b85, Confidential: #0033a0, Secret: #c8102e, Top Secret: #ff8c00, Top Secret//SCI: #fce83a.&quot;
        }
    ]
}
{% endmanifest %}

{% if user %}
&amp;lt;div style=&quot;
    background-color: {{ backgroundColor }};
    color: {% if backgroundColor == &#39;#fce83a&#39; or backgroundColor == &#39;#ff8c00&#39; %}black{% else %}white{% endif %};
    width: 100%;
    height: 2.5rem;
    font-weight: 700;
    justify-content: center;
    align-items: center;
    text-transform: uppercase;
    display: flex;
    position: sticky;
    {% if position == &#39;top&#39; %}
        top: 0;
    {% endif %}
    {% if position == &#39;bottom&#39; %}
        bottom: 0;
    {% endif %}
    left: 0;
    z-index: 1000;&quot;&amp;gt;
    {{ text }}
&amp;lt;/div&amp;gt;
{% endif %}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-adding-the-component-to-a-page&quot;&gt;Step 2: Adding the Component to a Page&lt;/h3&gt;
&lt;p&gt;Once the web template is created, it can be inserted into a page, header, or footer.&lt;/p&gt;
&lt;h4 id=&quot;inserting-the-component-into-the-header&quot;&gt;Inserting the Component into the Header&lt;/h4&gt;
&lt;p&gt;To insert the component into the header, use the &lt;strong&gt;VS Code Editor&lt;/strong&gt; built into Power Pages. Navigate to the &lt;strong&gt;Header Web Template&lt;/strong&gt; and add the following code snippet where the classification banner should appear:&lt;/p&gt;
&lt;pre class=&quot; language-liquid&quot;&gt;&lt;code class=&quot;prism  language-liquid&quot;&gt;{% component name=&quot;Classification Banner&quot; position=&quot;top&quot; text=&quot;Confidential&quot; backgroundColor=&quot;#0033a0&quot; %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/635eedb3-f6c5-4a99-9b91-ac73b0f1dc48&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/fde83ee6-fbba-4ab4-b128-0fd7c7332797&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-3-modifying-component-settings&quot;&gt;Step 3: Modifying Component Settings&lt;/h3&gt;
&lt;p&gt;Once the component is placed on a page, you can modify its settings directly within the editor. If the component is added to a header or footer, you will need to return to the &lt;strong&gt;VS Code Editor&lt;/strong&gt; to make changes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/77a45c4c-2c34-44c9-b809-5c1b6fb84585&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-4-editing-web-templates-in-restricted-environments&quot;&gt;Step 4: Editing Web Templates in Restricted Environments&lt;/h3&gt;
&lt;p&gt;If you are working in an environment where the built-in VS Code Editor is not available, you can use the &lt;strong&gt;Power Platform CLI (PAC CLI)&lt;/strong&gt; to download and edit the web templates.&lt;/p&gt;
&lt;h4 id=&quot;steps-to-use-pac-cli&quot;&gt;Steps to Use PAC CLI:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Install the Power Platform CLI if you haven’t already.&lt;/li&gt;
&lt;li&gt;Authenticate to your Power Pages environment using:&lt;pre class=&quot; language-sh&quot;&gt;&lt;code class=&quot;prism  language-sh&quot;&gt;pac auth create --environment &quot;your-environment&quot; --cloud UsGovHigh
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Download the web template files:&lt;pre class=&quot; language-sh&quot;&gt;&lt;code class=&quot;prism  language-sh&quot;&gt;pac pages download --environment &quot;your-environment&quot; --cloud UsGovHigh --modelVersion 2
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Make your modifications locally using your preferred editor.&lt;/li&gt;
&lt;li&gt;Upload the updated web template back to Power Pages:&lt;pre class=&quot; language-sh&quot;&gt;&lt;code class=&quot;prism  language-sh&quot;&gt;pac pages upload --environment &quot;your-environment&quot; --cloud UsGovHigh --path &quot;your-local-path&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This method ensures you can manage your custom components even when direct online editing is not possible.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Using web templates as custom components in Power Pages allows for greater flexibility and maintainability in site development. Whether for simple elements like banners or more complex components like data tables, this approach enhances efficiency and reusability.&lt;/p&gt;
&lt;p&gt;By leveraging the VS Code Editor or PAC CLI, you can efficiently create, modify, and deploy these components across your Power Pages sites. Ready to start building reusable components? Give it a try and enhance your Power Pages experience!&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/7049330464247089532/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2025/02/using-web-templates-as-custom.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/7049330464247089532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/7049330464247089532'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2025/02/using-web-templates-as-custom.html' title='Using Web Templates as Custom Components in Power Pages: A Classification Banner Example'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-7900660215382814819</id><published>2024-11-20T14:35:00.002-05:00</published><updated>2024-11-20T14:35:46.626-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="data"/><category scheme="http://www.blogger.com/atom/ns#" term="dataverse"/><category scheme="http://www.blogger.com/atom/ns#" term="Dynamics"/><category scheme="http://www.blogger.com/atom/ns#" term="powerbi"/><category scheme="http://www.blogger.com/atom/ns#" term="reporting"/><category scheme="http://www.blogger.com/atom/ns#" term="Reports"/><title type='text'>From Messy to Manageable: Cleanly Load Dataverse Tables in Power BI</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/58aa531e-bae7-4ed1-b88a-a54cf87b1db6&quot; alt=&quot;From Messy to Manageable: Cleanly Load Dataverse Tables in Power BI&quot;&gt;&lt;/p&gt;
&lt;p&gt;First and foremost, I want to take a moment to acknowledge &lt;a href=&quot;https://www.linkedin.com/in/brandonpires/&quot;&gt;Brandon Pires&lt;/a&gt;, who originally crafted the script that inspired all of this work. Brandon’s creativity laid the foundation for this blog post, and his efforts are key to helping Power BI developers improve efficiency and cleanliness in their reports.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Introduction: Using Templates to Keep Your Dataverse Clean&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When working with Microsoft Dataverse in Power BI, things can get messy quickly. Dataverse often contains a wealth of fields, system columns, and metadata that can make your reports harder to understand, cluttered, and less efficient. However, by leveraging templates and custom functions, you can automatically clean and format your data, allowing you to focus on deriving insights rather than grappling with unnecessary noise.&lt;/p&gt;
&lt;p&gt;One such function, inspired by Brandon Pires, is designed to clean column names from Dataverse and keep them tidy. In this blog post, I will explain how this function works, why it improves efficiency, and how you can use it in your Power BI workflows to create more manageable and maintainable data models.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Power BI Cleaning Function: A Deep Dive&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let
    // Define the function with parameters for the table name, prefix, Dataverse host, and feature toggles
    #&quot;Clean Table&quot; = (tableName as text, prefix as text, dataverseHost as text, transformDateTimeToDate as logical, removeColumnsWithTablesAndRecords as logical) =&amp;gt;
    let
        // Connect to the Common Data Service
        Source = CommonDataService.Database(dataverseHost),
        
        // Retrieve the specified table
        #&quot;One Table&quot; = Source{[Schema=&quot;dbo&quot;, Item=tableName]}[Data],
        
        // Rename columns with the specified prefix
        #&quot;Rename columns to system columns&quot; = Table.RenameColumns(
            #&quot;One Table&quot;,
            {
                {&quot;createdon&quot;, prefix &amp;amp; &quot;createdon&quot;},
                {&quot;modifiedon&quot;, prefix &amp;amp; &quot;modifiedon&quot;},
                {&quot;createdby&quot;, prefix &amp;amp; &quot;createdby&quot;},
                {&quot;statuscodename&quot;, prefix &amp;amp; &quot;statusreason&quot;},
                {&quot;statecodename&quot;, prefix &amp;amp; &quot;state&quot;}
            }
        ),
        
        // List of all datetime and datetimezone columns
        #&quot;List of all datetime and datetimezone columns&quot; = if transformDateTimeToDate then
            Table.ColumnsOfType(
                #&quot;Rename columns to system columns&quot;,
                {
                    type nullable datetime,
                    type datetime,
                    type nullable datetimezone,
                    type datetimezone
                }
            )
        else
            {},
        
        // Create list pair of datetime and datetimezone columns to type date pair
        #&quot;Create list pair of datetime and datetimezone columns to type date pair&quot; = if transformDateTimeToDate then
            List.Transform(
                #&quot;List of all datetime and datetimezone columns&quot;,
                each {_, type date}
            )
        else
            {},
        
        // Transform datetime and datetimezone columns to date
        #&quot;Transform datetime and datetimezone columns to date&quot; = if transformDateTimeToDate then
            Table.TransformColumnTypes(
                #&quot;Rename columns to system columns&quot;,
                #&quot;Create list pair of datetime and datetimezone columns to type date pair&quot;
            )
        else
            #&quot;Rename columns to system columns&quot;,
        
        // Get names of columns with tables and records
        #&quot;Get names of columns with tables and records&quot; = if removeColumnsWithTablesAndRecords then
            Table.ColumnsOfType(
                #&quot;Transform datetime and datetimezone columns to date&quot;,
                {
                    type nullable table,
                    type table,
                    type nullable record,
                    type record
                }
            )
        else
            {},
        
        // Remove columns with tables and records
        #&quot;Remove columns with tables and records&quot; = if removeColumnsWithTablesAndRecords then
            Table.RemoveColumns(
                #&quot;Transform datetime and datetimezone columns to date&quot;,
                #&quot;Get names of columns with tables and records&quot;
            )
        else
            #&quot;Transform datetime and datetimezone columns to date&quot;,
        
        // Remove system columns, only keep columns with specified prefix or &quot;modified&quot;
        #&quot;Remove system columns&quot; = Table.TransformColumnNames(
            Table.SelectColumns(
                #&quot;Remove columns with tables and records&quot;,
                List.Select(
                    Table.ColumnNames(#&quot;Remove columns with tables and records&quot;),
                    each Text.StartsWith(_, prefix) or Text.StartsWith(_, &quot;modified&quot;)
                )
            ),
            each Text.Replace(_, prefix, &quot;&quot;)
        )
    in
        #&quot;Remove system columns&quot;
in
    #&quot;Clean Table&quot;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function script presented here is a template that helps you &lt;strong&gt;remove unnecessary columns&lt;/strong&gt; and &lt;strong&gt;rename system fields&lt;/strong&gt;, making your data more consistent and easier to work with. The function takes in parameters such as the &lt;strong&gt;Dataverse host URL&lt;/strong&gt;, a &lt;strong&gt;prefix for column names&lt;/strong&gt;, and flags to control additional transformations. Let’s break down how each part of this function works:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Connect to the Dataverse Host&lt;/strong&gt;: This function starts by connecting to Dataverse using a parameterized URL (&lt;code&gt;dataverseHost&lt;/code&gt;). This is a best practice because it allows the same function to be used across different environments (like dev, test, and production) without modifying the core script.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rename System Columns&lt;/strong&gt;: One of the early steps in the function is to rename system columns by adding a specified prefix (&lt;code&gt;prefix&lt;/code&gt;). This ensures that key fields like &lt;code&gt;createdon&lt;/code&gt;, &lt;code&gt;modifiedon&lt;/code&gt;, etc., are consistently labeled, helping to avoid confusion. Consistent column naming also makes your data model more intuitive for future developers or collaborators.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Optional Transformations&lt;/strong&gt;: This function uses two &lt;strong&gt;feature toggles&lt;/strong&gt; (&lt;code&gt;transformDateTimeToDate&lt;/code&gt; and &lt;code&gt;removeColumnsWithTablesAndRecords&lt;/code&gt;) to control how much data cleaning is performed. This flexibility helps adapt the function to different use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Date Transformations&lt;/strong&gt;: Converts datetime columns to simple date columns if specified, reducing data complexity and making it easier to create date-based visuals.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Removing Complex Columns&lt;/strong&gt;: The script can also remove columns containing nested tables or records, which can complicate data processing and impact performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Filtering Columns&lt;/strong&gt;: Finally, the function removes any columns that do not match the specified prefix or the word &lt;code&gt;&quot;modified&quot;&lt;/code&gt;. This helps limit your data to only what you need, cutting down on clutter and improving the efficiency of your Power BI reports.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Best Practice: Use a Parameter for Dataverse URL&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One of the best practices highlighted by this script is to use a &lt;strong&gt;parameter for the Dataverse URL&lt;/strong&gt; (&lt;code&gt;dataverseHost&lt;/code&gt;). By using parameters, you can easily switch environments without editing the script each time. This approach supports a &lt;strong&gt;more agile and scalable development process&lt;/strong&gt; and allows teams to deploy their reports in multiple environments seamlessly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/ee084ac5-632e-4f02-b87b-c318903af495&quot; alt=&quot;Create parameter&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you’re unsure how to create a parameter in Power BI, here’s a quick guide:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;Power BI Desktop&lt;/strong&gt;, navigate to the &lt;strong&gt;Home&lt;/strong&gt; tab and click &lt;strong&gt;Manage Parameters&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New Parameter&lt;/strong&gt; and name it something like &lt;code&gt;DataverseUrl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Type&lt;/strong&gt; to &lt;strong&gt;Text&lt;/strong&gt; and use the &lt;strong&gt;Suggested Values&lt;/strong&gt; option to create a &lt;strong&gt;List of Values&lt;/strong&gt;. Enter your different environment URLs, such as Dev, Integration, and Prod, into the list. Then, set the &lt;strong&gt;Default Value&lt;/strong&gt; and &lt;strong&gt;Current Value&lt;/strong&gt; to the appropriate environment (e.g., your development Dataverse URL).&lt;/li&gt;
&lt;li&gt;Use this parameter in your query to reference different environments without rewriting your scripts.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;How to Add This Function to Your Power BI Report&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To use this function within Power BI, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open Power Query Editor&lt;/strong&gt;: In your Power BI Desktop file, go to &lt;strong&gt;Transform Data&lt;/strong&gt; to open Power Query Editor.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a New Query&lt;/strong&gt;: Click on &lt;strong&gt;New Source&lt;/strong&gt; &amp;gt; &lt;strong&gt;Blank Query&lt;/strong&gt;, then open the &lt;strong&gt;Advanced Editor&lt;/strong&gt; and paste the script provided.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rename Function&lt;/strong&gt;: After pasting, rename the query to something like &lt;code&gt;CleanTable&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Invoke the Function&lt;/strong&gt;: Now that you have the function, you can use it to clean multiple tables. For each table, create a new query and use &lt;strong&gt;Invoke Custom Function&lt;/strong&gt;, selecting &lt;code&gt;CleanTable&lt;/code&gt; and specifying your desired parameters. You can also use this function on Microsoft tables, such as &lt;code&gt;account&lt;/code&gt; and &lt;code&gt;contact&lt;/code&gt;, if you wish to apply some of the optional transformations. Just make sure to set the &lt;code&gt;prefix&lt;/code&gt; parameter to an empty string (&lt;code&gt;&quot;&quot;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/f5d3cb0f-9e3d-4c14-bc5d-29354ae651ca&quot; alt=&quot;call function&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This process allows you to apply consistent cleaning across multiple tables in Dataverse, significantly improving both efficiency and maintainability.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/77bb5350-5e83-41ad-91d9-09ed65fd79e3&quot; alt=&quot;show data pane&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Save as a Template for Future Use&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can also save your Power BI report with this function and parameter as a &lt;strong&gt;template file&lt;/strong&gt; (.pbit). This allows you to easily reuse the setup for all of your future reports. By using a template, you can ensure consistency across different projects and avoid repeating the setup process each time you need to create a new report.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Keeping your Power BI data clean and organized is crucial for effective reporting and analysis. By leveraging custom functions like the one described here, you can maintain consistency, reduce clutter, and improve the performance of your Power BI reports. Inspired by Brandon Pires, this script is a powerful tool to help streamline your data transformation process, making your reports more intuitive and easier to manage.&lt;/p&gt;
&lt;p&gt;Feel free to try this approach in your next Power BI project and let me know how it works for you. Embracing these best practices will save time and help your team stay focused on what really matters—extracting valuable insights from your data.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/7900660215382814819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/11/from-messy-to-manageable-cleanly-load.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/7900660215382814819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/7900660215382814819'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/11/from-messy-to-manageable-cleanly-load.html' title='From Messy to Manageable: Cleanly Load Dataverse Tables in Power BI'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-3783517998363999999</id><published>2024-10-16T09:35:00.002-04:00</published><updated>2024-10-16T09:35:10.530-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="api"/><category scheme="http://www.blogger.com/atom/ns#" term="canvas"/><category scheme="http://www.blogger.com/atom/ns#" term="connections"/><category scheme="http://www.blogger.com/atom/ns#" term="consent"/><category scheme="http://www.blogger.com/atom/ns#" term="deploy"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerApps"/><category scheme="http://www.blogger.com/atom/ns#" term="prompt"/><category scheme="http://www.blogger.com/atom/ns#" term="Security"/><title type='text'>Bypass Power Apps Consent Prompts Using PowerShell</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/ca0f86c0-1746-4196-80f1-3d53ec85caab&quot; alt=&quot;Bypass Power Apps Consent Prompts Using PowerShell&quot;&gt;&lt;/p&gt;
&lt;p&gt;When a user opens a Power App for the first time, they are often presented with a consent form asking for permission to access data sources or APIs used by the app. This Canvas API consent form can be disruptive, especially in scenarios where the app is intended for a broad user base or part of an automated deployment. The consent form can create unnecessary friction, requiring every user to individually approve permissions. Fortunately, there’s a way to bypass this pop-up consent form using PowerShell.&lt;/p&gt;
&lt;p&gt;In this blog post, I will guide you through automating the process of bypassing the Power Apps consent form using PowerShell. The goal is to either allow users to select an app from a specific environment or use a configuration file to perform actions on multiple environments.&lt;/p&gt;
&lt;p&gt;This automation can be particularly useful for initial deployments of a new app or to ensure all apps currently have this applied.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/2a561503-24b2-4c81-8d20-167e89fdceb1&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Background: Bypassing Power Apps Consent&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before diving into the PowerShell script, it’s important to understand what the Canvas API consent form is and why it might need to be bypassed. The consent form prompts users to confirm that they are comfortable with the application accessing various data sources. While this is an important security measure, it can be a hindrance in some situations. For example, when you have a small embedded app in a Power BI application, it may not be large enough for a user to see the consent form. Similarly, for apps that have been integrated into model-driven apps, users may not even realize that a Canvas App is present.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.matthewdevaney.com/disable-the-power-apps-permissions-pop-up-bypass-consent-form/&quot;&gt;Matthew Devaney&lt;/a&gt;’s article on how to &lt;a href=&quot;https://www.matthewdevaney.com/disable-the-power-apps-permissions-pop-up-bypass-consent-form/&quot;&gt;Disable the Power Apps Permissions Pop-Up&lt;/a&gt; and &lt;a href=&quot;https://www.imenos.com/en/power-apps/powerapps-bypass-consent-when-opening-app-the-first-time/&quot;&gt;Wouter&lt;/a&gt; detailed guide on &lt;a href=&quot;https://www.imenos.com/en/power-apps/powerapps-bypass-consent-when-opening-app-the-first-time/&quot;&gt;Bypassing Consent When Opening a Power App&lt;/a&gt; are excellent resources to get started. They demonstrate how to use PowerShell commands to bypass the consent screen for individual apps. I wanted to take this a step further by making the process more configurable and applicable to multiple environments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Script Overview&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The PowerShell script makes use of the &lt;code&gt;Microsoft.PowerApps.Administration.PowerShell&lt;/code&gt; module to interact with Power Apps environments and apps. With the ability to import a configuration file, you can easily define environments and apps that need to have their consent requirements bypassed. Alternatively, the script allows you to select a specific app interactively.&lt;/p&gt;
&lt;p&gt;Here’s a high-level overview of how the script works:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Import Required Modules&lt;/strong&gt;: The script begins by checking if the necessary PowerShell module (&lt;code&gt;Microsoft.PowerApps.Administration.PowerShell&lt;/code&gt;) is installed. If not, it installs the module automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disable Consent for Selected Apps&lt;/strong&gt;: Depending on how the script is run, it can either take an environment ID and app ID directly or load a configuration file to process multiple apps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration File Option&lt;/strong&gt;: The configuration file allows you to define multiple environments and their corresponding apps. This option is useful for automating environments like dev, QA, and production.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The script is documented using PowerShell’s self-documenting features, making it easier to understand and extend. The self-documentation provides details on parameters, descriptions, and usage examples. For more information on how to use these self-documenting features, see &lt;a href=&quot;https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help?view=powershell-7.4&quot;&gt;Microsoft’s documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PowerShell Script&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Below is the complete PowerShell script for automating the process of bypassing the Canvas API consent form. Before diving into the code, here’s a brief explanation: This script can be used to disable the consent prompts for specific Power Apps either interactively or through a predefined configuration. It is useful for simplifying user experience, particularly in deployments where manual consent approvals would be cumbersome.&lt;/p&gt;
&lt;h3 id=&quot;getting-the-environment-id&quot;&gt;Getting the Environment ID&lt;/h3&gt;
&lt;p&gt;To use this script, you will need the environment ID of your Power Platform environment. The easiest way to get this ID is by navigating to the &lt;a href=&quot;https://aka.ms/ppac&quot;&gt;Power Platform Admin Center&lt;/a&gt;, selecting the ‘Environments’ area, and viewing the details for your specific environment. Below is a picture that shows where you can find the details for an environment:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/3ddfb99b-d32e-49aa-960c-8e2e68090b34&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;how-to-use-the-script-based-on-different-examples&quot;&gt;How to Use the Script Based on Different Examples&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Using a Configuration File&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: &lt;code&gt;./DisableAppConsent.ps1 -configFilePath &quot;./config.json&quot; -configEnvironmentName &quot;dev&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;This example uses the configuration file to disable consent for all apps in the “dev” environment. You can define multiple environments and their respective apps within a JSON file. This method is particularly helpful if you want to automate the consent bypass process for multiple environments without any manual intervention.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Direct Environment and App ID&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: &lt;code&gt;./DisableAppConsent.ps1 -environmentId &quot;env-id&quot; -appId &quot;app-id&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;This example disables consent for a specific app using the provided environment ID and app ID. This is ideal when you already know the specific environment and app details you need to process. It allows for a quick and precise update without requiring additional configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interactive App Selection&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: &lt;code&gt;./DisableAppConsent.ps1 -environmentId &quot;env-id&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;This example allows the user to select an app from the specified environment to disable consent. If you only have an environment ID but do not know the specific app to target, this interactive option is useful. It will present a list of apps within the specified environment, allowing you to choose one interactively.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can also view the script on &lt;a href=&quot;https://github.com/rwilson504/PowerShell/blob/main/Dataverse/bypass-permissions-for-canvas-apps.ps1&quot;&gt;GitHub&lt;/a&gt;: You can also view the script on &lt;a href=&quot;https://github.com/rwilson504/PowerShell/blob/main/Dataverse/bypass-permissions-for-canvas-apps.ps1&quot;&gt;GitHub&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot; language-powershell&quot;&gt;&lt;code class=&quot;prism  language-powershell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;#
.SYNOPSIS
    This script disables the consent prompt for specified Power Apps in an environment.

.DESCRIPTION
    The script provides three ways to disable the consent prompt:
    1. Using a configuration file that contains environment and app details.
    2. Using a provided environment ID and app ID.
    3. Allowing the user to select an app from a given environment.

.AUTHOR
    Rick Wilson

.PARAMETER configFilePath
    The path to the configuration JSON file containing environment and app details.

.PARAMETER configEnvironmentName
    The name of the environment (e.g., dev, prod, qa) as specified in the configuration file.

.PARAMETER environmentId
    The ID of the environment to be used for disabling consent if a configuration file is not provided.

.PARAMETER appId
    The ID of the app to be used for disabling consent if a configuration file is not provided.

.EXAMPLE
    ./DisableAppConsent.ps1 -configFilePath &quot;./config.json&quot; -configEnvironmentName &quot;dev&quot;
    This example uses the configuration file to disable consent for all apps in the &quot;dev&quot; environment.

.EXAMPLE
    ./DisableAppConsent.ps1 -environmentId &quot;env-id&quot; -appId &quot;app-id&quot;
    This example disables consent for a specific app using the provided environment ID and app ID.

.EXAMPLE
    ./DisableAppConsent.ps1 -environmentId &quot;env-id&quot;
    This example allows the user to select an app from the specified environment to disable consent.

#&amp;gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Parameter definitions&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Mandatory=&lt;span class=&quot;token boolean&quot;&gt;$false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HelpMessage=&lt;span class=&quot;token string&quot;&gt;&quot;The path to the configuration JSON file containing environment and app details.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$configFilePath&lt;/span&gt; = &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Mandatory=&lt;span class=&quot;token boolean&quot;&gt;$false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HelpMessage=&lt;span class=&quot;token string&quot;&gt;&quot;The name of the environment (e.g., dev, prod, qa) as specified in the configuration file.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$configEnvironmentName&lt;/span&gt; = &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Mandatory=&lt;span class=&quot;token boolean&quot;&gt;$false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HelpMessage=&lt;span class=&quot;token string&quot;&gt;&quot;The ID of the environment to be used for disabling consent if a configuration file is not provided.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$environmentId&lt;/span&gt; = &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Mandatory=&lt;span class=&quot;token boolean&quot;&gt;$false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HelpMessage=&lt;span class=&quot;token string&quot;&gt;&quot;The ID of the app to be used for disabling consent if a configuration file is not provided.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$appId&lt;/span&gt; = &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Function to check if a module is installed and import it if necessary&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; Import&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ModuleIfNeeded &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token namespace&quot;&gt;[Parameter(Mandatory=$true)]&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$ModuleName&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Get-Module&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ListAvailable &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Name &lt;span class=&quot;token variable&quot;&gt;$ModuleName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Module &lt;span class=&quot;token variable&quot;&gt;$ModuleName&lt;/span&gt; not found. Installing...&quot;&lt;/span&gt;
        Install&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Module &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Name &lt;span class=&quot;token variable&quot;&gt;$ModuleName&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Force &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;AllowClobber
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Import-Module&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Name &lt;span class=&quot;token variable&quot;&gt;$ModuleName&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Import required module if it is not already installed&lt;/span&gt;
Import&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ModuleIfNeeded &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ModuleName &lt;span class=&quot;token string&quot;&gt;&quot;Microsoft.PowerApps.Administration.PowerShell&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Function to Disable Consent on a given App&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; Disable&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ConsentForApp &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token namespace&quot;&gt;[Parameter(Mandatory=$true)]&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$EnvironmentId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token namespace&quot;&gt;[Parameter(Mandatory=$true)]&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$AppId&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;# Disable consent&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;AdminPowerAppApisToBypassConsent &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;EnvironmentName &lt;span class=&quot;token variable&quot;&gt;$EnvironmentId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;AppName &lt;span class=&quot;token variable&quot;&gt;$AppId&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Main logic to determine which flow to execute&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$configFilePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-and&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$configEnvironmentName&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Load configuration file&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$configFilePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$config&lt;/span&gt; = &lt;span class=&quot;token function&quot;&gt;Get-Content&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Raw &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$configFilePath&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ConvertFrom-Json&lt;/span&gt;
        
        &lt;span class=&quot;token variable&quot;&gt;$environment&lt;/span&gt; = &lt;span class=&quot;token variable&quot;&gt;$config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;environments &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Where-Object&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$configEnvironmentName&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$appName&lt;/span&gt; in &lt;span class=&quot;token variable&quot;&gt;$environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appNames&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Retrieving App ID for app: &lt;span class=&quot;token variable&quot;&gt;$appName&lt;/span&gt; in environment: &lt;span class=&quot;token variable&quot;&gt;$environment&lt;/span&gt;.name&quot;&lt;/span&gt;
                &lt;span class=&quot;token variable&quot;&gt;$app&lt;/span&gt; = Get&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;AdminPowerApp &lt;span class=&quot;token variable&quot;&gt;$appName&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;EnvironmentName &lt;span class=&quot;token variable&quot;&gt;$environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;environmentId
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$app&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processing app: &lt;span class=&quot;token variable&quot;&gt;$appName&lt;/span&gt; with App ID:&lt;span class=&quot;token function&quot;&gt; $&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$app&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AppName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; in environment: &lt;span class=&quot;token variable&quot;&gt;$environment&lt;/span&gt;.name&quot;&lt;/span&gt;
                    Disable&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ConsentForApp &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;EnvironmentId &lt;span class=&quot;token variable&quot;&gt;$environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;environmentId &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;AppId &lt;span class=&quot;token variable&quot;&gt;$app&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AppName
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;App: &lt;span class=&quot;token variable&quot;&gt;$appName&lt;/span&gt; not found in environment: &lt;span class=&quot;token variable&quot;&gt;$environment&lt;/span&gt;.name&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Environment: &lt;span class=&quot;token variable&quot;&gt;$configEnvironmentName&lt;/span&gt; not found in configuration file.&quot;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;exit&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Configuration file not found at path: &lt;span class=&quot;token variable&quot;&gt;$configFilePath&lt;/span&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;exit&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;elseif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$environmentId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-and&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$appId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Use provided environment and app ID&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processing app: &lt;span class=&quot;token variable&quot;&gt;$appId&lt;/span&gt; in environment: &lt;span class=&quot;token variable&quot;&gt;$environmentId&lt;/span&gt;&quot;&lt;/span&gt;
    Disable&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ConsentForApp &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;EnvironmentId &lt;span class=&quot;token variable&quot;&gt;$environmentId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;AppId &lt;span class=&quot;token variable&quot;&gt;$appId&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;elseif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$environmentId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Prompt user to select an app from the provided environment&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Loading Power Apps from environment: &lt;span class=&quot;token variable&quot;&gt;$environmentId&lt;/span&gt;...&quot;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$apps&lt;/span&gt; = Get&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;AdminPowerApp &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;EnvironmentName &lt;span class=&quot;token variable&quot;&gt;$environmentId&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$appChoices&lt;/span&gt; = &lt;span class=&quot;token variable&quot;&gt;$apps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ForEach-Object&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$_&lt;/span&gt;.DisplayName (&lt;span class=&quot;token variable&quot;&gt;$_&lt;/span&gt;.AppName)&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token variable&quot;&gt;$selectedAppIndex&lt;/span&gt; = &lt;span class=&quot;token variable&quot;&gt;$appChoices&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Out-GridView&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Title &lt;span class=&quot;token string&quot;&gt;&quot;Select a Power App to disable consent&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;OutputMode Single
    &lt;span class=&quot;token variable&quot;&gt;$selectedApp&lt;/span&gt; = &lt;span class=&quot;token variable&quot;&gt;$apps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$selectedAppIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$selectedApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        Disable&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ConsentForApp &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;EnvironmentId &lt;span class=&quot;token variable&quot;&gt;$environmentId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;AppId &lt;span class=&quot;token variable&quot;&gt;$selectedApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AppId
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;No app selected. Exiting.&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Please provide either a configuration file path and config file environment name, or an environment ID.&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;exit&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Operation completed.&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Sample Configuration File&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Below is a sample configuration file (&lt;code&gt;config.json&lt;/code&gt;) that you can use with the script. This file defines multiple environments and the corresponding apps that need to have their consent bypassed. You can also view this sample configuration file on &lt;a href=&quot;https://github.com/rwilson504/PowerShell/blob/main/Dataverse/bypassPermissionsConfig.json&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;environments&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dev&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;environmentId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;00000000-0000-0000-0000-000000000000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;appNames&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;App Display Name&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;environmentId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;00000000-0000-0000-0000-000000000000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;appNames&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;App Display Name&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Interactive Deployment&lt;/strong&gt;: If you’re managing a single environment and need to disable consent for just one app, the script allows you to manually select the environment and app, making the process straightforward.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Using PowerShell to automate the bypassing of Power Apps consent forms can greatly simplify the user experience, particularly in large deployments. By incorporating flexibility to either select an app interactively or use a configuration file, you can customize the process to suit your needs—whether it’s a quick update or a flexible deployment process.&lt;/p&gt;
&lt;p&gt;The articles by &lt;a href=&quot;https://www.matthewdevaney.com/disable-the-power-apps-permissions-pop-up-bypass-consent-form/&quot;&gt;Matthew Devaney&lt;/a&gt; and &lt;a href=&quot;https://www.imenos.com/en/power-apps/powerapps-bypass-consent-when-opening-app-the-first-time/&quot;&gt;Wouter&lt;/a&gt; provide an excellent foundation, and this script builds upon those concepts to offer more advanced, flexible automation. I hope this guide and the PowerShell script help you streamline your Power Apps deployments and reduce friction for your users.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/3783517998363999999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/10/bypass-power-apps-consent-prompts-using.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/3783517998363999999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/3783517998363999999'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/10/bypass-power-apps-consent-prompts-using.html' title='Bypass Power Apps Consent Prompts Using PowerShell'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-6792479578687180826</id><published>2024-08-23T15:20:00.001-04:00</published><updated>2024-08-23T15:21:02.206-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="autogenate"/><category scheme="http://www.blogger.com/atom/ns#" term="autonumber"/><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="code"/><category scheme="http://www.blogger.com/atom/ns#" term="dataverse"/><category scheme="http://www.blogger.com/atom/ns#" term="dates"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="fiscalyear"/><category scheme="http://www.blogger.com/atom/ns#" term="plugins"/><category scheme="http://www.blogger.com/atom/ns#" term="unique"/><title type='text'>Custom Auto Number in Dataverse with Fiscal Year-Based Incrementing Using Plugin Code</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/d00d8c52-30ea-4f5e-a5ad-a2825b8a8a1c&quot; alt=&quot;Custom Auto Number in Dataverse with Fiscal Year-Based Incrementing Using Plugin Code&quot;&gt;&lt;/p&gt;
&lt;p&gt;In many scenarios, businesses require custom auto-numbering for records in Microsoft Dataverse that go beyond the default functionality provided. In this article, I’ll walk you through a solution that involves creating a custom auto-number field without using the out-of-the-box auto-numbering feature in Dataverse. Instead, we’ll use a combination of a custom entity as a counter and a plugin that triggers on the pre-create event of the target table.&lt;/p&gt;
&lt;h2 id=&quot;the-approach&quot;&gt;The Approach&lt;/h2&gt;
&lt;p&gt;For this solution, we’ll create a custom table called &lt;strong&gt;Fiscal Year Counter&lt;/strong&gt;. This table will manage our numbering sequence based on the fiscal year. The idea is to dynamically generate invoice numbers that reset each fiscal year, providing a high level of customization to fit your organization’s unique fiscal calendar.&lt;/p&gt;
&lt;h3 id=&quot;the-fiscal-year-counter-table-setup&quot;&gt;The &lt;strong&gt;Fiscal Year Counter&lt;/strong&gt; Table Setup&lt;/h3&gt;
&lt;p&gt;First, create a table named &lt;strong&gt;Fiscal Year Counter&lt;/strong&gt; with the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt; (String): To store the fiscal year name, such as “FY2024.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start Date&lt;/strong&gt; (Date Only, Time zone independent): The start date of the fiscal year.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;End Date&lt;/strong&gt; (Date Only, Time zone independent): The end date of the fiscal year.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Last Number&lt;/strong&gt; (Whole Number): To track the last generated number for the fiscal year.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This setup allows you to configure fiscal years according to your organization’s requirements. The records in this table must be pre-created with appropriate Name, Start Date, and End Date values. If you want to start the numbering at a value other than 1, you can set the &lt;strong&gt;Last Number&lt;/strong&gt; field accordingly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Ensure that the &lt;strong&gt;Start Date&lt;/strong&gt; and &lt;strong&gt;End Date&lt;/strong&gt; fields are set to “Date Only” and “Time Zone Independent.” This is crucial for the logic to work correctly, as using other date/time formats may lead to discrepancies in determining the correct fiscal year during the auto-numbering process.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;implementing-the-auto-numbering-logic&quot;&gt;Implementing the Auto-Numbering Logic&lt;/h2&gt;
&lt;p&gt;To automate the numbering, I developed a plugin that runs on the &lt;code&gt;pre-create&lt;/code&gt; event of the target table, which in this example is &lt;strong&gt;Invoices&lt;/strong&gt;. This plugin increments the last number in the &lt;strong&gt;Fiscal Year Counter&lt;/strong&gt; table based on the current fiscal year and assigns the new number to the invoice.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/894a9e17-4ce4-4b8a-848c-b731026822be&quot; alt=&quot;Plugin Step on Invoice&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;using-the-record-creation-date-to-determine-the-fiscal-year&quot;&gt;Using the Record Creation Date to Determine the Fiscal Year&lt;/h3&gt;
&lt;p&gt;The plugin determines which fiscal year a record belongs to by using the date on which the record is created. It compares this date with the start and end dates defined in the &lt;strong&gt;Fiscal Year Counter&lt;/strong&gt; table to identify the correct fiscal year.&lt;/p&gt;
&lt;h3 id=&quot;ensuring-uniqueness-through-database-locks&quot;&gt;Ensuring Uniqueness Through Database Locks&lt;/h3&gt;
&lt;p&gt;A crucial part of the plugin’s design is ensuring that each auto-generated number is unique. To achieve this, the plugin locks the &lt;strong&gt;Fiscal Year Counter&lt;/strong&gt; record during the number generation process. This lock prevents other processes from accessing the same record simultaneously, which could otherwise result in duplicate numbers.&lt;/p&gt;
&lt;p&gt;This locking mechanism is critical to maintaining the integrity of the auto-numbering sequence. Therefore, it’s important not to refactor the code for the sake of efficiency, as the current design prioritizes accuracy and uniqueness over speed.&lt;/p&gt;
&lt;h3 id=&quot;steps-in-the-auto-numbering-process&quot;&gt;Steps in the Auto-Numbering Process&lt;/h3&gt;
&lt;p&gt;Here’s a high-level overview of the steps involved:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Identify the Fiscal Year&lt;/strong&gt;: When a new invoice is created, the plugin uses the current date to determine which fiscal year the record falls into by comparing it against the start and end dates in the &lt;strong&gt;Fiscal Year Counter&lt;/strong&gt; table.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lock the Fiscal Year Record&lt;/strong&gt;: The plugin locks the identified fiscal year record to ensure no other process can modify it simultaneously, preventing duplicate numbers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Increment the Last Number&lt;/strong&gt;: The plugin retrieves the &lt;strong&gt;Last Number&lt;/strong&gt; field for the identified fiscal year, increments it, and updates the field.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Assign the Auto-Number&lt;/strong&gt;: The plugin concatenates the fiscal year name (e.g., “FY2024”) with the incremented number and assigns it to the invoice.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;writing-the-plugin&quot;&gt;Writing the Plugin&lt;/h2&gt;
&lt;p&gt;To implement this, you need to write a plugin that follows the steps outlined above. I won’t go into the details of settings up a plugin project, but I highly recommend referring to &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/developer/data-platform/write-plug-in?tabs=pluginbase&quot;&gt;this guide on writing plugins&lt;/a&gt; if you need help getting started. This guide provides a comprehensive tutorial on creating and registering a plugin in Dataverse.&lt;/p&gt;
&lt;pre class=&quot; language-c&quot;&gt;&lt;code class=&quot;prism # language-c&quot;&gt;using Microsoft&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Xrm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Sdk&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
using Microsoft&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Xrm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Sdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Messages&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
using Microsoft&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Xrm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Sdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Query&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
using System&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
using System&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Linq&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
using System&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ServiceModel&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

namespace AutoNumberByDate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Plugins
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    public class AutoNumberByFiscalYear &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; IPlugin
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        public &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IServiceProvider serviceProvider&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// Obtain the tracing service&lt;/span&gt;
            ITracingService tracingService &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ITracingService&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;serviceProvider&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ITracingService&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// Obtain the execution context from the service provider.  &lt;/span&gt;
            IPluginExecutionContext context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IPluginExecutionContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                serviceProvider&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IPluginExecutionContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


            &lt;span class=&quot;token comment&quot;&gt;// The InputParameters collection contains all the data passed in the message request.  &lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;InputParameters&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Target&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;InputParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Target&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; is Entity&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;// Obtain the target entity from the input parameters.  &lt;/span&gt;
                Entity entity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Entity&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;InputParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Target&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token comment&quot;&gt;// Obtain the IOrganizationService instance which you will need for web service calls.  &lt;/span&gt;
                IOrganizationServiceFactory serviceFactory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IOrganizationServiceFactory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;serviceProvider&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IOrganizationServiceFactory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;// Passing null into CreateOrganizationService will get the system organization service which will have access to the fiscal year counter by default.&lt;/span&gt;
                IOrganizationService service &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; serviceFactory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CreateOrganizationService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;null&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                try
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token comment&quot;&gt;//call the method to set the name field with the fiscal year number&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;SetNameFieldWithFiscalYearNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; service&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

                &lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FaultException&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;OrganizationServiceFault&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    throw new &lt;span class=&quot;token function&quot;&gt;InvalidPluginExecutionException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;An error occurred in AutoNumberByFiscalYear.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

                &lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Exception ex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    tracingService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Trace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;AutoNumberByFiscalYear: {0}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    throw&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        private &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SetNameFieldWithFiscalYearNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Entity entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; IOrganizationService service&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            string controlNumber &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0001&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; currentNumber &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// Get the current date in UTC.&lt;/span&gt;
            DateTime currentDate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; DateTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UtcNow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// Look for an existing fiscal year counter entity&lt;/span&gt;
            QueryExpression qExpression &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; new &lt;span class=&quot;token function&quot;&gt;QueryExpression&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                EntityName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;raw_fiscalyearcounter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                ColumnSet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; new &lt;span class=&quot;token function&quot;&gt;ColumnSet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;raw_lastnumber&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                Criteria &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; new FilterExpression
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    Conditions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                        new &lt;span class=&quot;token function&quot;&gt;ConditionExpression&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ConditionOperator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;LessEqual&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentDate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        new &lt;span class=&quot;token function&quot;&gt;ConditionExpression&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_end&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ConditionOperator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GreaterEqual&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentDate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            EntityCollection results &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; service&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;RetrieveMultiple&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;qExpression&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            Entity counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; results&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Entities&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FirstOrDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; null&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;// If the counter is there update it to lock it in the transaction.&lt;/span&gt;
                Entity blocker &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; new &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; LogicalName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;raw_fiscalyearcounter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; counter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                blocker&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; counter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GetAttributeValue&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                service&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;blocker&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token comment&quot;&gt;// Now that the counter is locked retrieve the counter again so that we can get the current number and update it.&lt;/span&gt;
                QueryExpression qExpression2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; new &lt;span class=&quot;token function&quot;&gt;QueryExpression&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    EntityName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;raw_fiscalyearcounter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    ColumnSet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; new &lt;span class=&quot;token function&quot;&gt;ColumnSet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_lastnumber&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;raw_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    Criteria &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; new FilterExpression
                    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                        Conditions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                            new &lt;span class=&quot;token function&quot;&gt;ConditionExpression&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ConditionOperator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;LessEqual&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentDate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            new &lt;span class=&quot;token function&quot;&gt;ConditionExpression&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_end&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ConditionOperator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GreaterEqual&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentDate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token comment&quot;&gt;// DO NOT refactor RetrieveMultipleRequest to RetrieveMultiple otherwise some caching will occur.&lt;/span&gt;
                RetrieveMultipleRequest rmRequest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; new &lt;span class=&quot;token function&quot;&gt;RetrieveMultipleRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; qExpression2 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                RetrieveMultipleResponse lockedResults &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;RetrieveMultipleResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;service&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rmRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                Entity lockedCounter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; lockedResults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;EntityCollection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Entities&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;First&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                Entity counterUpdater &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; new &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; LogicalName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;raw_fiscalyearcounter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; counter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token comment&quot;&gt;// Get the current number and increment it.&lt;/span&gt;
                currentNumber &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; lockedCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GetAttributeValue&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_lastnumber&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                currentNumber &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;currentNumber&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                controlNumber &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentNumber&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;PadLeft&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;0&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token comment&quot;&gt;// Update the counter with the new number.&lt;/span&gt;
                counterUpdater&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_lastnumber&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentNumber&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                service&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counterUpdater&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token comment&quot;&gt;// Set the control number on the invoice {FY}{Sequence #}&quot;.&lt;/span&gt;
                entity&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $&lt;span class=&quot;token string&quot;&gt;&quot;{lockedCounter.GetAttributeValue&amp;lt;string&amp;gt;(&quot;&lt;/span&gt;raw_name&lt;span class=&quot;token string&quot;&gt;&quot;)}{controlNumber}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;//if no counter was found throw an error&lt;/span&gt;
                throw new &lt;span class=&quot;token function&quot;&gt;InvalidPluginExecutionException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;No counter was found for the current fiscal year. Please contact your system administrator.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can access the complete code solution I created you can get it here: &lt;a href=&quot;https://github.com/rwilson504/DataverseAutoNumberByDateIncrements/tree/main/code/AutoNumberByDate&quot;&gt;https://github.com/rwilson504/DataverseAutoNumberByDateIncrements/tree/main/code/AutoNumberByDate&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;example-solution&quot;&gt;Example Solution&lt;/h2&gt;
&lt;p&gt;To help you get started, I’ve created a sample solution that implements the concepts discussed in this article. This example includes the &lt;strong&gt;Fiscal Year Counter&lt;/strong&gt; table, the plugin code, and the necessary configurations to replicate the auto-numbering functionality.&lt;/p&gt;
&lt;p&gt;Additionally, I’ve included a sample table called &lt;strong&gt;Invoices&lt;/strong&gt;, along with a model-driven app that integrates these tables. This setup allows you to easily configure and test the auto-numbering functionality in a practical environment.&lt;/p&gt;
&lt;p&gt;You can download the sample solutions here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rwilson504/DataverseAutoNumberByDateIncrements/raw/main/AutoNumberingBasedonDates_1_0_0_1.zip&quot;&gt;Unmanaged&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rwilson504/DataverseAutoNumberByDateIncrements/raw/main/AutoNumberingBasedonDates_1_0_0_1_managed.zip&quot;&gt;Managed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;creating-the-fiscal-year-counter-records&quot;&gt;Creating the Fiscal Year Counter Records&lt;/h3&gt;
&lt;p&gt;Below are screenshots showing the setup of the &lt;strong&gt;Fiscal Year Counter&lt;/strong&gt; records. These screenshots demonstrate how to configure the Name, Start Date, End Date, and Last Number fields.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/b1a3a869-8bec-4ddc-896b-332b973c381e&quot; alt=&quot;Fiscal Year Counter Records&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;creating-new-invoices&quot;&gt;Creating New Invoices&lt;/h3&gt;
&lt;p&gt;Here are screenshots showing the process of creating new invoices with the custom auto-numbering system in place. You’ll see how the plugin automatically assigns a unique invoice number based on the current fiscal year using the record creation date.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/ff4430f2-5351-42cf-9650-94093dc92ae9&quot; alt=&quot;New Invoice Creation&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By following this approach, you can create a highly configurable auto-numbering system that adapts to your organization’s fiscal year requirements while ensuring the uniqueness of each generated number. This method not only offers flexibility but also integrates seamlessly with Dataverse, allowing for custom logic and automation that out-of-the-box features may not provide.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/6792479578687180826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/08/custom-auto-number-in-dataverse-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/6792479578687180826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/6792479578687180826'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/08/custom-auto-number-in-dataverse-with.html' title='Custom Auto Number in Dataverse with Fiscal Year-Based Incrementing Using Plugin Code'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-2356869058674623814</id><published>2024-08-21T16:01:00.001-04:00</published><updated>2024-08-21T16:01:06.436-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cli"/><category scheme="http://www.blogger.com/atom/ns#" term="Connectors"/><category scheme="http://www.blogger.com/atom/ns#" term="customconnectors"/><category scheme="http://www.blogger.com/atom/ns#" term="dod"/><category scheme="http://www.blogger.com/atom/ns#" term="gcc"/><category scheme="http://www.blogger.com/atom/ns#" term="gcc high"/><category scheme="http://www.blogger.com/atom/ns#" term="gcch"/><category scheme="http://www.blogger.com/atom/ns#" term="government"/><category scheme="http://www.blogger.com/atom/ns#" term="government community cloud"/><category scheme="http://www.blogger.com/atom/ns#" term="json"/><category scheme="http://www.blogger.com/atom/ns#" term="paconn cli"/><category scheme="http://www.blogger.com/atom/ns#" term="power automate"/><category scheme="http://www.blogger.com/atom/ns#" term="power platform"/><category scheme="http://www.blogger.com/atom/ns#" term="Tools"/><title type='text'>Connecting the Paconn CLI Tool to GCC, GCCH, and DoD Environments for Power Platform Connectors</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/5a2755aa-9b80-4627-b02f-e2d78c8d996b&quot; alt=&quot;Connecting the Paconn CLI Tool to GCC, GCCH, and DoD Environments for Power Platform Connectors&quot;&gt;&lt;/p&gt;
&lt;p&gt;When working with the &lt;code&gt;paconn&lt;/code&gt; CLI tool to create and manage custom connectors in the Power Platform, it’s essential to configure your environment settings properly, especially when targeting different government cloud environments like GCC, GCC High, and DoD. In this article, we’ll guide you through setting up these configurations, including creating a &lt;code&gt;connectionSettings.json&lt;/code&gt; file for each environment, downloading a custom connector, and updating the connector’s settings for seamless management.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Azure Subscription&lt;/strong&gt;: You need an active Azure subscription to register an application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paconn CLI Tool&lt;/strong&gt;: Ensure you have the &lt;code&gt;paconn&lt;/code&gt; CLI tool installed. You can install it using Python’s pip:&lt;pre class=&quot; language-bash&quot;&gt;&lt;code class=&quot;prism  language-bash&quot;&gt;pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; paconn
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-1-create-an-azure-app-registration&quot;&gt;Step 1: Create an Azure App Registration&lt;/h2&gt;
&lt;p&gt;Begin by registering an application in Azure Active Directory (Azure AD) that will serve as the identity for your &lt;code&gt;paconn&lt;/code&gt; operations.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Navigate to Azure AD&lt;/strong&gt;: Sign in to the Azure portal and go to &lt;strong&gt;Azure Active Directory&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a New App Registration&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;App registrations&lt;/strong&gt; &amp;gt; &lt;strong&gt;New registration&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Provide a name, such as “Paconn Connector App.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redirect URI&lt;/strong&gt;: Skip this step as it is not required.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API Permissions&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The app automatically includes the &lt;code&gt;User.Read&lt;/code&gt; permission under Microsoft Graph. No additional API permissions are needed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/305136c5-4125-45f8-8bc0-3bdcfda94636&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Allow Public Client Flows&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;strong&gt;Authentication&lt;/strong&gt; &amp;gt; &lt;strong&gt;Advanced settings&lt;/strong&gt;, set &lt;strong&gt;Allow public client flows&lt;/strong&gt; to &lt;strong&gt;Yes&lt;/strong&gt;. This enables the device code flow, which &lt;code&gt;paconn&lt;/code&gt; uses for authentication.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/08eebd97-9231-4987-9371-5655272f8aa5&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Copy Your IDs&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;After registering the application, go to the &lt;strong&gt;Overview&lt;/strong&gt; section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy the &lt;strong&gt;Application (client) ID&lt;/strong&gt; and &lt;strong&gt;Directory (tenant) ID&lt;/strong&gt;. These values will be used in the &lt;code&gt;connectionSettings.json&lt;/code&gt; file in the next step.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/2005494b-492b-4865-8b23-e5cf3f4f9712&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By the end of this step, you should have your &lt;strong&gt;Application (client) ID&lt;/strong&gt; and &lt;strong&gt;Directory (tenant) ID&lt;/strong&gt; ready for configuring the connection settings in the following step.&lt;/p&gt;
&lt;h2 id=&quot;step-2-create-the-connectionsettings.json-file&quot;&gt;Step 2: Create the &lt;code&gt;connectionSettings.json&lt;/code&gt; File&lt;/h2&gt;
&lt;p&gt;Next, you’ll create a &lt;code&gt;connectionSettings.json&lt;/code&gt; file with specific values tailored for each environment. This file is crucial for authenticating and operating within your selected cloud.&lt;/p&gt;
&lt;h3 id=&quot;gcc-environment&quot;&gt;GCC Environment&lt;/h3&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;powerAppsUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://gov.api.powerapps.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;flowUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://gov.api.flow.microsoft.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  
  &lt;span class=&quot;token string&quot;&gt;&quot;resource&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://gov.service.powerapps.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;authorityUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://login.microsoftonline.com/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;clientId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Application (client) ID&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;tenant&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Directory (tenant) ID&amp;gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;gcc-high-environment&quot;&gt;GCC High Environment&lt;/h3&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;powerAppsUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://high.api.powerapps.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;flowUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://high.api.flow.microsoft.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;resource&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://high.service.powerapps.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;authorityUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://login.microsoftonline.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;clientId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Application (client) ID&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;tenant&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Directory (tenant) ID&amp;gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;dod-environment&quot;&gt;DoD Environment&lt;/h3&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;powerAppsUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://api.apps.appsplatform.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;flowUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://api.flow.appsplatform.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;resource&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://service.apps.appsplatform.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;authorityUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://login.microsoftonline.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;clientId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Application (client) ID&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;tenant&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Directory (tenant) ID&amp;gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;lt;Your Application (client) ID&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Your Directory (tenant) ID&amp;gt;&lt;/code&gt; with the values from your Azure App Registration.&lt;/p&gt;
&lt;h2 id=&quot;step-3-log-in-to-paconn&quot;&gt;Step 3: Log In to Paconn&lt;/h2&gt;
&lt;p&gt;Once you’ve configured your &lt;code&gt;connectionSettings.json&lt;/code&gt; file with the correct values for your environment, the next step is to log in to the &lt;code&gt;paconn&lt;/code&gt; CLI tool. This authentication process is essential for performing any subsequent operations with the tool.&lt;/p&gt;
&lt;p&gt;To log in, use the following command:&lt;/p&gt;
&lt;pre class=&quot; language-bash&quot;&gt;&lt;code class=&quot;prism  language-bash&quot;&gt;paconn login --settings connectionSettings.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command initiates the login process. Follow the prompts to authenticate using the device code flow. Once logged in, you’ll be ready to download and manage your custom connectors.&lt;/p&gt;
&lt;h2 id=&quot;step-4-download-a-custom-connector&quot;&gt;Step 4: Download a Custom Connector&lt;/h2&gt;
&lt;p&gt;After successfully logging in, you can download an existing custom connector from your environment. This process involves selecting the environment and the specific connector you want to work with.&lt;/p&gt;
&lt;p&gt;Run the following command:&lt;/p&gt;
&lt;pre class=&quot; language-bash&quot;&gt;&lt;code class=&quot;prism  language-bash&quot;&gt;paconn download --settings connectionSettings.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will prompt you to choose the environment based on your &lt;code&gt;connectionSettings.json&lt;/code&gt; file. After selecting the environment, you’ll be able to choose the connector you wish to download. The connector will be saved locally, along with a &lt;code&gt;settings.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/4720990c-d74f-44c3-af75-20489313e91b&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;step-5-update-the-connector&quot;&gt;Step 5: Update the Connector&lt;/h2&gt;
&lt;p&gt;Once you have downloaded the connector, you may need to update it. The &lt;code&gt;settings.json&lt;/code&gt; file downloaded with the connector needs to include the same settings you have in your &lt;code&gt;connectionSettings.json&lt;/code&gt; file. This ensures consistency when managing or updating the connector.&lt;/p&gt;
&lt;p&gt;Here’s what you need to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open the Downloaded &lt;code&gt;settings.json&lt;/code&gt; File&lt;/strong&gt;: Locate the file that was downloaded along with the connector.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Update the Fields&lt;/strong&gt;: Add or update the following fields with the values from your &lt;code&gt;connectionSettings.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;powerAppsUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://high.api.powerapps.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;flowUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://high.api.flow.microsoft.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;resource&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://high.service.powerapps.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;authorityUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://login.microsoftonline.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;clientId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Application (client) ID&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;tenant&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Directory (tenant) ID&amp;gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Save the File&lt;/strong&gt;: Ensure all changes are saved.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To apply the updates to the connector, run:&lt;/p&gt;
&lt;pre class=&quot; language-bash&quot;&gt;&lt;code class=&quot;prism  language-bash&quot;&gt;paconn update --settings settings.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will push the changes to the connector in the selected environment.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/2b8a4997-a344-4397-8f58-dcbe8ae5d38c&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;step-6-create-a-new-connector&quot;&gt;Step 6: Create a New Connector&lt;/h2&gt;
&lt;p&gt;Creating a new custom connector follows a similar process to updating an existing one, but with a few differences. Since it’s a new connector, you don’t need to include all the same properties in the &lt;code&gt;settings.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Here’s an example of a &lt;code&gt;settings.json&lt;/code&gt; file for a new connector:&lt;/p&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;environment&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;d9f0b637-5539-e256-9232-ecb5839cdb02&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;apiProperties&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;apiProperties.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;apiDefinition&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;apiDefinition.swagger.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;icon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;icon.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;powerAppsUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://high.api.powerapps.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;flowUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://high.api.flow.microsoft.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;authorityUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://login.microsoftonline.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;resource&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://high.service.powerapps.us/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;clientId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Application (client) ID&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;tenant&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;Your Directory (tenant) ID&amp;gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Key Differences&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No &lt;code&gt;connectorId&lt;/code&gt;&lt;/strong&gt;: Since this is a new connector, you don’t need to include the &lt;code&gt;connectorId&lt;/code&gt; property.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optional &lt;code&gt;script&lt;/code&gt; Property&lt;/strong&gt;: If you aren’t including custom code, you can omit the &lt;code&gt;script&lt;/code&gt; property from the &lt;code&gt;settings.json&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the &lt;code&gt;settings.json&lt;/code&gt; file is ready, you can create the new connector with the following command:&lt;/p&gt;
&lt;pre class=&quot; language-bash&quot;&gt;&lt;code class=&quot;prism  language-bash&quot;&gt;paconn create --settings settings.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a new custom connector in your specified environment using the provided settings.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When working with government cloud environments like GCC, GCC High, and DoD, it’s essential to consistently use &lt;code&gt;settings.json&lt;/code&gt; files for your operations with the &lt;code&gt;paconn&lt;/code&gt; CLI tool. This is because attempting to mix the &lt;code&gt;--settings&lt;/code&gt; option with other command-line arguments like &lt;code&gt;--api-prop&lt;/code&gt; and &lt;code&gt;--api-def&lt;/code&gt; will not work as expected.&lt;/p&gt;
&lt;p&gt;To ensure smooth operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keep a &lt;code&gt;connectionSettings.json&lt;/code&gt; file at your project root&lt;/strong&gt;: This file should contain the basic authentication and environment details.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Update the &lt;code&gt;settings.json&lt;/code&gt; file for each connector&lt;/strong&gt;: Tailor it with the specific details for each connector you manage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By following this approach, you’ll be able to effectively use the &lt;code&gt;paconn&lt;/code&gt; CLI tool to manage connectors across various government cloud environments.&lt;/p&gt;
&lt;p&gt;It’s also worth noting that while the &lt;a href=&quot;https://learn.microsoft.com/en-us/power-platform/developer/cli/reference/connector&quot;&gt;PAC CLI&lt;/a&gt; tool also supports commands for managing connectors, it is relatively new and still has some bugs. Until these issues are resolved, I recommend continuing with the &lt;code&gt;paconn&lt;/code&gt; method described here. However, the PAC CLI tool does offer a much easier way to connect to these clouds, so I’m optimistic about its potential in the future.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/2356869058674623814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/08/connecting-paconn-cli-tool-to-gcc-gcch.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/2356869058674623814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/2356869058674623814'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/08/connecting-paconn-cli-tool-to-gcc-gcch.html' title='Connecting the Paconn CLI Tool to GCC, GCCH, and DoD Environments for Power Platform Connectors'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-6635980753915711135</id><published>2024-06-24T13:51:00.002-04:00</published><updated>2024-06-24T13:51:20.027-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="automate"/><category scheme="http://www.blogger.com/atom/ns#" term="collectionformat"/><category scheme="http://www.blogger.com/atom/ns#" term="connector"/><category scheme="http://www.blogger.com/atom/ns#" term="Flow"/><category scheme="http://www.blogger.com/atom/ns#" term="openapi"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerAutomate"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerPlatform"/><category scheme="http://www.blogger.com/atom/ns#" term="swagger"/><category scheme="http://www.blogger.com/atom/ns#" term="workflow"/><title type='text'>Overcoming OpenAPI 2.0 `multi` CollectionFormat Challenges in Power Automate Custom Connectors</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/02ae64d9-15d4-4e94-9d7f-f33f85b56450&quot; alt=&quot;Overcoming OpenAPI 2.0  CollectionFormat Challenges in Power Automate Custom Connectors&quot;&gt;&lt;/p&gt;
&lt;p&gt;Integrating APIs into Power Automate flows often requires creating custom connectors, a process that can encounter challenges with certain API specifications. Specifically, the OpenAPI 2.0 specification allows array and multi-value parameters to be passed in various formats, including the &lt;code&gt;multi&lt;/code&gt; collection format. This format is particularly troublesome for Power Automate’s Custom Connector wizard, which does not support it natively. This article outlines the issue and provides a detailed workaround using custom code components and modifying input parameters, ensuring seamless API integration.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge-with-multi-collectionformat&quot;&gt;The Challenge with &lt;code&gt;multi&lt;/code&gt; CollectionFormat&lt;/h2&gt;
&lt;p&gt;The OpenAPI 2.0 specification introduces several collection formats for array parameters, with &lt;code&gt;multi&lt;/code&gt; being one of them. This format allows multiple values for the same parameter to be passed by repeating the parameter’s name in the query string, which is not directly supported in Power Automate Custom Connectors. Attempting to import an OpenAPI specification using the &lt;code&gt;multi&lt;/code&gt; format results in an error, blocking the creation of the custom connector and hindering integration efforts.&lt;/p&gt;
&lt;h2 id=&quot;error-encountered&quot;&gt;Error Encountered&lt;/h2&gt;
&lt;p&gt;Developers face a specific error when the Custom Connector wizard encounters a &lt;code&gt;multi&lt;/code&gt; collection format:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error: paths/~1v1~1preview~1records~1person/get/parameters/1/collectionFormat: The &#39;collectionFormat&#39; keyword value &#39;Multi&#39; is not supported.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This error signifies the inability of the wizard to process the specified collection format, necessitating a workaround to proceed with the connector creation.&lt;/p&gt;
&lt;h2 id=&quot;a-workaround&quot;&gt;A Workaround&lt;/h2&gt;
&lt;h3 id=&quot;step-1-modifying-parameter-types-from-array-to-string&quot;&gt;Step 1: Modifying Parameter Types from Array to String&lt;/h3&gt;
&lt;p&gt;The first part of the workaround involves changing the input parameters’ types in the OpenAPI definition from arrays to strings. This modification aims to bypass the Custom Connector wizard’s limitations by allowing the input of multiple values in a single, comma-separated string.&lt;/p&gt;
&lt;h4 id=&quot;original-array-parameter-definition&quot;&gt;Original Array Parameter Definition&lt;/h4&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;collectionFormat&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;multi&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;List of services to filter facilities by the services they offer.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;x-ms-summary&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Services Offered&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;in&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;services[]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;array&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;modified-string-parameter-definition&quot;&gt;Modified String Parameter Definition&lt;/h4&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A comma-separated list of services to filter facilities by the services they offer.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;x-ms-summary&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Services Offered&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;in&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;services[]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-leveraging-custom-code-components&quot;&gt;Step 2: Leveraging Custom Code Components&lt;/h3&gt;
&lt;p&gt;To handle the modified string parameters correctly and support the original intention of passing multiple values, custom code components within the connector are utilized. These components programmatically adjust the request’s query string, ensuring that the API receives the parameters in the expected &lt;code&gt;multi&lt;/code&gt; format.&lt;/p&gt;
&lt;p&gt;For detailed guidance on writing code for Power Automate Custom Connectors, visit &lt;a href=&quot;https://learn.microsoft.com/en-us/connectors/custom-connectors/write-code&quot;&gt;Microsoft’s official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;custom-code-example&quot;&gt;Custom Code Example&lt;/h4&gt;
&lt;pre class=&quot; language-csharp&quot;&gt;&lt;code class=&quot;prism  language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Script&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ScriptBase
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; Dictionary&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; specialHandlingMap &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GetFacilities&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;facilityIds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;services[]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bbox[]&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GetFacilityServicesById&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;serviceIds&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GetNearbyFacilities&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;services[]&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; Task&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HttpResponseMessage&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ExecuteAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; operationId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OperationId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;specialHandlingMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;TryGetValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operationId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; queryParamNames&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; HttpUtility&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ParseQueryString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RequestUri&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Query&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; paramName &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; queryParamNames&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AllKeys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;paramName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; values &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; query&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;paramName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    query&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;paramName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                        query&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;paramName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; uriBuilder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UriBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RequestUri&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; query&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RequestUri &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; uriBuilder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Uri&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SendAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CancellationToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ConfigureAwait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/5b05e8ba-7a08-4897-9ab4-f6d1fe6bc710&quot; alt=&quot;Image of Custom Connector Code Step&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;importance-of-descriptive-parameter-descriptions&quot;&gt;Importance of Descriptive Parameter Descriptions&lt;/h3&gt;
&lt;p&gt;Adjusting the parameter types necessitates clear and descriptive parameter descriptions to guide users on the correct input format. Descriptions like “A comma-separated list of services…” ensure users understand how to format their input, enhancing usability and reducing errors.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By modifying the OpenAPI definition to change parameter types from arrays to strings and utilizing custom code components within Power Automate Custom Connectors, developers can overcome the limitations posed by the lack of support for the &lt;code&gt;multi&lt;/code&gt; collection format. This comprehensive workaround ensures that custom connectors remain a powerful tool for integrating a wide range of APIs into Power Automate flows, even when facing complex parameter formatting challenges.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/6635980753915711135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/06/overcoming-openapi-20-multi.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/6635980753915711135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/6635980753915711135'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/06/overcoming-openapi-20-multi.html' title='Overcoming OpenAPI 2.0 `multi` CollectionFormat Challenges in Power Automate Custom Connectors'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-8080557741545593425</id><published>2024-06-14T10:13:00.002-04:00</published><updated>2024-06-14T10:13:01.621-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="airgap"/><category scheme="http://www.blogger.com/atom/ns#" term="Firewall"/><category scheme="http://www.blogger.com/atom/ns#" term="install"/><category scheme="http://www.blogger.com/atom/ns#" term="modules"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerShell"/><category scheme="http://www.blogger.com/atom/ns#" term="ps"/><category scheme="http://www.blogger.com/atom/ns#" term="script"/><title type='text'>Installing PowerShell Modules in Firewalled and Air-Gapped Systems</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/c2927200-441b-4645-9689-d82038fb3a5e&quot; alt=&quot;Installing PowerShell Modules in Firewalled and Air-Gapped Systems&quot;&gt;&lt;/p&gt;
&lt;p&gt;Managing IT environments with limited or no internet access, such as firewalled systems or air-gapped setups, presents unique challenges. One of the critical tasks in such environments is the installation and usage of PowerShell modules, which often require internet access for download and updates. This guide provides a method to facilitate the offline installation of PowerShell modules using custom scripts and includes a practical example of managing Power Platform environments by limiting developer environments.&lt;/p&gt;
&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;
&lt;p&gt;Firewalled systems have restricted internet access, necessitating special methods to manage and configure software. Air-gapped systems are completely isolated from the internet, making direct downloads impossible. In such environments, administrators need to manually transfer and install PowerShell modules to manage various tasks effectively.&lt;/p&gt;
&lt;h2 id=&quot;step-by-step-guide&quot;&gt;Step-by-Step Guide&lt;/h2&gt;
&lt;h3 id=&quot;step-1-prepare-the-powershell-module-for-offline-use&quot;&gt;Step 1: Prepare the PowerShell Module for Offline Use&lt;/h3&gt;
&lt;p&gt;The first script, &lt;strong&gt;PowerShellModuleOfflinePackager.ps1&lt;/strong&gt;, downloads the required PowerShell module and its dependencies from an internet-connected machine, then packages them into a zip file for easy transfer.&lt;/p&gt;
&lt;p&gt;Here’s the script &lt;a href=&quot;https://github.com/rwilson504/PowerShell/blob/main/PowerShell/PowerShellModuleOfflinePackager.ps1&quot;&gt;(Get it on Github)&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot; language-powershell&quot;&gt;&lt;code class=&quot;prism  language-powershell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;#
.SYNOPSIS
Downloads the most current version of a PowerShell NuGet package or a specified version and extracts it for manual installation.

.DESCRIPTION
This script downloads the specified or latest version of a NuGet package from the PowerShell Gallery and extracts it to a specified or default output directory. 
If no version is specified, the latest version of the package is downloaded. If no output directory is specified, the script 
creates a default output folder in the script&#39;s directory. After extracting the packages, the script can optionally compress 
the package folders into a single ZIP file for easy transfer to an offline system. If the zipping is done, it also deletes the 
folders created by Save-Package unless the SkipZip parameter is specified.

.PARAMETER Name
The ID of the NuGet package to download.

.PARAMETER Version
The version of the NuGet package to download. If not specified, the latest version will be downloaded.

.PARAMETER OutputDir
The directory where the package will be downloaded and extracted. If not specified, a folder named &#39;NuGetPackages&#39; will be 
created in the directory where the script is being run.

.PARAMETER SkipZip
If specified, the script will not compress the package folders into a ZIP file.

.EXAMPLE
.\PowerShellModuleOfflinePackager.ps1 -Name &quot;PSReadline&quot;

Downloads the latest version of the PSReadline package, extracts it to the default output directory, and compresses the extracted files into a ZIP file.

.EXAMPLE
.\PowerShellModuleOfflinePackager.ps1 -Name &quot;PSReadline&quot; -Version &quot;2.2.0&quot;

Downloads version 2.2.0 of the PSReadline package, extracts it to the default output directory, and compresses the extracted files into a ZIP file.

.EXAMPLE
.\PowerShellModuleOfflinePackager.ps1 -Name &quot;PSReadline&quot; -OutputDir &quot;C:\MyPackages&quot;

Downloads the latest version of the PSReadline package, extracts it to C:\MyPackages, and compresses the extracted files into a ZIP file.

.EXAMPLE
.\PowerShellModuleOfflinePackager.ps1 -Name &quot;PSReadline&quot; -Version &quot;2.2.0&quot; -OutputDir &quot;C:\MyPackages&quot;

Downloads version 2.2.0 of the PSReadline package, extracts it to C:\MyPackages, and compresses the extracted files into a ZIP file.

.EXAMPLE
.\PowerShellModuleOfflinePackager.ps1 -Name &quot;PSReadline&quot; -SkipZip

Downloads the latest version of the PSReadline package, extracts it to the default output directory, but does not compress the extracted files into a ZIP file.
#&amp;gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Mandatory = &lt;span class=&quot;token boolean&quot;&gt;$true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HelpMessage = &lt;span class=&quot;token string&quot;&gt;&quot;The ID of the NuGet package to download.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$Name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HelpMessage = &lt;span class=&quot;token string&quot;&gt;&quot;The version of the NuGet package to download. If not specified, the latest version will be downloaded.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$Version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HelpMessage = &lt;span class=&quot;token string&quot;&gt;&quot;The directory where the package will be downloaded and extracted. If not specified, a folder named &#39;NuGetPackages&#39; will be created in the directory where the script is being run.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$OutputDir&lt;/span&gt; = &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$PSScriptRoot&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HelpMessage = &lt;span class=&quot;token string&quot;&gt;&quot;If specified, the script will not compress the package folders into a ZIP file.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[switch]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$SkipZip&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$packageDir&lt;/span&gt; = &lt;span class=&quot;token string&quot;&gt;&lt;span class=&quot;token function&quot;&gt;&quot;$&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$OutputDir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;\NuGetPackages&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Create the output directory if it doesn&#39;t exist&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-Not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$PackageDir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ItemType Directory &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$PackageDir&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Force
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# If no version is specified, find the latest version&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-Not&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$Version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fetching the latest version of &lt;span class=&quot;token variable&quot;&gt;$Name&lt;/span&gt; from the PowerShell Gallery...&quot;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$latestPackage&lt;/span&gt; = Find&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Package &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Name &lt;span class=&quot;token variable&quot;&gt;$Name&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Source PSGallery &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Sort-Object&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Property Version &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Descending &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Select-Object&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;First 1
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$latestPackage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$Version&lt;/span&gt; = &lt;span class=&quot;token variable&quot;&gt;$latestPackage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Version
        &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Latest version of &lt;span class=&quot;token variable&quot;&gt;$Name&lt;/span&gt; is &lt;span class=&quot;token variable&quot;&gt;$Version&lt;/span&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Package &lt;span class=&quot;token variable&quot;&gt;$Name&lt;/span&gt; not found in the PowerShell Gallery.&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;exit&lt;/span&gt; 1
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Download and extract the specified version of the package&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Downloading and extracting &lt;span class=&quot;token variable&quot;&gt;$Name&lt;/span&gt; version &lt;span class=&quot;token variable&quot;&gt;$Version&lt;/span&gt;...&quot;&lt;/span&gt;
Save&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Package &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Name &lt;span class=&quot;token variable&quot;&gt;$Name&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;RequiredVersion &lt;span class=&quot;token variable&quot;&gt;$Version&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$packageDir&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Source PSGallery

&lt;span class=&quot;token comment&quot;&gt;# Compress the extracted package folders into a single ZIP file, if SkipZip is not specified&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-Not&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$SkipZip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$zipFileName&lt;/span&gt; = &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$Name&lt;/span&gt;-&lt;span class=&quot;token variable&quot;&gt;$Version&lt;/span&gt;.zip&quot;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$zipFilePath&lt;/span&gt; = &lt;span class=&quot;token function&quot;&gt;Join-Path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$OutputDir&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ChildPath &lt;span class=&quot;token variable&quot;&gt;$zipFileName&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Compressing the package folders into &lt;span class=&quot;token variable&quot;&gt;$zipFilePath&lt;/span&gt;...&quot;&lt;/span&gt;
    Compress&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Archive &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$packageDir&lt;/span&gt;\*&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;DestinationPath &lt;span class=&quot;token variable&quot;&gt;$zipFilePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Force

    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Packages compressed into &lt;span class=&quot;token variable&quot;&gt;$zipFilePath&lt;/span&gt;&quot;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# Remove the extracted folders after zipping&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cleaning up extracted folders...&quot;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Remove-Item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$packageDir&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Recurse &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Force

    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cleanup complete.&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Skipping compression and cleanup of the package folders.&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Example Usage:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot; language-powershell&quot;&gt;&lt;code class=&quot;prism  language-powershell&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;\PowerShellModuleOfflinePackager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ps1 &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Name &lt;span class=&quot;token string&quot;&gt;&quot;Microsoft.PowerApps.Administration.PowerShell&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;OutputDir &lt;span class=&quot;token string&quot;&gt;&quot;C:\ModulePackages&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-transfer-the-zip-file-to-the-air-gapped-or-firewalled-system&quot;&gt;Step 2: Transfer the Zip File to the Air-Gapped or Firewalled System&lt;/h3&gt;
&lt;p&gt;Copy the generated zip file and the second script, &lt;strong&gt;ExtractModuleToDirectory.ps1&lt;/strong&gt;, to the air-gapped or firewalled system using a USB drive or other secure method.&lt;/p&gt;
&lt;h3 id=&quot;step-3-extract-and-install-the-powershell-module&quot;&gt;Step 3: Extract and Install the PowerShell Module&lt;/h3&gt;
&lt;p&gt;The second script, &lt;strong&gt;ExtractModuleToDirectory.ps1&lt;/strong&gt;, extracts the PowerShell module from the zip file to a specified directory within the &lt;code&gt;PSModulePath&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;p&gt;Here’s the script &lt;a href=&quot;https://github.com/rwilson504/PowerShell/blob/main/PowerShell/ExtractModuleToDirectory.ps1&quot;&gt;(Get it on Github)&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot; language-powershell&quot;&gt;&lt;code class=&quot;prism  language-powershell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;#
.SYNOPSIS
Extracts a PowerShell module ZIP file to a selected PowerShell module directory.

.DESCRIPTION
This script is used on an offline system to extract the contents of a PowerShell module ZIP file to a specified PowerShell module directory. 
The script lists all the available PowerShell module directories, allows the user to select one, and then extracts the ZIP file contents to that directory. 
If the -Force parameter is specified, existing files will be overwritten.

.PARAMETER ZipFilePath
The path to the ZIP file containing the PowerShell module.

.PARAMETER Force
If specified, existing files in the target directory will be overwritten.

.EXAMPLE
.\ExtractModuleToDirectory.ps1 -ZipFilePath &quot;C:\Modules\PSReadline-2.2.0.zip&quot;

Lists available PowerShell module directories, prompts the user to select one, and extracts the contents of PSReadline-2.2.0.zip to the selected directory.

.EXAMPLE
.\ExtractModuleToDirectory.ps1 -ZipFilePath &quot;C:\Modules\PSReadline-2.2.0.zip&quot; -Force

Lists available PowerShell module directories, prompts the user to select one, and extracts the contents of PSReadline-2.2.0.zip to the selected directory, overwriting existing files if they already exist.
#&amp;gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Mandatory = &lt;span class=&quot;token boolean&quot;&gt;$true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HelpMessage = &lt;span class=&quot;token string&quot;&gt;&quot;The path to the ZIP file containing the PowerShell module.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$ZipFilePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HelpMessage = &lt;span class=&quot;token string&quot;&gt;&quot;If specified, existing files in the target directory will be overwritten.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token namespace&quot;&gt;[switch]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$Force&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Function to get all available PowerShell module directories&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; Get&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ModulePaths &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$modulePaths&lt;/span&gt; = &lt;span class=&quot;token variable&quot;&gt;$env&lt;/span&gt;:PSModulePath &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;split &lt;span class=&quot;token string&quot;&gt;&#39;;&#39;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$modulePaths&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Function to display a menu and get user selection&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; Show&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Menu &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token namespace&quot;&gt;[string[]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$MenuItems&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt; = 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-lt&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$MenuItems&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt;+&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Write-Host&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[{0}] {1}&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;f &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$MenuItems&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token variable&quot;&gt;$selection&lt;/span&gt; = &lt;span class=&quot;token function&quot;&gt;Read-Host&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Please select a directory (enter the number)&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;[int]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$selection&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; 1
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Verify that the ZIP file exists&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-Not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$ZipFilePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The ZIP file &#39;&lt;span class=&quot;token variable&quot;&gt;$ZipFilePath&lt;/span&gt;&#39; does not exist.&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;exit&lt;/span&gt; 1
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Get available PowerShell module directories&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$modulePaths&lt;/span&gt; = Get&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ModulePaths

&lt;span class=&quot;token comment&quot;&gt;# Display the menu&lt;/span&gt;

 and get user selection
&lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Available PowerShell module directories:&quot;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$selectionIndex&lt;/span&gt; = Show&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Menu &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;MenuItems &lt;span class=&quot;token variable&quot;&gt;$modulePaths&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Validate the selection&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$selectionIndex&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-lt&lt;/span&gt; 0 &lt;span class=&quot;token operator&quot;&gt;-or&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$selectionIndex&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-ge&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$modulePaths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Invalid selection. Exiting.&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;exit&lt;/span&gt; 1
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$targetDir&lt;/span&gt; = &lt;span class=&quot;token variable&quot;&gt;$modulePaths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$selectionIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Ensure the target directory exists&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-Not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Test-Path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$targetDir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The directory &#39;&lt;span class=&quot;token variable&quot;&gt;$targetDir&lt;/span&gt;&#39; does not exist. Creating it...&quot;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;New-Item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ItemType Directory &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$targetDir&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Force
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Extract the ZIP file to the selected directory&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Extracting the contents of &#39;&lt;span class=&quot;token variable&quot;&gt;$ZipFilePath&lt;/span&gt;&#39; to &#39;&lt;span class=&quot;token variable&quot;&gt;$targetDir&lt;/span&gt;&#39;...&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Add-Type&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;AssemblyName System&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IO&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Compression&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;FileSystem
    &lt;span class=&quot;token namespace&quot;&gt;[System.IO.Compression.ZipFile]&lt;/span&gt;::ExtractToDirectory&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$ZipFilePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$targetDir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$Force&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Extraction complete.&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Write-Error&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;An error occurred while extracting the ZIP file: &lt;span class=&quot;token variable&quot;&gt;$_&lt;/span&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Exception&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Message &lt;span class=&quot;token operator&quot;&gt;-match&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;already exists&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Write-Output&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Consider using the -Force parameter to overwrite existing files.&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Example Usage:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot; language-powershell&quot;&gt;&lt;code class=&quot;prism  language-powershell&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;\ExtractModuleToDirectory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ps1 &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ZipFilePath &lt;span class=&quot;token string&quot;&gt;&quot;D:\ModulePackages\Microsoft.PowerApps.Administration.PowerShell.zip&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Force
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;practical-example-limiting-power-platform-developer-environments&quot;&gt;Practical Example: Limiting Power Platform Developer Environments&lt;/h2&gt;
&lt;p&gt;With the PowerShell module installed, you can manage Power Platform environments, including restricting the creation of developer environments. This example demonstrates how to connect to Power Platform and disable developer environments using the installed PowerShell module.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Connect to Power Platform&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For firewalled systems, specify the appropriate &lt;code&gt;-Environment&lt;/code&gt; parameter to connect to your Power Platform environment. For government cloud environments, adjust the &lt;code&gt;-Endpoint&lt;/code&gt; parameter accordingly (e.g., &lt;code&gt;usgov&lt;/code&gt; for GCC Moderate, &lt;code&gt;usgovhigh&lt;/code&gt; for GCC High, or &lt;code&gt;dod&lt;/code&gt; for GCC DOD).&lt;/p&gt;
&lt;pre class=&quot; language-powershell&quot;&gt;&lt;code class=&quot;prism  language-powershell&quot;&gt;Add&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;PowerAppsAccount &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Endpoint &lt;span class=&quot;token string&quot;&gt;&quot;usgov&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Disable Developer Environments&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Use the following command to disable the creation of developer environments:&lt;/p&gt;
&lt;pre class=&quot; language-powershell&quot;&gt;&lt;code class=&quot;prism  language-powershell&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$requestBody&lt;/span&gt; = &lt;span class=&quot;token namespace&quot;&gt;[pscustomobject]&lt;/span&gt;@&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    powerPlatform = &lt;span class=&quot;token namespace&quot;&gt;[pscustomobject]&lt;/span&gt;@&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        governance = &lt;span class=&quot;token namespace&quot;&gt;[pscustomobject]&lt;/span&gt;@&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            disableDeveloperEnvironmentCreationByNonAdminUsers  = &lt;span class=&quot;token boolean&quot;&gt;$true&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;TenantSettings &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;RequestBody &lt;span class=&quot;token variable&quot;&gt;$requestBody&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This configuration helps maintain control over the Power Platform environments, ensuring that only authorized users can create developer environments.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Managing PowerShell modules in firewalled or air-gapped systems requires additional steps, but with the right tools, it can be efficiently achieved. By packaging and transferring PowerShell modules offline, you can maintain the security of your environment while still being able to manage it effectively. The provided scripts simplify this process, ensuring that your isolated systems remain functional and secure. Additionally, the practical example of managing Power Platform environments demonstrates how to apply these techniques to real-world scenarios.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/8080557741545593425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/06/installing-powershell-modules-in.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/8080557741545593425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/8080557741545593425'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/06/installing-powershell-modules-in.html' title='Installing PowerShell Modules in Firewalled and Air-Gapped Systems'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-1937541655724509671</id><published>2024-03-08T15:48:00.002-05:00</published><updated>2024-03-08T15:48:23.284-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Authentication"/><category scheme="http://www.blogger.com/atom/ns#" term="azuredevops"/><category scheme="http://www.blogger.com/atom/ns#" term="basicauthentication"/><category scheme="http://www.blogger.com/atom/ns#" term="dataflow"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="integration"/><category scheme="http://www.blogger.com/atom/ns#" term="pat"/><category scheme="http://www.blogger.com/atom/ns#" term="powerbi"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerPlatform"/><category scheme="http://www.blogger.com/atom/ns#" term="powerquery"/><title type='text'>Syncing Azure DevOps Work Item Status to Microsoft Dataverse with Dataflows</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/de09fe1f-3949-4bb1-abde-587528e9d2ef&quot; alt=&quot;Syncing Azure DevOps Work Item Status to Microsoft Dataverse with Dataflows&quot;&gt;&lt;/p&gt;
&lt;p&gt;In today’s fast-paced development environments, seamless integration between customer and development tracking systems can be crucial for maintaining transparency, efficiency, and alignment across teams. Our objective centers around a scenario faced by some organizations: &lt;strong&gt;synchronizing customer requirements captured by staff in Microsoft Dataverse with the development work tracked in Azure DevOps (ADO)&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;business-case-and-goals&quot;&gt;Business Case and Goals&lt;/h2&gt;
&lt;p&gt;Our service teams interact with customers to capture requirements, which are then stored in Microsoft Dataverse. As development plans are formulated, corresponding ADO items are created for each requirement. The primary goals of our integration efforts are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Visibility for Service Staff:&lt;/strong&gt; Enable service teams to view the status of the ADO items associated with customer requirements directly within Dataverse. This integration aims to eliminate the need for service staff to navigate away from their primary system to check development progress, fostering a more efficient and cohesive workflow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enhanced Reporting Capabilities:&lt;/strong&gt; By syncing ADO item statuses with Dataverse, we unlock the potential for advanced querying capabilities within Dataverse. This allows for the creation of detailed reports and analytics on development progress, directly correlating customer requirements with development statuses.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Streamlined Operations:&lt;/strong&gt; The integration ensures that information flow between customer service and development teams is automated and streamlined. This not only saves time but also reduces the potential for errors in tracking and reporting on the progress of development work against customer requirements.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By achieving these goals, we aim to enhance the operational efficiency of our teams, improve the accuracy of our reporting, and ultimately deliver a better service experience to our customers. The following sections detail the technical journey we embarked on to realize this integration, navigating through authentication challenges, API limitations, and leveraging Power BI Dataflows as a creative solution to synchronize ADO Work Items with Microsoft Dataverse.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge&quot;&gt;The Challenge&lt;/h2&gt;
&lt;p&gt;Our objective to synchronize specific ADO Work Item fields with a Dataverse table for enriched reporting introduced a multifaceted set of challenges:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authentication with Personal Access Token (PAT):&lt;/strong&gt; Although ADO supports various authentication methods, our scenario necessitated the use of a PAT for its flexibility and security. Integrating this with Dataverse Dataflows presented an initial obstacle, as these dataflows do not natively support basic authentication, which is essential when using PATs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Inconsistent Behavior in Authentication:&lt;/strong&gt; Initial attempts to directly set the Authorization header in the &lt;code&gt;Web.Contents&lt;/code&gt; function and configure the connection as Anonymous were met with errors, reporting incorrect credentials. This issue underscored the subtle complexities of handling authentication within Power BI and Dataverse integrations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Challenges with Data Source Configuration:&lt;/strong&gt; Adding a new data source via the Web API connector and attempting to use the PAT solely in the password field (leaving the username empty) resulted in invalid credentials errors. However, starting with a blank query and then incorporating the &lt;code&gt;Web.Contents&lt;/code&gt; function with Basic authentication—using only the PAT for authentication—eventually proved successful. This discovery process highlighted the trial and error involved in establishing a viable authentication method.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API Limitations:&lt;/strong&gt; The &lt;code&gt;wit/workitemsbatch&lt;/code&gt; endpoint, ideal for our purposes, does not support &lt;code&gt;POST&lt;/code&gt; requests when authenticating with basic authentication via the &lt;code&gt;Web.Contents&lt;/code&gt; function in M code. This limitation, along with a constraint on processing only 200 records at a time, required a strategic approach to batch processing and API requests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Absence of a Direct Azure DevOps Connector in Dataflows:&lt;/strong&gt; Unlike Power BI Desktop, Dataflows lacks an out-of-the-box connector for Azure DevOps, adding an extra layer of complexity. This required us to utilize the Azure DevOps REST API, a robust yet initially daunting interface for those unfamiliar with its intricacies. Learning to navigate and effectively leverage the REST API took time but was essential for achieving our integration goals.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For comprehensive guidance on utilizing the Azure DevOps REST API, including accessing work items, repositories, and other essential services, refer to the official API documentation: &lt;a href=&quot;https://learn.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-rest-7.2&amp;amp;viewFallbackFrom=azure-devops-rest-7.1&quot;&gt;Azure DevOps Services REST API Reference&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;/h2&gt;
&lt;p&gt;Despite these obstacles, a solution was crafted through a series of steps, leveraging Power BI Dataflows as an intermediary to handle the data transformation and syncing process.&lt;/p&gt;
&lt;h3 id=&quot;step-1-create-and-configure-the-pat&quot;&gt;Step 1: Create and Configure the PAT&lt;/h3&gt;
&lt;p&gt;The initial and crucial step in syncing Azure DevOps (ADO) Work Item states with Microsoft Dataverse involves creating a Personal Access Token (PAT) within Azure DevOps. This PAT serves as the authentication mechanism for accessing ADO’s APIs securely.&lt;/p&gt;
&lt;p&gt;Here’s a step-by-step guide to ensure your PAT is properly configured:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Navigate to Azure DevOps:&lt;/strong&gt; Go to your Azure DevOps organization’s user settings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Access Security:&lt;/strong&gt; Find and click on the “Personal access tokens” option under the security settings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create New Token:&lt;/strong&gt; Select “New Token.” Ensure you provide it with a descriptive name that clearly indicates its usage, such as “DataverseSync.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set Expiry:&lt;/strong&gt; Choose an appropriate expiry date for the token according to your project duration and security policies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assign Scopes:&lt;/strong&gt; Assign the necessary scopes for the PAT. For this integration, you must at least include permissions to read Work Items. If your integration requires accessing other ADO API endpoints, make sure to include those permissions as well.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For a detailed walkthrough on creating a PAT in Azure DevOps, refer to the official documentation available at &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate&quot;&gt;Create Personal Access Tokens to authenticate access&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Remember, the PAT is sensitive and should be securely stored. It provides direct access to your Azure DevOps services and should only be shared with trusted individuals and applications.&lt;/p&gt;
&lt;h3 id=&quot;step-2-implement-power-bi-dataflow&quot;&gt;Step 2: Implement Power BI Dataflow&lt;/h3&gt;
&lt;p&gt;After securing your PAT, the next step is to establish a Power BI dataflow that will serve as the intermediary for transferring and transforming data between Azure DevOps (ADO) and Microsoft Dataverse. This involves creating custom functions within Power BI to handle data batching and API calls. Follow these detailed instructions to set up your Power BI dataflow:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/1d1a23f1-448c-4c34-acee-b8c51087ac4b&quot; alt=&quot;Copmleted Dataflow&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;creating-a-new-blank-query-for-batching&quot;&gt;Creating a New Blank Query for Batching&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Open Power BI Desktop:&lt;/strong&gt; Start by opening Power BI Desktop and navigating to the Data view.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create a New Query:&lt;/strong&gt; Go to the Home tab, click on “Transform Data,” and then select “Data Source Settings.” Here, choose to create a new blank query by selecting “New Source” &amp;gt; “Blank Query.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enter the SplitListIntoBatch Function Code:&lt;/strong&gt; In the query editor that opens, enter the following M code to create the &lt;code&gt;SplitListIntoBatch&lt;/code&gt; function. This function is designed to split your data into smaller batches for processing.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot; language-m&quot;&gt;&lt;code class=&quot;prism  language-m&quot;&gt;// Function to split a list into smaller lists of a given size
(list as list, batchSize as number) as list =&amp;gt;
let
    // Calculate the number of batches
    numBatches = Number.RoundUp(List.Count(list) / batchSize),
    // Generate a list of batches
    batches = List.Transform(
        {0..numBatches - 1}, each List.Skip(list, _ * batchSize) &amp;amp; List.FirstN(list, batchSize)
    )
in
    batches
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;Name Your Query:&lt;/strong&gt; Rename the query to &lt;code&gt;SplitListIntoBatch&lt;/code&gt; by right-clicking on the query name in the left pane and selecting “Rename.”&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;creating-the-function-for-azure-devops-api-calls&quot;&gt;Creating the Function for Azure DevOps API Calls&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Add Another Blank Query:&lt;/strong&gt; Repeat the steps to add a new blank query, this time for making API calls to Azure DevOps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enter the GetWorkItems Function Code:&lt;/strong&gt; In the new blank query, copy the following M code to create the &lt;code&gt;GetWorkItems&lt;/code&gt; function. Adjust the &lt;code&gt;adoOrganization&lt;/code&gt; and &lt;code&gt;adoProject&lt;/code&gt; variables as necessary for your Azure DevOps instance.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot; language-m&quot;&gt;&lt;code class=&quot;prism  language-m&quot;&gt;(ids as list) as table =&amp;gt;
let
    // Convert the list of IDs to a comma-separated string
    idsString = Text.Combine(List.Transform(ids, Text.From), &quot;,&quot;),

    // Specify the fields to retrieve
    fields = &quot;System.Title,System.State&quot;,
    
    //ADO Organization Name
    adoOrganization = &quot;PowerAppsRAW&quot;,

    //ADO Project Name
    adoProject = &quot;My%20Project&quot;,

    // Set up API URL and headers
    apiUrl = &quot;https://dev.azure.com/&quot; &amp;amp; adoOrganization &amp;amp; &quot;/&quot; &amp;amp; adoProject &amp;amp; &quot;/_apis/wit/workitems&quot;,
    headers = [
        #&quot;Content-Type&quot; = &quot;application/json&quot;
    ],
    
    // Make the Get request
    Source = Json.Document(Web.Contents(apiUrl, [
        Headers = headers,
        Query = [
            #&quot;api-version&quot; = &quot;7.1&quot;,
            ids = idsString,
            fields = fields
        ]
    ])),
    
    // Convert &#39;value&#39; array to a table
    workItemsTable = Table.FromList(Source[value], Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    
    // Expand the top-level properties of each work item
    expandedTable = Table.ExpandRecordColumn(workItemsTable, &quot;Column1&quot;, {&quot;id&quot;, &quot;rev&quot;, &quot;fields&quot;, &quot;url&quot;}, {&quot;ID&quot;, &quot;Revision&quot;, &quot;Fields&quot;, &quot;URL&quot;}),
    
    // Dynamically expand all fields within the &#39;Fields&#39; column
    // Get the list of field names dynamically from the first row (assuming consistency across rows)
    fieldNames = Record.FieldNames(expandedTable{0}[Fields]),
    fullyExpandedTable = Table.ExpandRecordColumn(expandedTable, &quot;Fields&quot;, fieldNames, fieldNames)
in
    fullyExpandedTable
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;Name Your Query:&lt;/strong&gt; This time, rename the query to &lt;code&gt;GetWorkItems&lt;/code&gt; to reflect its purpose.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After completing these steps, you’ve successfully created the necessary functions within your Power BI Dataflow. These functions will allow you to batch process your Dataverse data and fetch updated work item information from Azure DevOps, respectively.&lt;/p&gt;
&lt;h2 id=&quot;step-3-efficiently-combining-data-for-synchronization&quot;&gt;Step 3: Efficiently Combining Data for Synchronization&lt;/h2&gt;
&lt;p&gt;As we proceed to optimize our synchronization process, it’s important to address the configuration needed when actually running the query. This step ensures that we only query Azure DevOps for updates on ADO item IDs present in our Dataverse environment, significantly reducing Azure API usage. Below, we’ve provided sample code and now include essential guidance on configuring the connection for the Azure DevOps (ADO) URL.&lt;/p&gt;
&lt;h3 id=&quot;efficient-data-fetching-and-processing&quot;&gt;Efficient Data Fetching and Processing&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initiate Data Retrieval:&lt;/strong&gt; Start the process by creating a new query for the &lt;code&gt;new_customerrequirement&lt;/code&gt; table in Dataverse to identify the specific ADO item IDs that require updates. This step determines the scope of our synchronization efforts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Apply Batch Processing:&lt;/strong&gt; Utilize the &lt;code&gt;SplitListIntoBatch&lt;/code&gt; function to divide the list of relevant IDs into smaller batches. This approach is crucial for managing API call volume and adhering to Azure DevOps API rate limits.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fetch Updated Work Item Information:&lt;/strong&gt; With each batch, invoke the &lt;code&gt;GetWorkItems&lt;/code&gt; function to fetch the current status and other pertinent details for the ADO items. Targeting only the IDs identified earlier ensures that our data retrieval is as efficient as possible.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot; language-m&quot;&gt;&lt;code class=&quot;prism  language-m&quot;&gt;let
    // Connect to dataverse
    Source = CommonDataService.Database(&quot;12345.crm.microsoftdynamics.com&quot;, [CreateNavigationProperties = true]),
    // Navigate to our table
    #&quot;Navigation 1&quot; = Source{[Shcema=&quot;dbo&quot;, Item=&quot;new_customerrequirement&quot;]}[Data],
    // We will drill down just to the new_adoitemid field so we can pass the entire list to the next step
    #&quot;Drill Down&quot; = #&quot;Navigation 1&quot;[new_adoitemid],
    // Split the list into batches of 200
    #&quot;Batch Items&quot; = SplitListIntoBatches(#&quot;Drill Down&quot;, 200),
    // Get the work items for each batch from the Azure DevOps API
    #&quot;Get Work Items&quot; = List.Transform(#&quot;Batch Items&quot;, each GetWorkItems(_)),
    // Combine the results into a single table
    #&quot;Combined Results&quot; = Table.Combine(#&quot;Get Work Items&quot;)
in
    #&quot;Combined Results&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;running-the-query-and-configuring-the-connection&quot;&gt;Running the Query and Configuring the Connection&lt;/h3&gt;
&lt;p&gt;After setting up your query with the provided sample code, executing the query will prompt you to configure the connection settings for accessing Azure DevOps. Here’s how to accurately set up the connection:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prompt for Connection Settings:&lt;/strong&gt; When you attempt to run the query for the first time, Power BI will prompt you to specify how to connect to the Azure DevOps URL. This is a crucial step to ensure secure and successful data retrieval.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set Authentication Type:&lt;/strong&gt; In the dialog box that appears, you’ll need to set the authentication method for the ADO URL connection. Choose “Basic” as the authentication method. This selection is necessary to use your Personal Access Token (PAT) for authentication.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure Username and Password:&lt;/strong&gt; For the username field, leave it blank. The PAT does not require a username to be specified. In the password field, paste in the PAT that you created earlier. Your PAT acts as the password, providing secure access to Azure DevOps data based on the permissions you’ve set when creating the token.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Save and Proceed:&lt;/strong&gt; After configuring the authentication settings, save your changes and proceed with running the query. This setup should allow Power BI to securely fetch the required data from Azure DevOps using your PAT, enabling the data transformation and syncing process to proceed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;finalizing-the-data-preparation&quot;&gt;Finalizing the Data Preparation&lt;/h3&gt;
&lt;p&gt;With the connection properly configured, you can efficiently combine the data fetched from Azure DevOps with the records in your Dataverse &lt;code&gt;new_customerrequirement&lt;/code&gt; table. This process prepares the synchronized dataset for the final step of updating Dataverse records, ensuring that only relevant and updated ADO item information is processed and prepared for synchronization.&lt;/p&gt;
&lt;h2 id=&quot;step-4-creating-a-dataverse-dataflow-and-linking-to-power-bi-dataflow-results&quot;&gt;Step 4: Creating a Dataverse Dataflow and Linking to Power BI Dataflow Results&lt;/h2&gt;
&lt;p&gt;After setting up your Power BI dataflow to fetch and process ADO item statuses, the final step involves creating a dataflow within Microsoft Dataverse. This Dataverse dataflow will utilize the Dataflows connector to connect to your Power BI dataflow, allowing you to synchronize and update the &lt;code&gt;new_customerrequirement&lt;/code&gt; table with the latest ADO item statuses. Here’s how to accomplish this:&lt;/p&gt;
&lt;h3 id=&quot;creating-a-dataverse-dataflow&quot;&gt;Creating a Dataverse Dataflow&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Navigate to Power Apps:&lt;/strong&gt; Start by going to the Power Apps portal and selecting your environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Access Dataflows:&lt;/strong&gt; From the left navigation pane, choose “Data” and then “Dataflows” to access the dataflows section.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create New Dataflow:&lt;/strong&gt; Click on “New dataflow” and then select “Start from blank” to begin the creation process.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;connecting-to-power-bi-dataflow&quot;&gt;Connecting to Power BI Dataflow&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Use the Dataflows Connector:&lt;/strong&gt; Within the dataflow creation process, select “Add data” and then choose the “Power BI dataflows” connector. This allows you to connect directly to the data processed by your Power BI dataflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authenticate and Select Your Dataflow:&lt;/strong&gt; Authenticate as necessary and select the Power BI dataflow you created earlier, which contains the ADO item statuses.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;linking-and-updating-the-new_customerrequirement-table&quot;&gt;Linking and Updating the &lt;code&gt;new_customerrequirement&lt;/code&gt; Table&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Combine IDs with Power BI Dataflow Results:&lt;/strong&gt; With the data from your Power BI dataflow now accessible within Dataverse, the next step is to link this data with the corresponding IDs in the &lt;code&gt;new_customerrequirement&lt;/code&gt; table. This involves matching ADO item IDs from Power BI dataflow results with those stored in Dataverse to ensure accurate updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Update Table with ADO Item Statuses:&lt;/strong&gt; Finally, utilize the linked information to update the &lt;code&gt;new_customerrequirement&lt;/code&gt; table, specifically the fields related to ADO item statuses. This ensures that the service staff can view the current status of development work directly within Dataverse, without needing to access Azure DevOps.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;finalizing-the-integration&quot;&gt;Finalizing the Integration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Test and Validate:&lt;/strong&gt; It’s essential to test the dataflow to ensure that data is being correctly updated in the &lt;code&gt;new_customerrequirement&lt;/code&gt; table. Validate the integration by checking if the ADO item statuses in Dataverse accurately reflect those in Azure DevOps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schedule Refreshes:&lt;/strong&gt; To maintain up-to-date information, schedule regular refreshes of your Dataverse dataflow. This ensures that the service staff always has the latest status updates at their disposal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By following these steps, you complete the integration cycle, effectively bridging Azure DevOps and Microsoft Dataverse. This enables your organization to streamline operations, enhance reporting capabilities, and provide your service staff with the visibility needed to offer informed customer support.&lt;/p&gt;
&lt;h2 id=&quot;an-alternative-approach-single-query-execution&quot;&gt;An Alternative Approach: Single Query Execution&lt;/h2&gt;
&lt;p&gt;While the method described above leverages functions within Power BI Dataflows to batch process and synchronize data, it’s crucial to note that there is an alternative strategy that does not require premium capacity. This alternative involves consolidating the entire process into a single query, thereby avoiding the creation of a computed table which necessitates a Power BI workspace with premium capacity.&lt;/p&gt;
&lt;h3 id=&quot;benefits-of-a-single-query-approach&quot;&gt;Benefits of a Single Query Approach&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cost Efficiency:&lt;/strong&gt; By avoiding the need for premium capacity, this method can be more cost-effective, especially for organizations looking to optimize their use of Power BI and Azure resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicity:&lt;/strong&gt; Consolidating the process into a single query can simplify the dataflow, making it easier to manage and troubleshoot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance:&lt;/strong&gt; A single query approach might also offer performance benefits by reducing the complexity and potential overhead introduced by multiple function calls and batch processing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;considerations&quot;&gt;Considerations&lt;/h3&gt;
&lt;p&gt;It’s important to weigh the benefits against potential limitations, such as the complexity of crafting a single, comprehensive query that can handle all necessary operations efficiently. Additionally, while this approach avoids the need for premium capacity, it still requires careful planning around API rate limits and the handling of large datasets.&lt;/p&gt;
&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;/h3&gt;
&lt;p&gt;Implementing this strategy requires a deep understanding of the Power Query M language and the ability to effectively leverage the Web.Contents function, query parameters, and data transformation capabilities within a single query block. This approach might look something like the following:&lt;/p&gt;
&lt;pre class=&quot; language-m&quot;&gt;&lt;code class=&quot;prism  language-m&quot;&gt;let
    // Connect to dataverse
    Source = CommonDataService.Database(&quot;12345.crm.microsoftdynamics.com&quot;, [CreateNavigationProperties = true]),
    
    // Navigate to our table
    #&quot;Navigation 1&quot; = Source{[Shcema=&quot;dbo&quot;, Item=&quot;new_customerrequirement&quot;]}[Data],
    
    // We will drill down just to the new_adoitemid field so we can pass the entire list to the next step
    #&quot;Drill Down&quot; = #&quot;Navigation 1&quot;[new_adoitemid],
    
    // Define the batch size
    BatchSize = 200,

    // Split the list into batches
    NumBatches = Number.RoundUp(List.Count(#&quot;Drill Down&quot;) / BatchSize),
    Batches = List.Transform({0..NumBatches - 1}, each List.Skip(#&quot;Drill Down&quot;, _ * BatchSize) &amp;amp; List.FirstN(#&quot;Drill Down&quot;, BatchSize)),

    // Function to fetch work items for a batch of IDs (inline definition)
    GetWorkItemsForBatch = (ids as list) as table =&amp;gt;
        let
            idsString = Text.Combine(List.Transform(ids, Text.From), &quot;,&quot;),
            fields = &quot;System.Title,System.State&quot;,
            adoOrganization = &quot;PowerAppsRAW&quot;,
            adoProject = &quot;My%20Project&quot;,
            apiUrl = &quot;https://dev.azure.com/&quot; &amp;amp; adoOrganization &amp;amp; &quot;/&quot; &amp;amp; adoProject &amp;amp; &quot;/_apis/wit/workitems&quot;,
            headers = [#&quot;Content-Type&quot; = &quot;application/json&quot;],
            Source = Json.Document(Web.Contents(apiUrl, [
                Headers = headers,
                Query = [
                    #&quot;api-version&quot; = &quot;7.1&quot;,
                    ids = idsString,
                    fields = fields
                ]
            ])),
            workItemsTable = Table.FromList(Source[value], Splitter.SplitByNothing(), null, null, ExtraValues.Error),
            expandedTable = Table.ExpandRecordColumn(workItemsTable, &quot;Column1&quot;, {&quot;id&quot;, &quot;rev&quot;, &quot;fields&quot;, &quot;url&quot;}, {&quot;ID&quot;, &quot;Revision&quot;, &quot;Fields&quot;, &quot;URL&quot;}),
            fieldNames = if Table.IsEmpty(expandedTable) then {} else Record.FieldNames(expandedTable{0}[Fields]),
            fullyExpandedTable = Table.ExpandRecordColumn(expandedTable, &quot;Fields&quot;, fieldNames, fieldNames)
        in
            fullyExpandedTable,

    // Fetch work items for each batch and combine results
    FetchResults = List.Transform(Batches, each GetWorkItemsForBatch(_)),
    CombinedResults = Table.Combine(FetchResults)
in
    CombinedResults
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This illustrative example simplifies the process into a single, cohesive query, demonstrating the potential to streamline the integration without relying on premium features.&lt;/p&gt;
&lt;h2 id=&quot;overcoming-obstacles&quot;&gt;Overcoming Obstacles&lt;/h2&gt;
&lt;p&gt;This journey wasn’t without its trials, particularly around authentication and the nuances of the M language for dataflows. The solution required creative thinking, such as using Power BI dataflows as a workaround for Dataverse’s authentication limitations and meticulously crafting M code to interact with the ADO API within its constraints.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By bridging Azure DevOps and Microsoft Dataverse with Power BI Dataflows, we’ve established a robust process for syncing work item updates for enhanced reporting and insight into project requirements. This solution not only addresses the immediate need but also offers a template for similar challenges, showcasing the flexibility and power of Microsoft’s ecosystem when it comes to custom integrations.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/1937541655724509671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/03/syncing-azure-devops-work-item-status.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1937541655724509671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1937541655724509671'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/03/syncing-azure-devops-work-item-status.html' title='Syncing Azure DevOps Work Item Status to Microsoft Dataverse with Dataflows'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-5972739817834629061</id><published>2024-03-06T15:20:00.002-05:00</published><updated>2024-03-06T15:20:47.999-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="automation"/><category scheme="http://www.blogger.com/atom/ns#" term="connector"/><category scheme="http://www.blogger.com/atom/ns#" term="CustomConnector"/><category scheme="http://www.blogger.com/atom/ns#" term="govee"/><category scheme="http://www.blogger.com/atom/ns#" term="lighting"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerApps"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerAutomate"/><title type='text'>Govee and Power Platform: Transforming Smart Lighting Automation</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/bb05d532-19a7-4236-bb4e-e91e169a1997&quot; alt=&quot;Govee and Power Platform: Transforming Smart Lighting Automation&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the evolving world of smart home technology, the integration of lighting solutions with sophisticated automation platforms is gaining significant traction. Our focus in this discussion is the Govee Lights Power Automate Connector, a pioneering tool that brings together the advanced capabilities of Govee’s smart lighting with the robust automation features of Microsoft Power Automate.&lt;/p&gt;
&lt;p&gt;For those interested in exploring the full capabilities of this connector, including setup instructions, usage scenarios, and technical specifications, detailed information is available on the official Microsoft documentation page. You can access it here: &lt;a href=&quot;https://learn.microsoft.com/en-us/connectors/govee/&quot;&gt;Govee Connector for Power Automate&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This connector not only exemplifies the practical application of integrating smart devices with automation platforms but also opens up new possibilities for enhancing home and office environments through intelligent lighting control.&lt;/p&gt;
&lt;h2 id=&quot;practical-integration-for-advanced-home-automation&quot;&gt;Practical Integration for Advanced Home Automation&lt;/h2&gt;
&lt;p&gt;The Govee Lights Power Automate Connector provides a pragmatic solution for controlling Govee smart lights through the Power Automate platform. By utilizing the Govee Developer API, this connector enables a straightforward yet sophisticated approach to lighting automation.&lt;/p&gt;
&lt;h3 id=&quot;building-the-connector-technical-insights-into-the-govee-api&quot;&gt;Building the Connector: Technical Insights into the Govee API&lt;/h3&gt;
&lt;p&gt;The development of the Govee Lights Power Automate Connector required a detailed understanding of the Govee API. This process was facilitated by two key resources:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Postman Quickstart Guide for Govee:&lt;/strong&gt; This guide provides a comprehensive starting point for anyone looking to understand and use the Govee API. It is especially useful for beginners or those not familiar with API interactions. The guide walks you through the basic steps of setting up API requests and testing them in Postman, making it an invaluable resource for getting up to speed quickly. Access the guide here: &lt;a href=&quot;https://quickstarts.postman.com/guide/govee/#0&quot;&gt;Postman Quickstart for Govee&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Govee Developer API Reference:&lt;/strong&gt; For a more in-depth exploration, the official Govee Developer API Reference is the go-to document. It contains detailed information on the API’s capabilities, parameters, response structures, and more. This comprehensive document is essential for developers looking to fully exploit the features of the Govee API in their applications. You can find the official documentation here: &lt;a href=&quot;https://govee-public.s3.amazonaws.com/developer-docs/GoveeDeveloperAPIReference.pdf&quot;&gt;Govee Developer API Reference&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using these resources, we were able to effectively understand and harness the full potential of Govee’s API, paving the way for the creation of this connector. This knowledge allowed us to build a tool that can interact seamlessly with Govee lights, providing users with an enhanced level of control and automation possibilities.&lt;/p&gt;
&lt;h3 id=&quot;key-features&quot;&gt;Key Features&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Direct Device Control:&lt;/strong&gt; The connector allows users to manage their Govee lights through Power Automate, offering functionalities like brightness adjustment and color change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Device Information Access:&lt;/strong&gt; This feature provides essential information about Govee devices, such as the MAC address, model, and supported properties. It’s vital for identifying the specific requirements to execute commands on the devices.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;utilizing-power-automate-for-smarter-lighting-control&quot;&gt;Utilizing Power Automate for Smarter Lighting Control&lt;/h2&gt;
&lt;p&gt;The integration of this connector with Power Automate’s automation tools enhances the control and customization of home lighting. It allows for the efficient management of lights as part of a broader automated home system.&lt;/p&gt;
&lt;h3 id=&quot;application-example-device-information-retrieval-and-command-execution&quot;&gt;Application Example: Device Information Retrieval and Command Execution&lt;/h3&gt;
&lt;p&gt;Consider a practical application of this integration:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Retrieve Device Information:&lt;/strong&gt; Create a flow in Power Automate to gather the necessary details about your Govee devices.&lt;br&gt;
&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/7a48f824-cf40-4542-8792-097910903def&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Process and Implement Data:&lt;/strong&gt; Use this information to prepare and structure the commands for the intended devices.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Command Execution:&lt;/strong&gt; Utilize this setup to execute desired actions, such as turning lights on or off and adjusting brightness.&lt;br&gt;
&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/ab7cd4b6-869b-4d78-be5a-cbc6cd289d30&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Refine and Integrate Your Automation:&lt;/strong&gt; Test and modify your flow for optimal performance, potentially incorporating other smart automation triggers.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;examples-of-power-automate-triggers-for-govee-lights&quot;&gt;Examples of Power Automate Triggers for Govee Lights&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time-Based Lighting Control:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigger:&lt;/strong&gt; Schedule (Time-based trigger in Power Automate).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; Automatically dim Govee lights in the evening and brighten them in the morning.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Calendar Event-Driven Lighting:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigger:&lt;/strong&gt; Calendar event start (Outlook Calendar trigger).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; Change Govee light colors for different types of events.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Email Notification Response:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigger:&lt;/strong&gt; New email from a specific sender (Email trigger in Power Automate).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; Flash or change the color of Govee lights for priority emails.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Weather-Based Lighting Adjustments:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigger:&lt;/strong&gt; Weather forecast change (Weather connectors or APIs).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; Adjust light brightness or color temperature in response to weather.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IoT Device Interaction:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigger:&lt;/strong&gt; IoT device status change (Smart home IoT triggers).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; Modify Govee light brightness with changes in room temperature.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Social Media Alerts:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigger:&lt;/strong&gt; New social media mention or message (Social media triggers).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; Change light color or pattern for notifications.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Motion-Triggered Lighting:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigger:&lt;/strong&gt; Motion sensor activation (Smart home motion sensors).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; Turn on or adjust Govee lights when motion is detected.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Custom User Input:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigger:&lt;/strong&gt; Button press on a mobile app or physical button (Power Automate Button trigger).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; Switch Govee lights to a pre-set scene or color palette.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The Govee Lights Power Automate Connector represents a focused approach to enhancing home lighting systems through automation. It stands as a practical example of how smart technology can be effectively integrated into daily life using tools like Microsoft Power Automate.&lt;/p&gt;
&lt;p&gt;Explore the functionality and benefits of this connector for a more efficient and tailored smart home lighting experience.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/5972739817834629061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/03/govee-and-power-platform-transforming.html#comment-form' title='24 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/5972739817834629061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/5972739817834629061'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/03/govee-and-power-platform-transforming.html' title='Govee and Power Platform: Transforming Smart Lighting Automation'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>24</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-5380371718563607244</id><published>2024-02-29T11:47:00.001-05:00</published><updated>2024-02-29T11:47:39.045-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ai"/><category scheme="http://www.blogger.com/atom/ns#" term="autogpt"/><category scheme="http://www.blogger.com/atom/ns#" term="azure"/><category scheme="http://www.blogger.com/atom/ns#" term="azureopenapi"/><category scheme="http://www.blogger.com/atom/ns#" term="chatgpt"/><category scheme="http://www.blogger.com/atom/ns#" term="llm"/><category scheme="http://www.blogger.com/atom/ns#" term="openai"/><title type='text'>Step-by-Step to Success: Run AutoGPT using Azure OpenAI on Docker</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/105d93ce-4983-4c37-9fc2-bbf9dbc6be3e&quot; alt=&quot;Step-by-Step to Success: Run AutoGPT using Azure OpenAI on Docker&quot;&gt;&lt;/p&gt;
&lt;p&gt;Integrating AutoGPT with Azure OpenAI through Docker offers a direct path to unlocking advanced AI capabilities. This detailed guide not only walks through the initial setup and configuration steps but also emphasizes the critical adjustments required for effective Azure OpenAI integration. Let’s dive into a more focused and informative discussion on setting up AutoGPT and ensuring it works seamlessly with Azure OpenAI services.&lt;/p&gt;
&lt;h2 id=&quot;what-is-autogpt&quot;&gt;What is AutoGPT?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Significant-Gravitas/AutoGPT&quot;&gt;AutoGPT&lt;/a&gt; is like having a smart robot buddy that helps you achieve a specific goal by chatting with a super smart AI, kind of like having a conversation with a genius friend. Here’s how it works, broken down really simply:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;You Set a Goal&lt;/strong&gt;: Imagine you have a goal, like planning a surprise birthday party or learning about space. You tell this to your robot buddy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Robot Starts the Chat&lt;/strong&gt;: Your robot buddy kicks things off by asking the first question to the genius AI, aiming to get information or ideas related to your goal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Listening and Thinking&lt;/strong&gt;: After getting an answer, the robot thinks about it, figures out if it’s helpful, and what to ask next to get closer to your goal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Asking More Questions&lt;/strong&gt;: Based on what the genius AI says, the robot keeps the conversation going, asking more questions to dig deeper or get more specific information, all aimed at reaching your goal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Goal Achieved&lt;/strong&gt;: This back-and-forth chat continues until your robot buddy has gathered enough info or ideas to help you meet your goal, like having a full plan for that surprise party or a good understanding of space.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In short, AutoGPT is like a helpful middleman between you and a super-smart AI, doing all the talking and thinking for you, so you don’t have to come up with what to ask next. It makes getting to your goal easier by handling the conversation, making sure everything stays on track.&lt;/p&gt;
&lt;h2 id=&quot;detailed-configuration-steps-for-integrating-autogpt-with-azure-openai&quot;&gt;Detailed Configuration Steps for Integrating AutoGPT with Azure OpenAI&lt;/h2&gt;
&lt;h3 id=&quot;initial-setup&quot;&gt;Initial Setup&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;a href=&quot;https://www.docker.com/get-started/&quot;&gt;Docker&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fork and Clone the AutoGPT Repository&lt;/strong&gt;: Begin by forking the &lt;a href=&quot;https://github.com/Significant-Gravitas/AutoGPT&quot;&gt;AutoGPT repository on GitHub&lt;/a&gt; and cloning it to your local machine, for instance, at &lt;code&gt;C:\Auto-GPT&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;configuration&quot;&gt;Configuration&lt;/h3&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Environment Setup&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy the &lt;code&gt;.env.template&lt;/code&gt; file from &lt;code&gt;C:\Auto-GPT\autogpts\autogpt&lt;/code&gt; to the primary folder &lt;code&gt;C:\Auto-GPT&lt;/code&gt; and rename it to &lt;code&gt;.env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Edit the &lt;code&gt;.env&lt;/code&gt; file, setting &lt;code&gt;USE_AZURE=True&lt;/code&gt; to enable Azure OpenAI integration. Ensure &lt;code&gt;True&lt;/code&gt; is capitalized to avoid issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API Key Configuration&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Update the &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; in the &lt;code&gt;.env&lt;/code&gt; file with your Azure OpenAI API key, found in the Azure portal under your OpenAI service’s “Keys and Endpoints”.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/2f3968ad-27cb-4266-9b91-07d116908595&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Docker and Azure YAML Setup&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Copy the &lt;code&gt;azure.yaml.template&lt;/code&gt; file to &lt;code&gt;C:\Auto-GPT&lt;/code&gt; rename it to &lt;code&gt;azure.yaml&lt;/code&gt; we will adjust it later according to our Azure OpenAI service details.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;docker.compose.yml&lt;/code&gt; file in &lt;code&gt;C:\Auto-GPT&lt;/code&gt; using the Docker setup template from the AutoGPT documentation. Add the following line to the volumes section to prevent the &lt;code&gt;app/azure.yaml&lt;/code&gt; file not found error:&lt;/p&gt;
&lt;p&gt;Volume Sample:&lt;/p&gt;
&lt;pre class=&quot; language-yaml&quot;&gt;&lt;code class=&quot;prism  language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./azure.yaml&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/app/azure.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Entire docker-compose:&lt;/p&gt;
&lt;pre class=&quot; language-yaml&quot;&gt;&lt;code class=&quot;prism  language-yaml&quot;&gt; &lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;3.9&quot;&lt;/span&gt;
 &lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;token key atrule&quot;&gt;auto-gpt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; significantgravitas/auto&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gpt
     &lt;span class=&quot;token key atrule&quot;&gt;env_file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; .env    
     &lt;span class=&quot;token key atrule&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &quot;8000&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;8000&quot;  &lt;span class=&quot;token comment&quot;&gt;# remove this if you just want to run a single agent in TTY mode&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;profiles&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;exclude-from-up&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./data&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/app/data
       &lt;span class=&quot;token comment&quot;&gt;## allow auto-gpt to write logs to disk&lt;/span&gt;
       &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./logs&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/app/logs
       &lt;span class=&quot;token comment&quot;&gt;## allow auto-gpt to read the azure yaml file&lt;/span&gt;
       &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./azure.yaml&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/app/azure.yaml
       &lt;span class=&quot;token comment&quot;&gt;## uncomment following lines if you want to make use of these files&lt;/span&gt;
       &lt;span class=&quot;token comment&quot;&gt;## you must have them existing in the same folder as this docker-compose.yml&lt;/span&gt;
       &lt;span class=&quot;token comment&quot;&gt;#- type: bind&lt;/span&gt;
       &lt;span class=&quot;token comment&quot;&gt;#  source: ./ai_settings.yaml&lt;/span&gt;
       &lt;span class=&quot;token comment&quot;&gt;#  target: /app/ai_settings.yaml&lt;/span&gt;
       &lt;span class=&quot;token comment&quot;&gt;#- type: bind&lt;/span&gt;
       &lt;span class=&quot;token comment&quot;&gt;#  source: ./prompt_settings.yaml&lt;/span&gt;
       &lt;span class=&quot;token comment&quot;&gt;#  target: /app/prompt_settings.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;azure-ai-models-deployment&quot;&gt;Azure AI Models Deployment&lt;/h3&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;strong&gt;Deploy Azure AI Models&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;a href=&quot;https://oai.azure.com/portal&quot;&gt;Azure AI Studio&lt;/a&gt; to deploy necessary models like &lt;code&gt;gpt-4&lt;/code&gt; and &lt;code&gt;gpt-3.5-turbo-text-embedding-ada-002&lt;/code&gt;, setting deployment names to match the model names for simplicity.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/51e4ed6d-ffe3-4bc1-9acb-2fb43f47528b&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;final-adjustments&quot;&gt;Final Adjustments&lt;/h3&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Modify the &lt;code&gt;azure.yaml&lt;/code&gt; File&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;azure_api_type&lt;/code&gt; to &lt;code&gt;azure&lt;/code&gt;, ensuring the use of the API key for authentication.  If you want to use Azure AD you can set the parameter to &lt;code&gt;azure_ad&lt;/code&gt;.  This will also require that you use an auth token as your OPENAPI_API_KEY.  Instructions on how to obtain this token can be found in &lt;a href=&quot;https://gist.github.com/primaryobjects/523577860628974501ffd3c52cd73525&quot;&gt;How to Configure AutoGPT with Azure OpenAI Active Directory Managed Identity&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;azure_api_base&lt;/code&gt; and &lt;code&gt;azure_api_version&lt;/code&gt; was determined using the &lt;a href=&quot;https://oai.azure.com/portal&quot;&gt;Azure AI Studio’s&lt;/a&gt; chat playground “View code” feature.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/d5888573-532e-4f7e-880d-84280ec2e80c&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/770210c4-1aa1-4d57-8aa1-cb7b7de7a386&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For azure_model_map, an iterative approach was taken. Initially, no mappings were specified. After running the Docker command, errors indicating missing models were used to gradually populate this section with the correct model mappings. This process involved mapping the AutoGPT’s expected model names to the corresponding deployment names in Azure AI Studio.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/Blogger/assets/7444929/41dc5ec2-a20f-4518-a815-4eb57beeeef0&quot; alt=&quot;2024-02-28_16-36-06&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Complete azure.yaml file.&lt;/p&gt;
&lt;pre class=&quot; language-yaml&quot;&gt;&lt;code class=&quot;prism  language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;azure_api_type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; azure
&lt;span class=&quot;token key atrule&quot;&gt;azure_api_base&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//rawopenai.openai.azure.com/
&lt;span class=&quot;token key atrule&quot;&gt;azure_api_version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2024&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;02&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;15&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;preview
&lt;span class=&quot;token key atrule&quot;&gt;azure_model_map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;gpt-3.5-turbo-16k&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gpt&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;35&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;turbo
    &lt;span class=&quot;token key atrule&quot;&gt;gpt-4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gpt&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;ext-embedding-3-small&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;embedding&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;ada&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;002&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;execution&quot;&gt;Execution&lt;/h3&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;&lt;strong&gt;Running AutoGPT&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Execute AutoGPT via Docker from the &lt;code&gt;C:\Auto-GPT&lt;/code&gt; directory using the command &lt;code&gt;docker compose run --rm auto-gpt&lt;/code&gt;. This step confirms the successful integration and functionality of AutoGPT with Azure OpenAI.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;AutoGPT revolutionizes our interaction with AI by automating the conversation process, guiding us toward achieving specific goals with minimal effort. This transformative approach streamlines tasks ranging from content creation to complex data analysis, making it a versatile tool for anyone looking to leverage AI’s power. The simplicity of AutoGPT, coupled with its goal-oriented methodology, democratizes access to advanced AI capabilities, enabling users to focus on outcomes rather than getting bogged down in the technicalities of prompt engineering.&lt;/p&gt;
&lt;p&gt;Through this article, we’ve provided a detailed blueprint for integrating AutoGPT with Azure OpenAI, ensuring you have the knowledge to harness this innovative technology effectively. Whether you’re a seasoned developer or new to the world of AI, the step-by-step guide laid out here is designed to empower you to implement AutoGPT within the Azure ecosystem successfully. Embracing AutoGPT opens up a realm of possibilities, allowing you to push the boundaries of what you can achieve with AI, turning complex tasks into manageable, goal-driven projects.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/5380371718563607244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2024/02/step-by-step-to-success-run-autogpt.html#comment-form' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/5380371718563607244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/5380371718563607244'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2024/02/step-by-step-to-success-run-autogpt.html' title='Step-by-Step to Success: Run AutoGPT using Azure OpenAI on Docker'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675696861245191896.post-1119866378213904633</id><published>2024-02-29T11:17:00.001-05:00</published><updated>2024-02-29T11:17:44.759-05:00</updated><title type='text'>Power Automate Blueprint Accessing Azure Portal Backend APIs and the Intricacies of main.iam.ad.ext.azure.com</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/6f67a1f1-2456-48d0-8638-93fa3cabb301&quot; alt=&quot;Power Automate Blueprint Accessing Azure Portal Backend APIs and the Intricacies of main.iam.ad.ext.azure.com&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the realms of digital infrastructure management, automation emerges as a pivotal ally, especially when confronting repetitive and time-sensitive tasks. A recent endeavor led me to a scenario where automating the management of OAuth tokens for users within our organization was paramount. Our meticulous record-keeping of these tokens and their respective assignments is handled through Power Apps. However, the manual aspect of adding these tokens via the Azure portal, which necessitated the upload of a CSV file each time, posed a cumbersome challenge.&lt;/p&gt;
&lt;p&gt;Given the current preview status of this functionality, a straightforward method through Graph API was conspicuously absent. Thus, I aimed to devise an automated framework, enabling individuals with the appropriate permissions in Power Apps to seamlessly add these tokens for users. While this wouldn’t entirely absolve admins of their duties—they would still need to activate the tokens within the Azure portal—it significantly mitigated the manual labor involved in creating and uploading the CSV file.&lt;/p&gt;
&lt;p&gt;My exploration revealed that during a manual CSV file upload, an API located at &lt;a href=&quot;http://main.iam.ad.ext.azure.com&quot;&gt;main.iam.ad.ext.azure.com&lt;/a&gt; is triggered in the background. However, this API is a closed door, accessible exclusively via the Azure portal and not through an app registration. This discovery beckoned a deeper dive to harness this API for automating the OAuth token management chore.&lt;/p&gt;
&lt;p&gt;This trail led to the crafting of a solution using Power Automate, which is the focal point of this article. The scripts and methodologies delineated here draw inspiration and foundational knowledge from the following insightful articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://rozemuller.com/use-internal-azure-api-with-logic-apps/&quot;&gt;Utilizing the internal main.iam.ad.ext.azure.com API with Logic Apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rozemuller.com/use-internal-azure-api-in-automation/#authenticate-to-mainiamadextazurecom&quot;&gt;Employing the internal main.iam.ad.ext.azure.com API in automation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://goodworkaround.com/2020/11/27/accessing-the-backend-azure-ad-apis-behind-portal-azure-com/&quot;&gt;Accessing the backend Azure AD APIs behind portal.azure.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While these articles unveiled a treasure trove of information, I envisioned extending this knowledge by showcasing how this automation could be embodied within Power Automate. This article, therefore, aspires to bridge that informational chasm and furnish a step-by-step guide on configuring the &lt;a href=&quot;http://main.iam.ad.ext.azure.com&quot;&gt;main.iam.ad.ext.azure.com&lt;/a&gt; API with Power Automate to automate OAuth token management, albeit it’s crucial to note that &lt;a href=&quot;http://main.iam.ad.ext.azure.com&quot;&gt;main.iam.ad.ext.azure.com&lt;/a&gt; is an unsupported API, which calls for a cautious approach in a production environment.&lt;/p&gt;
&lt;h2 id=&quot;service-account&quot;&gt;Service Account&lt;/h2&gt;
&lt;p&gt;Utilizing the &lt;a href=&quot;http://main.iam.ad.ext.azure.com&quot;&gt;main.iam.ad.ext.azure.com&lt;/a&gt; API requires a distinct approach for authentication due to its unsupported status and exclusive accessibility via the Azure portal. Unlike many Azure services, this API doesn’t support service principal access, which is a common method for non-interactive, automated access within Azure environments.&lt;/p&gt;
&lt;p&gt;To navigate this, it’s advisable to create a dedicated service account with the precise permissions required to interact with the &lt;a href=&quot;http://main.iam.ad.ext.azure.com&quot;&gt;main.iam.ad.ext.azure.com&lt;/a&gt; API. This setup aligns with the principle of least privilege (PoLP), ensuring the account has only the necessary access rights, and facilitates easier auditing and monitoring of the automated processes.&lt;/p&gt;
&lt;p&gt;Creating a service account is a good practice from a security standpoint. It not only provides a workaround for the lack of service principal support but also ensures that all actions carried out by the automation processes are traceable, thus enhancing the security and accountability of the setup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important Note on MFA and Token Lifetime:&lt;/strong&gt; If your Azure environment has Multi-factor authentication (MFA) requirements set up through conditional access, it can affect the token lifetime for the service account. In scenarios where this becomes a hindrance to automation processes, you may need to consider excluding or adjusting the MFA requirements for the service account. However, always ensure that any changes made align with your organization’s security policies and best practices.&lt;/p&gt;
&lt;h2 id=&quot;initial-key-vault-setup&quot;&gt;Initial Key Vault Setup&lt;/h2&gt;
&lt;p&gt;Azure Key Vault is a pivotal component in this setup, acting as a secure repository for storing and managing the refresh token needed for automation. It provides a centralized platform to safeguard sensitive data such as secrets, encryption keys, and certificates.&lt;/p&gt;
&lt;h3 id=&quot;resource-provider-registration&quot;&gt;Resource Provider Registration&lt;/h3&gt;
&lt;p&gt;Before diving into scripts or deployment files, ensure that the necessary Azure resource providers are registered within your subscription, particularly &lt;code&gt;Microsoft.Authorization&lt;/code&gt; and &lt;code&gt;Microsoft.KeyVault&#39;&lt;/code&gt; These providers are crucial for creating and managing the Key Vault and setting the necessary permissions.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/3a9826cb-ecd9-42f8-91d2-df47a48ba54f&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;deployment-options&quot;&gt;Deployment Options&lt;/h3&gt;
&lt;p&gt;There are various avenues to set up the Key Vault – you can employ Azure PowerShell, Azure CLI, or Bicep files, among other methods. In this guide, both PowerShell scripts and Bicep files are provided to offer flexibility based on your preferences or environment constraints.&lt;/p&gt;
&lt;h4 id=&quot;powershell-scripts&quot;&gt;PowerShell Scripts&lt;/h4&gt;
&lt;p&gt;A script named &lt;a href=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/blob/main/01-create-resources-powershell.ps1&quot;&gt;01-create-resources-powershell.ps1&lt;/a&gt; is provided to facilitate the creation of a resource group and a Key Vault. It’s an executable script where you just need to replace the parameters with your environment details.&lt;/p&gt;
&lt;pre class=&quot; language-undefined&quot;&gt;&lt;code class=&quot;prism language-*.sh-session language-undefined&quot;&gt;.\01-create-hidden-api-environment.ps1 -Location &quot;eastus&quot; -ResourceGroupName &quot;hidden-resourcegroup&quot; -KeyVaultName &quot;hidden-kv&quot; -TenantId &quot;123e4567-e89b-12d3-a456-426614174000&quot; -SubscriptionId &quot;123e4567-e89b-12d3-a456-426614174001&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;bicep-files&quot;&gt;Bicep Files&lt;/h4&gt;
&lt;p&gt;Bicep is a declarative language for describing and deploying Azure resources. It simplifies the process of writing and managing Azure Resource Manager (ARM) templates. Bicep files offer a streamlined method to deploy resources directly from Visual Studio Code, provided you have the Bicep extension installed. The files included in this guide are structured to deploy a resource group and a Key Vault effortlessly.&lt;/p&gt;
&lt;p&gt;What is great about these files is that you can easily deploy from within Visual Studio Code.  Just install the Bicep extension.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/dbbbe922-8346-4756-94ab-49d5be154186&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then right click on the bicep file to deploy.  The &lt;code&gt;main.parameters.json&lt;/code&gt; file can be used to supply all the necessary parameters for deployment.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/be99a9fc-c4c7-4fc9-91fc-c78827e521ff&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;Both deployment methods are designed to abstract the complexities involved in setting up Azure Key Vault, providing a straightforward path to secure the refresh token necessary for automation.&lt;/p&gt;
&lt;h4 id=&quot;azure-portal&quot;&gt;Azure Portal&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to the Azure portal, then select “Create a resource.”&lt;/li&gt;
&lt;li&gt;In the “Search the Marketplace” field, type “Key Vault” and select it from the list.&lt;/li&gt;
&lt;li&gt;Click the “Create” button to open the “Create Key Vault” blade.&lt;/li&gt;
&lt;li&gt;Fill in the necessary fields such as the Name, Subscription, Resource Group, and Location.&lt;/li&gt;
&lt;li&gt;Review the other settings and adjust them according to your preferences or requirements.&lt;/li&gt;
&lt;li&gt;Click the “Review + create” button, review your settings one final time, and then click “Create” to deploy the Key Vault.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;acquiring-the-initial-refresh-token&quot;&gt;Acquiring the Initial Refresh Token&lt;/h2&gt;
&lt;p&gt;For the automation to function seamlessly, acquiring a refresh token initially is crucial. This token will serve as the bridge for obtaining new access tokens, allowing the automation to interact with the &lt;a href=&quot;http://main.iam.ad.ext.azure.com&quot;&gt;main.iam.ad.ext.azure.com&lt;/a&gt; API securely.&lt;/p&gt;
&lt;p&gt;A PowerShell script named &lt;a href=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/blob/main/02-set-initial-refresh-token.ps1&quot;&gt;02-set-initial-refresh-token.ps1&lt;/a&gt; is provided to facilitate this process. When executed, this script will prompt you to sign in twice. The first login should be performed with an account that possesses the requisite permissions to update the Key Vault. Following this, a second login prompt will appear. This is where you would log in using the service account created earlier, which has been configured with just the necessary rights to interact with the Azure API. This dual-login mechanism ensures that the process is securely handled, aligning with the principle of least privilege while setting the stage for automated interactions with the &lt;a href=&quot;http://main.iam.ad.ext.azure.com&quot;&gt;main.iam.ad.ext.azure.com&lt;/a&gt; API. The example below shows you how to run the script, replace the parameters with your environment details.&lt;/p&gt;
&lt;pre class=&quot; language-undefined&quot;&gt;&lt;code class=&quot;prism language-*.sh-session language-undefined&quot;&gt;.\02-set-initial-refresh-token.ps1 -TenantId &quot;123e4567-e89b-12d3-a456-426614174000&quot; -SubscriptionId &quot;123e4567-e89b-12d3-a456-426614174001&quot; -KeyVaultName &quot;hidden-kv&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;automation-framework-setup&quot;&gt;Automation Framework Setup&lt;/h2&gt;
&lt;p&gt;Embarking on the automation of OAuth token management necessitates a structured setup within Power Automate and Azure. The steps below delineate the essential configurations:&lt;/p&gt;
&lt;h3 id=&quot;create-app-registration&quot;&gt;Create App Registration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;There’s no need to add any API roles.&lt;/li&gt;
&lt;li&gt;Generate a new secret, copying the secret value for safekeeping, as it will be crucial when creating the connection for Key Vault in Power Automate.&lt;/li&gt;
&lt;li&gt;Ensure to also copy the Application (Client) ID and the Directory (tenant) ID, which will be required for the connection within Power Automate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/56a79799-527e-41ff-8396-98ed6e1f084f&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;install-the-azure-key-vault-custom-connectors&quot;&gt;Install the Azure Key Vault Custom Connectors&lt;/h3&gt;
&lt;p&gt;Either install the Azure Key Vault custom connectors solution &lt;a href=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/raw/main/power-platform-solutions/AzurePortalAPICustomConnector_1_0_0_2.zip&quot;&gt;AzurePortalAPICustomConnector_1_0_0_2&lt;/a&gt;, or follow the installation guidelines provided &lt;a href=&quot;https://github.com/Microsoft/PowerPlatformConnectors/tree/master/custom-connectors/AzureKeyVault&quot;&gt;here&lt;/a&gt;. Utilizing a custom connector is vital since the certified connector for Key Vault doesn’t allow writing secrets back to the Key Vault, a feature requisite for this solution.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Update the host URL to reflect your new Key Vault.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/e6291654-ecc1-4915-b729-95c8f6b0e3d6&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Revise the security section:&lt;/li&gt;
&lt;li&gt;Ensure the Enable Service Principal support option is selected.&lt;/li&gt;
&lt;li&gt;Input the details copied from the app registration you created.
&lt;ul&gt;
&lt;li&gt;For the authentication URL, use:
&lt;ul&gt;
&lt;li&gt;Azure Cloud: &lt;code&gt;https://login.microsoftonline.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Azure Government: &lt;code&gt;https://login.microsoftonline.us&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;For the Resource URL use:
&lt;ul&gt;
&lt;li&gt;Azure Cloud: &lt;code&gt;https://vault.azure.net&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Azure Government: &lt;code&gt;https://vault.usgovcloudapi.net&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/3a05e59e-d23e-40f5-8cad-bfbae5a11f60&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy the Redirect URL from the security section, to be added within the app registration later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/0dd6016d-b327-408e-8133-f67648bc4ce4&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;update-app-registration&quot;&gt;Update App Registration&lt;/h3&gt;
&lt;p&gt;Incorporate the Power Automate redirect URL into the app registration.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/d060a313-94b5-4cc1-994f-dce807295d1b&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;key-vault-access-management&quot;&gt;Key Vault Access Management&lt;/h3&gt;
&lt;p&gt;Designate the app registration as a Key Vault Secrets Officer in Key Vault, ensuring the requisite permissions for reading and writing secrets are granted.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/537e6ab1-3a38-4642-a883-f0868d35c17d&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;power-automate-flow&quot;&gt;Power Automate Flow&lt;/h2&gt;
&lt;p&gt;The culmination of our setup is the creation of a Power Automate flow, designed to automate the process of managing OAuth tokens. Initially, the flow retrieves the existing refresh token from Key Vault, utilizes it to log in the service account, and upon a successful login, acquires a new refresh token alongside an access token. The new refresh token is then stored back in Key Vault, extending its lifespan, while the access token is employed to interact with the &lt;code&gt;main.iam.ad.ext.azure.com&lt;/code&gt; API.&lt;/p&gt;
&lt;p&gt;For a hands-on experience, you can download a solution containing the sample Flow from here: &lt;a href=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/raw/main/power-platform-solutions/AzurePortalAPIFlowExample_1_0_0_4.zip&quot;&gt;AzurePortalAPIFlowExample_1_0_0_4.zip&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important Note:&lt;/strong&gt; Ensure to secure all input and output parameters within any actions that may utilize the refresh token or access token to safeguard against unauthorized access.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/d35adbdc-446b-416a-a609-2d5472efef6a&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;get-refresh-token&quot;&gt;Get Refresh Token&lt;/h3&gt;
&lt;p&gt;The journey begins with the ‘Get secret’ action, courtesy of our custom Key Vault connector, fetching the refresh token from Key Vault to set the stage for the login process.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/7994e384-b765-434c-9358-9e10810219c7&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;Upon adding this action to your flow, select &lt;code&gt;Service Principal Connection&lt;/code&gt; as the authentication type, and furnish the details from the app registration created earlier.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/6c09cffc-f8f3-467c-a4e7-2434c7a8c232&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;parse-json-from-refresh-token&quot;&gt;Parse JSON from Refresh Token&lt;/h3&gt;
&lt;p&gt;Simplify the subsequent steps by parsing the Key Vault response using the ‘Parse JSON’ action.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/37600217-adf0-401f-b272-63eb9ebdabc6&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;The following schema can be copy/pasted into this action.&lt;/p&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;attributes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;created&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;integer&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boolean&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;recoverableDays&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;integer&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;recoveryLevel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;updated&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;integer&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;login&quot;&gt;Login&lt;/h3&gt;
&lt;p&gt;The ‘HTTP’ action propels a POST request to the AD OAuth token endpoint to procure the authorization token essential for Azure API interactions.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/fa7a43fe-4ea2-48b3-87ee-f900e0830ea1&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;URI (Replace {tenant-id} with your own tenant Id):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Azure Cloud: &lt;code&gt;https://login.windows.net/{tenant-id}/oauth2/token&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Azure Government: &lt;code&gt;https://login.microsoftonline.us/{tenant-id}/oauth2/token&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Header:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;content-type&lt;/code&gt;:&lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Body:&lt;br&gt;
-Azure Cloud:&lt;/p&gt;
&lt;pre class=&quot; language-undefined&quot;&gt;&lt;code class=&quot;prism language-*.txt language-undefined&quot;&gt;resource=74658136-14ec-4630-ad9b-26e160ff0fc6&amp;amp;grant_type=refresh_token&amp;amp;refresh_token=@{body(&#39;Parse_JSON_From_Refresh_Token&#39;)?[&#39;value&#39;]}&amp;amp;client_id=1950a258-227b-4e31-a9cf-717495945fc2&amp;amp;scope=openid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-Azure Government:&lt;/p&gt;
&lt;pre class=&quot; language-undefined&quot;&gt;&lt;code class=&quot;prism language-*.txt language-undefined&quot;&gt;resource=ee62de39-b9b0-4886-aa58-08b89c4e3db3&amp;amp;grant_type=refresh_token&amp;amp;refresh_token=@{body(&#39;Parse_JSON_From_Refresh_Token&#39;)?[&#39;value&#39;]}&amp;amp;client_id=1950a258-227b-4e31-a9cf-717495945fc2&amp;amp;scope=openid
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;parse-json-from-login&quot;&gt;Parse JSON from Login&lt;/h3&gt;
&lt;p&gt;Dive into the login response to extract the access and refresh tokens using the ‘Parse JSON’ action.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/1cf15732-a132-4b80-8980-f1737ee4719d&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;Utilize this schema:&lt;/p&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;access_token&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;expires_in&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;expires_on&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;ext_expires_in&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;foci&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;id_token&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;not_before&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;refresh_token&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;resource&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;scope&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;token_type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;set-new-refresh-token&quot;&gt;Set new Refresh Token&lt;/h3&gt;
&lt;p&gt;With a new refresh token at hand, update Key Vault using the ‘Create or update secret value’ action via the AzureKeyVault custom connector, thereby elongating the token’s lifespan.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/aad5bb7d-c6a2-4ffa-8d5b-b8b6d743c4a3&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;http-to-azure-api&quot;&gt;HTTP to Azure API&lt;/h3&gt;
&lt;p&gt;The curtain call involves employing the access token, obtained from the Login action, to interact with the Azure API. In this illustration, we’re fetching the account SKUs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/rwilson504/power-automate-azure-portal-hidden-api/assets/7444929/ec34d95a-8a36-4555-aab7-5ecb8c0dd1ab&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;upload-auth-token&quot;&gt;Upload Auth Token&lt;/h2&gt;
&lt;p&gt;The primary incentive behind devising this solution was to automate the simulation of uploading a hardware token CSV. The subsequent details exhibit the URLs and a sample body JSON for this purpose:&lt;/p&gt;
&lt;p&gt;To delve deeper into the realm of OATH tokens in Azure Entra, explore the following link: &lt;a href=&quot;https://learn.microsoft.com/en-us/entra/identity/authentication/concept-authentication-oath-tokens&quot;&gt;Authentication methods in Microsoft Entra ID - OATH tokens&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;sample-urlpayload&quot;&gt;Sample URL/Payload&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Commercial URLs:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Azure Cloud: &lt;code&gt;https://main.iam.ad.ext.azure.com/api/MultifactorAuthentication/HardwareToken/upload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Azure Government: &lt;code&gt;https://main.iam.ad.ext.azure.us/api/MultifactorAuthentication/HardwareToken/upload&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Body:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot; language-json&quot;&gt;&lt;code class=&quot;prism  language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;upn,serial number,secret key,time interval,manufacturer,model\r\ntest@mydomain.com,1234567,2234567abcdef2234567abcdef,30,Contoso,HardwareKey&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;mimeType&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/vnd.ms-excel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;760b21fc-128a-4504-9374-71f47638e27c.csv&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the final HTTP action of the Power Automate Flow, the above URLs and body can be employed to automate the hardware token upload process. You would specify the corresponding URL (based on your Azure environment) in the HTTP action’s URI field, and the provided JSON payload in the Body field. This automation step is crucial as it streamlines the hardware token management process by allowing a seamless upload of token data through the &lt;a href=&quot;http://main.iam.ad.ext.azure.com&quot;&gt;main.iam.ad.ext.azure.com&lt;/a&gt; API.&lt;/p&gt;
&lt;p&gt;The payload above delineates the necessary information for uploading hardware tokens, embodying user details, token attributes, and the corresponding hardware specifics.&lt;/p&gt;
&lt;p&gt;In conclusion, leveraging the &lt;a href=&quot;http://main.iam.ad.ext.azure.com&quot;&gt;main.iam.ad.ext.azure.com&lt;/a&gt; API in conjunction with Power Automate facilitates a seamless automation of hardware token management, thereby significantly reducing manual labor and enhancing security by minimizing human error.&lt;/p&gt;

&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;p&gt;💡 Real-world fixes and hands-on insights across Microsoft Power Platform, Power Apps, Power Automate, SharePoint, Dataverse, and Azure.&lt;/p&gt;
&lt;p&gt;📖 Explore more at &lt;a href=&quot;https://www.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;PowerAppsRaw.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  🔗 Connect with me:&lt;br/&gt;
  &lt;a href=&quot;https://linkedin.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt; |
  &lt;a href=&quot;https://youtube.PowerAppsRaw.com&quot; target=&quot;_blank&quot;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.richardawilson.com/feeds/1119866378213904633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.richardawilson.com/2023/11/readme.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1119866378213904633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675696861245191896/posts/default/1119866378213904633'/><link rel='alternate' type='text/html' href='http://www.richardawilson.com/2023/11/readme.html' title='Power Automate Blueprint Accessing Azure Portal Backend APIs and the Intricacies of main.iam.ad.ext.azure.com'/><author><name>Rick A. Wilson (RAW)</name><uri>http://www.blogger.com/profile/03562616659850164140</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXeizX1lkGH3JQPi6uDEiXfRNkpoC6uXIK8RF4EFcLW0fC3RC-4pR1r4Qx2gGUuUskeMzEy8sf1U8p79gMtaHYMMSHlCjGoVvysBanPP92m2dJxLhee34IHNXZ850NVw/s113/WilsonFamily20183.jpg'/></author><thr:total>11</thr:total></entry></feed>