Maturing on The Power Platform: We Don’t Create Unmanaged Layers in Prod

  1. Introduction
  2. Governance
  3. The reasons that we’re here
    1. Lack of Version Control
    2. Deployment Instability
    3. Difficult to troubleshoot issues
  4. Deploy managed solutions
  5. Call to Action

Introduction

I don’t want to be the bearer of bad news—well, maybe just a little. My goal is to save you from yourself, so let me be clear: WE DO NOT CREATE UNMANAGED LAYERS IN PRODUCTION!

If you’re serious about maturing on the Power Platform, there are a few fundamental principles you need to grasp. I get it—the way Power Platform is set up, with everyone having a default environment, can feel like the wild west. But there are some non-negotiables. At the very least, you should be working with two environments—ideally, three: one for development, one for testing, and one for production-ready solutions. You know, a proper application lifecycle management (ALM) process—the same concept they drilled into us in college.

In theory—and in practice, based on what I’ve seen over the years (including my own mistakes)—you can do whatever you want. But at some point, you need to stop, take a step back, and ask yourself: Is a “hot fix” in production really worth the risk?

My answer? Absolutely not. And here’s why.

Governance

Yes, the G word—governance. Autonomy is great—until there’s a data breach. Then suddenly, we’re all asking how our favorite retailer leaked our PII (Personally Identifiable Information), and I’m staring at an email telling me to cancel my credit card, pack up, and start a new life.

Okay, maybe this article isn’t that dramatic—but it could be. Governance isn’t just a Power Platform concern; it applies everywhere. And while we champion secure backends like Dataverse, security only works if we take governance seriously. So, do yourself a favor—treat it like it matters. Because it does.

I have the privilege of working alongside some of the world’s premier experts in governance and compliance, partnering with some of the biggest names in business. And time and time again, we find organizations falling into one of two categories:

The Gentleman’s Approach

These organizations recognize the power of Power Platform but haven’t fully deployed it across their enterprise. They want to get ahead of the chaos by implementing governance before things spiral out of control.

Please Save Us

On the other hand, some organizations have already deployed Power Platform—without guardrails. Now, it’s out of hand, and they’re desperately looking for a way to regain control before things get worse.

If you’ve taken the Gentleman’s Approach, thank you. It makes life so much easier when we can focus on methodology and toolkits to set you up for long-term success.

If you’re in the Please Save Us camp, thank you as well. Acknowledging the problem and committing to steering your organization in the right direction is a crucial step.

The Problem with Poor Implementations

Here’s the thing—lack of governance in Power Platform leads to poor adoption. We have this powerful platform at our fingertips, but if security gaps, broken processes, or unchecked risks get in the way, no one wants to use it—or worse, no one can use it safely.

CIOs and the Tough Questions

Do CIOs make my job harder when it comes to governance? Yes. And they should. The tough questions need to be asked. Don’t just take my word for it—press me, challenge me, ask for sources. This is your organization, your investment, your future.

As a consultant, I care deeply about the services I provide, but at the end of the day, I will roll off your project at some point. My goal? To leave your organization better than I found it. And that is part of the reason we don’t create unmanaged layers in production!

The reasons that we’re here

Lack of Version Control

It’s right there, staring you in the face. You can do it. Just pop that flow open, add that missing action, and everything is right with the world—until it’s not.

Whatever the reason, you must operate with the mindset that tweaking production directly is not acceptable. You cannot predict unexpected behavior, and doing so completely undermines your version control and environment strategy.

If you have a production environment (and please don’t tell me it’s the default environment—that’s a conversation for another day) and some form of environment strategy, respect it.

Make your changes in the lower environments, test them, get sign-off, and deploy to production—the way it should be done.

Deployment Instability

In production, or at least in managed solutions within production, we have what are called solution layers. (I even included a nice, shiny image above to illustrate this—you’re welcome.)

When you create unmanaged layers, you introduce the possibility of deployment failures down the line. The artifacts and components in future deployments weren’t designed to handle the unexpected behaviors you introduced by manipulating a solution directly in production.

Save your deployments. Do it the right way.

Stick to the process—develop, test, get approval, deploy. Your future self (and your team) will thank you.

Difficult to troubleshoot issues

The degree of difficulty in troubleshooting can vary—but it becomes exponentially harder when you don’t even know what you’re looking for.

The unpredictability of removing a single component, a line of code, or an action in a flow can drive even the most rational person up a wall. One small tweak can have ripple effects you didn’t anticipate, turning a simple fix into a time-consuming nightmare.

Let’s avoid unnecessary cleanup, frustration, and sweat-inducing emergencies. Follow best practices, respect your environments, and don’t create an unmanaged layer in production.

Regardless of which camp you fall into, governance matters—whether you’re planning ahead or trying to clean up the mess.

Deploy managed solutions

This should go without saying—but I’ve seen it all. I’ve been on engagements where entire production environments were packed with unmanaged solutions, and it took months to convert everything to managed.

I want my clients to be set up for success, even if it means being a thorn in someone’s side. I get that introducing complexity, governance, and strategy might seem like extra overhead for IT. But trust me—it’s worth it.

Now, think about the alternative: years of unmanaged layers, uncontrolled deployments, and an unrestricted environment that you still call production. The overhead and nightmares that come with that far outweigh the effort of doing things the right way from the start.

If your goal is to build a mature Power Platform model, then you need a strategy in place. Create the necessary environments, security groups, and pipelines to establish a structured, secure, and scalable framework.

Call to Action

It All Starts with Education

Educate your business units, educate IT, heck—educate your dog if you have to. A mature Power Platform adoption is an organizational effort, not just an IT initiative. Do it the right way.

Use the Right Tools

You have plenty of tools at your disposal:

✅ The CoE Starter Kit – Provides a holistic view of your environment.

Power Platform Admin Center – If you’re not ready for the CoE, at least establish a management strategy here.

Security Groups (M365 or Entra ID) – Set them up early to enforce governance and access control.

One Rule Above All

Whatever you do, do NOT create unmanaged layers in production.

Power Automate: The Logic Engine Behind Power Apps

  1. Introduction
  2. The Logic Engine Behind Power Apps
  3. Solution
    1. Canvas App
      1. Project Proposal Main Grid
      2. Project Proposal Entry Form
    2. Power Automate
      1. Handling Scope Logic

Introduction

One would think that by now, we’d all be settled on what Power Automate can do. But surprisingly, that’s not the case. It feels strange to still use the word “potential” when talking about Power Automate, especially since I’ve seen it achieve some pretty amazing feats. It has served as an integration point between the Power Platform and external systems, connected Azure and the Power Platform, and even acted as the logic layer for Power Apps. Yet, I still find myself in conversations with customers, exploring the true depth of its power and capabilities.

Over the next few weeks, I’ll be sharing more about what Power Automate can do. This week we’ll be talking about Power Automate as the logic layer for Power Apps. Follow along to learn more!


The Logic Engine Behind Power Apps

Power Apps is very capable. The problem is that the more complex your logic gets, the more complicated your formulas become. In my experience as a Power Platform developer, it’s rare to build a solution without involving at least one Power Automate flow. These flows are usually triggered by something happening in Power Apps—either directly when the app triggers an automation or once a record that was changed in the app meets certain conditions (like a CRUD operation in Dataverse, SQL Server, or SharePoint).


Solution

Below is a refined version of your text, maintaining a casual style and clear flow:


Our solution will include two components: Power Apps and Power Automate. We’ll be working on a “Project Proposal” process, where every proposal requires approval. Depending on factors like scope or budget, the proposal may need multiple approvers or just one. I won’t walk through the entire build here since this post is purely informational, but I will share screenshots and add details to illustrate each step.


Canvas App

Project Proposal Main Grid

Project Proposals Grid

When you first open the app, you’ll see a main grid listing all project proposals. Each row shows basic details like project name, budget, primary approver, and scope. This screen lets you quickly scan and select any proposal for more information.


Project Proposal Entry Form

Project Proposal Entry Form
Project Proposal Entry Form

This is where you enter all the core information for a new project proposal. It includes fields for basic details like project name, estimated budget, and scope. Once you fill out the form and submit, the proposal is added to Dataverse and triggers the Power Automate flow to handle scope logic.


Power Automate

Handling Scope Logic

Logic Handler

The crux of this solution is how we’re handling our logic. Sure, I could have written an expression with multiple If statements—maybe even nested ones—to get the result I wanted. But instead, I’m passing the necessary parameters to the Flow and letting Power Automate handle the conditional logic. If I ever want to add more conditions, I can do it in a visual way without diving into Power Fx.

Power Automate also offers other logic controls beyond simple If conditions, such as switch statements and parallel branches. This gives you a drag-and-drop interface to manage complex pathways—like sending notifications to different groups or looping through multiple records—without having to manually write or manage code. It’s all about making your logic more transparent and maintainable, so you can expand on it as requirements evolve.

Thank you for reading!!

More Than Word: Rapid App Development with SharePoint Templates

  1. Introduction
  2. SharePoint/Microsoft Lists
  3. Solution
    1. Available Templates
    2. Step 1: Create list from template
    3. Step 2: Be creative!!
    4. Extra

Introduction

Recently, someone asked me what I do for a living. My standard response is, “I am a Microsoft consultant.” I phrase it this way because the scope of Microsoft’s ecosystem is truly vast. Before I started consulting organizations on tools like Azure and Power Platform, I didn’t fully appreciate just how expansive Microsoft’s solutions really are.

The response I got was a little different than what I usually hear from business users, and I believe it was shaped as much by geography as by the products themselves. Milwaukee, WI, where I’m based, is a city historically known for heavy manufacturing, motorcycles, and beer.

This industrial legacy extends across Wisconsin, which has long been rooted in factories and industries, often relying on ERPs like Epicor or SAP. While Microsoft products are widely used here, they’re often limited to familiar tools like Word, Excel, and Outlook. However, Microsoft is far more than Word—it’s a robust platform that includes Azure cloud services, enterprise solutions like Dynamics F&O and Business Central, and the Power Platform. These tools empower both pro developers and low-code creators to build innovative solutions that drive business transformation.

Now, with the introduction of generative AI and Copilot, the Microsoft ecosystem has expanded even further, unlocking new possibilities for productivity and automation.

For those who still know Microsoft primarily for Word, I’m continuing a mission I started earlier this year: raising awareness of the incredible features included with Microsoft 365 licensing. Today, my focus is on the Business Standard license, specifically how it enables rapid development of custom business applications using SharePoint and Microsoft List templates. Let’s dive in and explore how you can make the most of these tools!

SharePoint/Microsoft Lists

One of the key benefits of a Business Standard license is access to SharePoint. SharePoint is an incredibly powerful tool, offering exceptional value for its cost. It serves as a collaborative workspace with features like built-in document management, intranet capabilities, and the ability to host and manage data in lists.

One of the key benefits of a Microsoft 365 Business Standard license is access to SharePoint, a robust tool offering exceptional value. SharePoint serves as a collaborative workspace with features like built-in document management, intranet capabilities, and the ability to host and manage data in lists.

While we won’t delve into all of SharePoint’s functionalities, let’s focus on its versatile lists feature. These lists are powerful tools for organizing and managing data, and you don’t need to access SharePoint directly to use them. The Microsoft Lists application provides an intuitive interface to work with these lists, making them a convenient and powerful data source for your business needs.

A significant advantage of Microsoft Lists is its accessibility across multiple platforms. You can manage your lists on the go using the Microsoft Lists mobile app, available for both iOS and Android devices. Additionally, while there isn’t a dedicated desktop app for macOS, you can use Microsoft Lists as a Progressive Web App (PWA) on your Mac. This setup allows you to work with your lists directly from your desktop, providing a seamless experience across devices.

This cross-platform availability ensures that you can access and manage your data whenever and wherever you need it, enhancing productivity and collaboration within your organization.

Solution

The template we’ll focus on today is the Asset Management template. While there are many templates to choose from, this one offers a great starting point for tracking and managing assets. It’s important to remember that you’re not limited to the fields provided in the template. SharePoint lists are customizable, and adding a new field to tailor the template to your specific needs is relatively easy.

If the out-of-the-box template meets most of your requirements but falls short in one or two areas, simply modify it by adding the necessary fields. This flexibility allows you to make the template truly your own while saving time and effort on development.

Available Templates

For posterity these are the templates available in SharePoint/Microsoft Lists:

1. Issue tracker

2. Employee onboarding

3. Event itinerary

4. Asset manager

5. Recruitment tracker

6. Travel requests

7. Travel requests with approvals

8. Work progress tracker

9. Content scheduler

10. Content scheduler with approvals

11. Playlist

12. Gift ideas

13. Expense tracker

14. Recipe tracker

15. Reading list

16. Apartment hunting

17. Job application tracker

18. Product support metrics

Step 1: Create list from template

In this step, we’ll select the Asset manager template. This will guide you through a wizard-like experience. On the next screen, you’ll see a preview of how the list will look when populated with data. From there, you’ll name your list and choose the option to create it. In just a few seconds, you’ll have a functioning data source for your asset management process.

Selecting template
Example
Renaming and creating template
Empty list in your SharePoint site.

Step 2: Be creative!!

The next steps are entirely up to you. There are countless stories waiting to be told through data. As a business application developer, I tell the story of business data using tools like Power Apps and Power Automate. A data or business intelligence analyst might choose to use Power BI to craft insightful reports from the same data. The key takeaway here is that we now have a central repository for our data—one that was created quickly, can be easily iterated upon, and serves as a foundation for exploring what’s possible with Microsoft 365 licensing.

If you’re a CIO or business user, this approach can help you realize the potential of the Power Platform. It’s perfect for spinning up a quick proof of concept (POC) to demonstrate not just the art of the possible, but the art of what is. And what is—that Microsoft is far more than just Word. It’s an expansive, powerful platform ready to transform the way you work.

Extra

Next, I’ll share images of an application and flow I built using this list as the foundation. By starting with the Asset Manager template, I was able to significantly reduce the time spent planning out the architecture and get straight to work. This allowed me to focus on the “extras”—how I wanted the app to look and how I wanted to structure my flows.

In total, it took me about three hours to build and iterate on the process, refining my ideas about how everything should function. By integrating this data source with the Power Platform, users can rapidly develop solutions tailored to meet specific needs, enabling faster delivery and greater flexibility.

List
Home screen of mobile app for managing assets
Flow used to implement ‘sumIndex’ functionality in another list, simplifying sum retrieval in the app by offloading the logic to the flow, reducing the app’s processing load.

Securing Internal Documents: Managing SharePoint Locations to Restrict External Portal Access

  1. Introduction
  2. Shoutout to Keegan
  3. Solution
    1. Step 1: Configuring the Basic Form
    2. Aside: Spoofing the System
    3. Step 2: Building the Flow
      1. 1. Trigger: When a row is added, modified, or deleted
    4. SharePoint Actions
      1. 2. Create new folder (Create Parent)
      2. 2. Create new folder (Create External Documents)
    5. Dataverse Actions
      1. 1. Add a New Row (Create External Document Location Record):
      2. 2. Add a New Row (Create Parent Document Location Record):
      3. 3. Update a Row (Change Parent Site on External Folder)
    6. In practice
      1. Steps to Set Up the Internal Subgrid:
      2. Test out internal subgrid

Introduction

I want to start by saying that my recent work with Power Pages has been a significant learning experience. While I had some idea of what I was getting into, I had to quickly upskill. Here’s the key takeaway: don’t fear what you don’t know. Fear of the unknown often holds us back, especially in the tech world, where there are always countless uncertainties. We use tools to build solutions and inevitably face gaps or unknowns along the way. Instead of shying away, embrace those unknowns, expect them, and take action. Soapbox moment over.

Shoutout to Keegan

I have to acknowledge my colleague, Keegan, for this. We worked on a Power Pages project with SharePoint integration and want to ensure that only external users can view external-facing documents. Internally, a reviewer will upload documents to the external user’s record. While the internal reviewer will have access to all documents in the library, the external user will be restricted to documents stored in an external-facing SharePoint folder.

We experimented with several approaches to implement the segregation, but nothing seemed to work. Initially, we considered adding a metadata field to the document library to flag files or folders as external, then using JavaScript in the portal to filter out the results. However, I was concerned that if the JavaScript failed or loaded slowly, it could inadvertently expose sensitive files to users who shouldn’t have access. That potential risk made me uncomfortable with relying on this approach.

We noticed there had to be an internal process Microsoft uses to decide which folder gets surfaced in the subgrid. It was Keegan who suggested that maybe the ‘Created On’ field in the Document Locations Dataverse table was being used to determine which folder gets displayed. And sure enough, that was the case. So, big shoutout to Keegan for that insight. He even suggested I write an article about it, but I have no problem giving credit where it’s due—he’s a great guy.

Solution

I won’t be covering the process of setting up SharePoint integration with Power Pages in this article, but I will go over the basics of our table permissions. Anything beyond that is outside the scope of this discussion. If you’re unfamiliar with the SharePoint integration setup, please visit Manage SharePoint documents. Once you’re comfortable with that, return to this article and pick up the instructions from there.

Step 1: Configuring the Basic Form

For our solution, we didn’t need to use the entire Dataverse form; we just needed a simple space to upload files. You can choose to use the full form or modify it to fit your needs. We’ll be uploading our forms to a table we named “Site.” A quick note: avoid naming a table in your Dataverse environment “Site.” Power Pages uses a table called “Site” that holds the site record for the Power Pages website, so using the same name could cause conflicts within the environment.

Whatever permissions you set on the form; I recommend changing the parent permission to “Global” for the purposes of this discussion. You can adjust the permissions later based on your specific needs, but for now, this will help show functionality. Once you change the parent permission’s access type, we should be all set. Still, please note—until we complete the Power Automate flow, I suggest against uploading anything into the subgrid. You’d likely have to delete it later anyway.

Aside: Spoofing the System


One thing we noticed when manually walking through this process is that in the Document Location table in Dataverse, the first Document Location record “wins” and becomes the default. This is why we need to “spoof” the system a bit. When the first file or folder is added, it automatically creates the parent document location in Dataverse, which we don’t want in this case. Instead, we want to create the external document location first. Once that’s done, we create the parent document location. After the parent is created, we’ll associate it with the external document location. This ensures that the external location takes priority in the subgrid, making it visible only to external users on the Power Pages website, while files or folders outside of the external folder structure and including the external folder will still be visible to internal users via the model-driven app.

Step 2: Building the Flow

Building out the flow is fairly straightforward. We want to automatically create the folder structure every time a new site is created, ensuring that when documents are uploaded from Power Pages, they are always directed into the external-facing folder. To implement this design effectively, we’ll use an automated trigger.

1. Trigger: When a row is added, modified, or deleted

This trigger will monitor the creation of new sites and automatically build the necessary folder structure, making sure the external folder is ready for document uploads.

SharePoint Actions

To achieve the necessary design for our folder structure, we will be using two SharePoint actions. These actions will create both the parent folder and the external folder nested inside the parent folder. Both actions will utilize the “Create new folder” action.

2. Create new folder (Create Parent)

  • Site Address:
    This should be the location of your document integration. If you’re unsure of the SharePoint site location for the integration, you can review the document management settings in Advanced Settings to find it.
  • List or Library:
    Library where your documents are stored, check the site contents of the SharePoint site to verify the document library where you want your documents to be stored.
  • Folder Path:
    The folder path will be a concatenation of the Site Name and the Site GUID, separated by an underscore (_). This ensures a unique folder structure for each site created.
replace(concat(triggerOutputs()?['body/dul_name'],'_',toUpper(triggerOutputs()?['body/dul_siteid'])),'-','')

This setup will create the parent folder, setting the foundation for further customization with the external folder inside.

2. Create new folder (Create External Documents)

  • Site Address:
    Use the same site address as the Create Parent action.
  • List or Library:
    Select the same document library as the Create Parent action.
  • Folder Path:
    Using the dynamic content from the previous action, select the Title of the folder created in the parent action, then add a forward slash (/) and specify the name of your external documents folder (e.g., 0External_Documents).

This will nest the external folder inside the parent folder, ensuring that all external-facing documents are uploaded into the appropriate folder structure.

Dataverse Actions

Once the folder structure is set up in SharePoint, the next step is to establish the corresponding Document Location in Dataverse. Before proceeding with any Dataverse actions, navigate to make.powerapps.com and open the Document Locations table. Find and extract the GUID for the default site’s Document Location record, which should be titled “Documents on Default Site.” This GUID is crucial for the Dataverse actions you’re about to implement, so make sure the record is available and correctly identified before continuing.

1. Add a New Row (Create External Document Location Record):

  • Table Name:
    Document Locations
  • Name:
    External Documents
  • Parent Site or Location (Document Locations):
    sharepointdocumentlocations({GUID of Default Site record})
  • Regarding (Sites):
    dul_sites({GUID of the site in the trigger})
  • Relative URL
    0External_Documents
    (Note: “Sites” is the table name being used for SharePoint integration in this example. Your table name may differ.)

It is essential to create the external document location record before proceeding with any further steps.

2. Add a New Row (Create Parent Document Location Record):

  • Table Name:
    Document Locations
  • Name:
    Trigger Name
  • Parent Site or Location (Document Locations):
    sharepointdocumentlocations({GUID of Default Site record})
  • Regarding (Sites):
    dul_sites({GUID of the site in the trigger})
  • Relative URL
    replace(concat({Name of Trigger},’_’,toUpper({GUID of Trigger})),’-‘,”)
    (Note: “Sites” is the table name being used for SharePoint integration in this example. Your table name may differ.)

3. Update a Row (Change Parent Site on External Folder)

  • Table Name: Document Locations
  • Row ID: {GUID of External Folder Document Location}
  • Parent Site or Location (Document Locations): sharepointdocumentlocations({GUID of Parent folder})

It’s crucial to update the parent site or location to align with the folder structure in SharePoint. This process leverages relative URLs, so it’s important that the relative URLs follow a consistent hierarchy. For example:

  • Default Site Relative URL: dul_site
  • Parent Relative URL: LinkedInTestSite
  • External Folder Relative URL: 0External_Folder

By correctly linking these records, the fully constructed URL will follow the pattern: dul_site/LinkedInTestSite/0External_Folder. This ensures the folder structure in Dataverse matches the structure in SharePoint, maintaining consistency and proper document organization.

Automated Dataverse trigger and creating folder structure in SharePoint
Creating external document location record in dataverse
Creating parent folder document location
Reparenting external document location with Parent record

In practice

Steps to Set Up the Internal Subgrid:

1. Open the main form for your table.

2. Add a subgrid to the form.

3. In the subgrid properties, select Related Records.

4. Choose Documents (Regarding) from the list.

5. Select All SharePoint Documents.

6. Save the changes.

7. Publish the form to apply the updates.

Test out internal subgrid

  1. Navigate to the table with the integration and select a record.
  2. Click Edit to open the form.
  3. In the subgrid, choose the Document Location dropdown and select All Locations. This will display all files in the folder structure.

In my case, the internal subgrid shows 5 records, including those uploaded from Power Pages or residing in the External Documents folder, but on the Power Pages side, only 3 files are visible.

  • This is because documents on the Power Pages side are written to the External Folder, so only documents in that folder will be visible to external users.

Important: If you upload a file to any location other than the External Folder, it will not be accessible to external users.

If you select the External Documents tab in the internal subgrid and upload a file, it will be added directly to the External Folder, making it visible to external users.

Internal facing subrid with all files including files uploaded from Power Pages
Files residing in the External Documents folder shown here in Power Pages

Data Transformation: Liquid Templates as Maps in Logic Apps and integrating them with Power Automate

Table of Contents

  1. Intro
  2. Scenario
  3. Demonstration
    1. Logic App
    2. Power Automate
      1. Secondary option
      2. Result
  4. Recommendations

Intro

In an earlier post, I mentioned transforming data using inline JavaScript powered by an Azure Function. I want to resurrect that idea. This time, I want to extend that conversation and open it up to integrating with Azure Logic Apps and Liquid Templating.

If you don’t want to read this, skip to the meat of the content.

As a consultant, I feel it is part of my duty to inform. Much of what we do with our daily interactions with data is transform it. We take raw data and manipulate it to serve different purposes based on our primary function. Other functions then transform it to suit their needs. In my line of work, it often amazes me how many different objects, presentations, automations, or apps can live off the same dataset, ultimately serving the same purpose: to drive the organization forward.

Power Platform experts may ask why I need a Logic App workflow to do what I can do in Power Automate, and someone proficient in Logic Apps may ask the same thing about Power Automate. Well, besides the similarities between the two technologies, architecting solutions shouldn’t be limited to the tools we are familiar with. The best solutions are made up of the best parts of various tools.

What do I mean by the best parts of? The scenario I am going to present today could, in theory and practice, be created using an Office Script that lives in SharePoint or an Excel file in OneDrive. In this case, the “best part” of Excel would be the Office Script, as we would not deal with any other functionality tied to the workbook. We could run our scenario through that Office Script and return its output to the flow, achieving virtually the same result. However, that is a different article for a different time.

The concept I want us to grasp is the solution itself. As a Power Platform developer who has now spent time working with Azure resources, I want to understand how I can benefit from both worlds. I know Azure can be daunting because it is a vast platform encompassing many things. When one declares Azure, you have to ask yourself…Azure what?

Scenario

The data we are trying to transform or manipulate comes in many forms. Sometimes, data is returned as a CSV, XML, JSON, plain text, HTML, YAML, or binary data such as files or images. In some cases, it even comes in custom formats specific to an application or system. It is our job as developers to figure out the best way and best tools to transform this data and serve it to our end user in a usable way on the destination server.

We will be working with a JSON payload. This concept was inspired by Microsoft Learn; however, I will not detail the creation of the liquid template. Instead, I will demonstrate how to access the template from Power Automate.

If you have not done so already, please follow the link I previously provided to set up your template and Logic App. Additionally, please add an extra action to your Logic App beyond what is described in the Microsoft Learn documentation, as we will need to return the value to our Power Automate flow.

Demonstration

Logic App

Following the documentation should result in your logic app containing the following trigger and actions:

  • When a HTTP Request is received (Trigger)
  • Transform JSON To JSON
  • Response (needed to provide a response to Power Automate)

In the Logic App portal, you need to copy the URL of the Logic App workflow. This URL will then be invoked in your Power Automate flow.

Power Automate

In Power Automate, we will create a flow with a manual trigger. Following the trigger, we will initialize four variables: one each for FirstName, LastName, Phone, and Devices. These are the same keys used in the Microsoft Learn documentation for creating the liquid template.

As you proceed, please populate the variables with values that align with the documentation. For the ‘devices’ variable, ensure you input values separated by commas, akin to the example shown below. Ensuring that devices are represented as objects in our output will be crucial.

In our Compose action, we’ll construct a JSON object similar to the one shown in the image below. Naturally, we won’t be constructing it exactly as depicted; I’ve included the formulas for reference purposes.

Excluding the trigger, we have five actions and several formulas dedicated to handling data transformation, which constitutes the ideal workflow.

Secondary option

To create a new flow, start with a manual trigger and then add an HTTP action. The flow should resemble the one depicted below.

In parameters for the http action

  1. Paste the URI to your logic app
  2. Select post as the method
  3. In the body, paste JSON to be parsed
Result

Now when you run the flows you will end up with basically the same results.

Recommendations

You might be wondering, “What did I lose?” or “What did I gain?” Both inquiries are pertinent. Our brief demonstration revealed that multiple actions are required to achieve what one action could previously accomplish. However, with templating, we gain increased flexibility for complex transformations. Separating the transformation logic from the workflow also enhances maintainability, making updates easier over time. Additionally, there’s the benefit of integrating with a broader range of Azure services. As mentioned before, Azure’s capacity to handle more advanced workloads allows us to enhance our Power Automate flows significantly.

Ultimately, the decision depends on what you, as a developer and an organization, are comfortable with. For smaller workloads, a strict Power Automate approach may suffice, but for enterprise-level solutions, exploring integrations with Azure might be the better option.

Thank you for reading!

Power Automate: Transforming DevOps Queries into Automated Notifications

Since I began my journey in IT, I’ve managed all my projects through Azure DevOps. When used correctly, DevOps is a powerful tool for solution development. However, it’s easy to lose track of tasks—especially if, like me, you tend to complete tasks but sometimes forget to update the hours or close them. In such cases, setting up a reminder can be incredibly helpful.

To create this reminder, we’ll use Power Automate to pull information from a custom query set up in DevOps. While I won’t cover setting up queries in DevOps here, you can refer to Microsoft Learn’s documentation for guidance on managing and organizing your queries.

Once your query is ready, let’s move over to Power Automate. For this demonstration, we’ll use an instant trigger.

Step 1: Call the Azure DevOps Query

Our first action after the trigger will be to fetch the query results from Azure DevOps. Use the “Get query results” action, then select the project name and the query ID.

The query will return a JSON payload, and there are multiple ways to handle it. For our purposes, we’ll send an email to notify the relevant parties of their time status.

Step 2: Process and Format the JSON Payload

Power Automate’s Send Email action supports simple HTML and CSS styling, which allows us to format the email content. We will structure the JSON data as an HTML table. To start, we’ll initialize a string variable that will serve as our row constructor, holding the content for each column in the table.

To build our rows, we will use the “Append to String” variable action to add rows based on the number of rows returned in our JSON object. You’ll notice that we’ll be using HTML tags and inserting our dynamic content between these tags. We’ll also apply inline CSS styling, which will be useful when we construct the final email notification.

Once we insert our dynamic content, Power Automate will automatically create an “Apply to each” loop. This loop will iterate over each item in the JSON object, appending a new row to our table for each iteration. This approach ensures that every entry is neatly formatted and included in the final email notification.

Step 3: Send Email Notification

In our final step, we’ll send an email notification containing the content of our string variable. You’ll see that I’ve included the table tags to encapsulate our formatted rows, along with headers for each column and some additional styling for clarity.

One important detail to remember when setting up the “Send Email” action is to enable the HTML content option. This tells Power Automate that we are using our own HTML and CSS styling. By doing so, our email will properly display the structured table and styling we’ve applied, ensuring a professional and readable notification for the recipients.

By following these steps, you can ensure that your DevOps tasks are always up to date and that all team members are aware of their status, ultimately enhancing productivity and organization.

Streamlining Workflow: Comparing Objects with Inline JavaScript in Azure Functions Powered by Power Automate

  1. What Are Azure Functions?
  2. Exercise
    1. Code
    2. Full code
    3. Power Automate

The short of it is…Power Platform lives on Azure. Now this article is not an attempt to push people into Azure, but I do at least want you to consider it. If you are like me, your introduction into Azure was most likely Azure AD now known as Entra ID and next year probably something else.

Azure is a big universe that supports many different workloads. Of particular interest to me and for the benefit of this article I want to focus on Azure Functions.

What Are Azure Functions?

I don’t think there is a need to dive deep into the subject, but what I will say is, Azure Functions allow us to run serverless, on-demand code. Azure Functions support various programming languages such as C# and JavaScript. The ability to call these functions and have them execute a piece of code is beneficial to developers, especially to “low-coders”. Reason being is, we don’t have to be as seasoned as a traditional “pro-coder” we can focus only on the code that matters to us.

With the advent of Co-Pilot and ChatGpt we can write code that serves our needs. I’d hate to cause a stir so I will say this, be careful with a.i. generated code, make sure your prompt is as explicit as you can get it and if you are unsure about the piece of code you are using…ask for help.

Exercise

I once worked with a client who needed to compare two objects and identify their differences to create exceptions for their customer service representatives to address. Implementing this process in Power Automate significantly saved time, though the solution involved multiple actions, loops, and data transformations, making it less streamlined than desired. However, as I gained more expertise in Azure Functions, I discovered that the same task could be accomplished more efficiently using just a few lines of JavaScript and a single action within the flow.

Before we proceed with this exercise, it’s important to note that a foundational understanding of how to provision an Azure resource and set up your function app is essential. To ensure you’re adequately prepared, I strongly recommend reviewing the information provided in the following link: Getting started with Azure Functions | Microsoft Learn.

Keep in mind that we are utilizing JavaScript for this task, so make sure to configure your function accordingly. While you can create your function directly in the Azure portal, which is the simplest approach, there’s also the option to develop it in Visual Studio Code. This latter method is a bit more complex but certainly achievable if you’re up for the challenge. For our function app, we’ll be using an HTTP trigger as the primary mechanism to initiate the process.

Code

Keep in mind that a function app essentially serves as a container for your code snippet. In this exercise, we’ll be adding code to our function and then obtaining the URL to integrate it with Power Automate. While I utilized ChatGPT to generate my code, it’s crucial to be aware that certain parts of this code are indispensable. One such essential line of code is as follows:

module.exports = async function (context, req){}

It’s important to operate within this framework, as the context from Power Automate will be fed into this function. Once that’s in place, our code will handle the rest of the process. This setup ensures that the data from Power Automate is seamlessly integrated and processed by our Azure Function.

Full code

Simply copy and paste the entire code into your function. Pay special attention to the parameter names ‘object1’ and ‘object2’. These are the parameters through which we will pass our objects. The code will then perform the comparison and return an object highlighting the differences, which we can utilize on the Power Automate side.

module.exports = async function (context, req) {

context.log('JavaScript HTTP trigger function processed a request.');

try {
// Assuming the input is a JSON string representing the objects.
const obj1 = req.query.object1 ? JSON.parse(req.query.object1) : null;
const obj2 = req.query.object2 ? JSON.parse(req.query.object2) : null;

// Validate the input
if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {
context.res = {
status: 400,
body: "Please pass two JSON objects in the query string or in the request body",
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};
return;
}

// Find differences
const differences = findObjectDifferences(obj1, obj2, "root");
context.log('Differences:', differences);

// Return the differences as a JSON string with the header "differences"
context.res = {
body: { "differences": differences },
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};

} catch (error) {
context.res = {
status: 500,
body: "Error processing your request",
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};
context.log.error("Exception thrown", error);
}
};

function findObjectDifferences(obj1, obj2, path) {
let differences = [];
let allKeys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);

allKeys.forEach((key) => {
let newPath = path + "." + key;
if (obj1.hasOwnProperty(key) && !obj2.hasOwnProperty(key)) {
differences.push({ path: newPath, obj1: JSON.stringify(obj1[key]), obj2: 'Not present' });
} else if (!obj1.hasOwnProperty(key) && obj2.hasOwnProperty(key)) {
differences.push({ path: newPath, obj1: 'Not present', obj2: JSON.stringify(obj2[key]) });
} else if (obj1[key] && obj2[key] && typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
differences = differences.concat(findObjectDifferences(obj1[key], obj2[key], newPath));
} else if (obj1[key] !== obj2[key]) {
differences.push({ path: newPath, obj1: JSON.stringify(obj1[key]), obj2: JSON.stringify(obj2[key]) });
}
});

return differences;
}

After configuring your function, save it. Then, locate and click on the ‘Get function URL’ button found in the editor’s ribbon. This URL is crucial as you will need it to make the HTTP request in Power Automate.

Power Automate

  1. Set Up the Trigger: Begin by setting up your Power Automate flow with a trigger of your choice. This trigger will initiate the flow.
  2. Initialize Object Variables: Next, initialize two object variables named ‘varObject1’ and ‘varObject2’. Initially, I attempted to directly write the objects in the HTTP request but encountered issues. It’s more effective to initialize these variables and assign your arrays to them, allowing for a smoother conversion process.
  3. Create an HTTP Request:
    • Choose ‘POST’ as the method for your HTTP request.
    • In the query, you will need to add two lines:
      • The first line should have ‘object1’ as the key, with the value being the ‘varObject1’ variable.
      • The second line should have ‘object2’ as the key, with the value being the ‘varObject2’ variable.
  4. Paste the Function App URL: Paste the URL you obtained from your Azure Function app into the appropriate field in your HTTP request setup.
  5. Save and Run: After setting up everything, save your flow configuration. Then, run your flow to test and see it in action.
varObject1
varObject2
HTTP Request
successful run and differences in the body

The following is the returned exceptions (differences) in the objects. The object specifies the affected columns “root.Borrower2” and “root.Address”

{ "differences": [ { "path": "root.Borrower2", "obj1": "\"Marsurice DeVan\"", "obj2": "\"Marsurice Devan\"" }, { "path": "root.Address", "obj1": "\"Dean\"", "obj2": "\"Down\"" } ] }

Why Not Azure (or however you pronounce it)?

Alright, Azure and Power Platform. It’s easy to overlook, but remember, Power Platform is cozily nestled right into Azure. I’ve gone from saying I build apps to now, more accurately, saying I work in the cloud.

Azure is essentially the backbone of the cloud world for Microsoft 365 and Power Platform, now Azure OpenAi. Between you and me, Azure has long had Ai capabilities with Azure Cognitive Services.

Azure has replaced the need for those loud, space-eating server rooms with a sleek, digital space. I remember the days of hiding in server rooms to escape the constant barrage of IT queries. Now, with Azure, those days are just a funny memory.

So, why Azure? Well, it’s vast. When my wife expressed interest in learning it, I had to ask, “Which part?” because it’s that big. It’s not just one thing; it’s a whole ecosystem waiting to be explored.

The cost might make some hesitant. I’m not claiming to be a Microsoft licensing expert, but generally, if the benefits are clear, people find the costs justifiable. And with Azure, the benefits are often worth it.

My journey and new role have led me deeper into Azure, especially Azure Functions. These have been a game-changer in my Power App development. They allow me to execute code, like JavaScript and my new favorite PowerShell, for complex tasks I’d rather not handle directly in the app. It’s been a great push to brush up on my coding skills too. I’ve reacquainted myself with Visual Studio Code as the last 4 years or so, I’ve lived in the Power Apps formula bar and Power Automate expressions.

But it’s not just about using Azure for the sake of it. Integrating Azure into your Power Platform solutions can significantly enhance what you’re able to do. It’s about making your solutions more robust and efficient. Azure Logic Apps, for instance, are like Power Automate on steroids, offering more capabilities and flexibility.

In essence, leveraging Azure within your Power Platform solutions isn’t just a good idea; it’s a strategic move. It’s about expanding your capabilities and delivering more sophisticated solutions. So, consider taking that step into Azure. It’s a solid move for anyone looking to enhance their Power Platform projects.

Enhancing Power Automate Desktop Proficiency with Access and PowerShell Integration

  1. Install ImportExcel Module
  2. Creating Desktop Flow
    1. Create Input Variable
    2. Retrieving Excel File From Folder
    3. Create “For each” loop
    4. Launch Excel
    5. Read from Excel worksheet
    6. Running PowerShell Script to insert data into our Access database

I recently had a conversation with a friend about the relevance of Access databases in today’s tech landscape. To my surprise, he emphatically affirmed that Access databases are still widely used. The last time I encountered Access was during my college days when it was used as a teaching tool for database modeling. Honestly, I had no idea that organizations continued to rely on it.

In my personal journey, Access has played a pivotal role in enhancing my skills with Power Automate Desktop. Initially, my goal was to create a Model Driven App and utilize it in conjunction with Power Apps desktop to execute desktop flows. This approach worked reasonably well, but over time, I no longer had the Model Driven App and didn’t want to recreate it. That’s when I turned to Access as my training ground.

However, even my practice with desktop flows on Access forms had its limitations. During my experimentation with PowerShell, I became determined to find a way to insert data into an Access database file without ever having to open Access itself. So, for those who still rely on Access in their workflows, This one is for you…

Here’s what you’ll need: a designated location to store your Excel file. Personally, I store mine in a folder on my desktop.

Install ImportExcel Module

To install the ImportExcel module, please open PowerShell and execute the provided script below:

Install-Module -Name ImportExcel -Scope CurrentUser

Creating Desktop Flow

Create Input Variable


To create an input variable for storing the path to the Access database we are working with, follow these steps to configure it:

  1. Open the Power Automate Desktop workflow where you intend to use the variable.
  2. Locate the area where you can define variables, typically in the workflow settings or variable panel.
  3. Create a new variable and give it a meaningful name, such as “varAccessDb.”
  4. Set the data type of this variable to “String” since it will store the file path, which is typically a text value.
  5. Save your workflow to ensure the variable is retained.

Now, you have an input variable named “varAccessDb” that can be used within your PowerShell script to hold the path to the Access database.

Retrieving Excel File From Folder


To initiate the process, the first action we need to perform is to retrieve the Excel file(s) that will be used in our flow. Follow these steps:

  1. In the Actions pane on the left-hand side of your Power Automate Desktop interface, type “Get files in folder” in the search bar.
  2. Locate the “Get files in folder” action in the search results.
  3. Drag and drop the “Get files in folder” action onto your workflow canvas.

This action will allow you to specify the folder from which you want to fetch the Excel files for further processing in your flow.


To direct the “Get files in folder” action to the folder containing your Excel workbooks and set it up to collect all files with a .xlsx extension, follow these steps:

  1. Select the “Get files in folder” action block on your workflow canvas to access its configuration.
  2. In the “Folder path” input field, specify the path to the folder where your Excel workbooks are located. You can either type the path or use the browse button (…) to navigate to and select the folder.
  3. In the “File filter” input box, input “*.xlsx”. This filter will ensure that the action captures all files with the .xlsx extension.
  4. Save your configuration.

Now, the “Get files in folder” action is configured to retrieve all Excel files with the .xlsx extension from the designated folder for further processing in your flow.

File filter: *.xlsx

Save.

Create “For each” loop

To make your solution dynamic and capable of handling one or multiple files, you can set up a “For Each” loop. Follow these steps:

  1. In the Actions pane, search for “For Each” to find the For Each loop action.
  2. Drag and drop the “For Each” loop action onto your workflow canvas.
  3. In the “Values to iterate” field of the “For Each” loop, use the %Files% variable that was generated from your “Get files in folder” action.
  4. To enhance readability, you can rename the “Store into” section from “CurrentItem” to “CurrentFile.”

By doing this, you’ve set up a loop that will iterate through each file retrieved by the “Get files in folder” action, allowing your workflow to handle both single and multiple files seamlessly.

Launch Excel

To add a “Launch Excel” action within your “For Each” loop and configure it, follow these steps:

  1. In the Actions pane, search for “Launch Excel” to locate the “Launch Excel” action.
  2. Drag and drop the “Launch Excel” action into your workflow editor, making sure it is nested within the “For Each” loop.

Now, let’s configure the “Launch Excel” action with the following parameters:

  • File path: This should point to the current Excel file being processed in the loop. Use the “CurrentFile” variable to specify the file path dynamically.
  • Visible: You can choose whether you want Excel to be visible during the execution of your workflow. Set it to “No” if you want Excel to run in the background without displaying the user interface, or “Yes” if you want Excel to be visible.
  • Create new instance: You can choose to create a new instance of Excel for each file, ensuring that each file is processed independently. Set it to “Yes” if you want a new instance for each file, or “No” if you want to reuse the same instance for all files.
  • Run macro (optional): If you have a specific Excel macro to run, you can specify it here. Otherwise, leave it blank if you don’t need to run a macro.

By configuring the “Launch Excel” action in this manner, you ensure that your workflow opens and processes each Excel file one by one within the “For Each” loop.

Launch Excel: and open the following document
Document Path: %CurrentFile.FullName%

Certainly, if you prefer to make the Excel instance visible, you can set the “Visible” option to “Yes” in the “Launch Excel” action configuration. This choice will allow you to see the Excel interface while the workflow is running, which can be helpful for monitoring and debugging your automation process.

Read from Excel worksheet

To add a “Read from Excel worksheet” action and configure it as described, follow these steps:

  1. In the Actions pane, search for “Read from Excel worksheet” and drag it into your workflow editor. Ensure that you place it within the same “For Each” loop as the “Launch Excel” action.
  2. Configure the “Read from Excel worksheet” action with the following parameters:
Excel instance: %ExcelInstance%
Retrieve: All available values from worksheet

Running PowerShell Script to insert data into our Access database

This PowerShell script will loop through the Excel data and insert records into the specified Access table without the need to have Access open. It should significantly improve the efficiency of your workflow compared to looping through each record in the spreadsheet using multiple actions in Power Automate Desktop.

  1. Add a “Run PowerShell script” action to your workflow.
  2. Copy and paste the following PowerShell script into the action, making any necessary updates to match your specific file paths, table names, and data variables:
# Define the path to the Access database
# varAccessDb is the our input variable
$accessDBPath = "%varAccessDb%"

# Define the connection string
$connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$accessDBPath;Persist Security Info=False;"

# Define the path to the Excel file
$excelFilePath = "%CurrentFile%"

# Import data from the Excel file
# Ensure that your Excel file has columns named PartName, SKU, Description, and Price
$dataCollection = Import-Excel -Path $excelFilePath

try {
    # Create a connection object
    $connection = New-Object System.Data.OleDb.OleDbConnection($connectionString)

    # Open the connection
    $connection.Open()

    foreach ($item in $dataCollection) {
        # Define the SQL query for inserting data
        $query = "INSERT INTO Part ([Part Name], [SKU], [Part Description], [Price]) VALUES ('$($item.PartName)', '$($item.SKU)', '$($item.Description)', $($item.Price))"

        # Create a command object
        $command = New-Object System.Data.OleDb.OleDbCommand($query, $connection)

        # Execute the command (perform the insert operation)
        $command.ExecuteNonQuery()
    }

    # Close the connection
    $connection.Close()
}
catch {
    # Handle the error
    Write-Host "An error occurred: $_"
}
finally {
    # Ensure that the connection is closed even if an error occurs
    if ($connection.State -eq [System.Data.ConnectionState]::Open) {
        $connection.Close()
    }
}

Lastly add an action to close Excel.

Power Automate Desktop – Turning on Track Changes in Word Document

Automation is a game-changer in the world of productivity and efficiency. It’s all about streamlining processes, ensuring consistency, and, believe it or not, even providing a sense of buoyancy. Yes, you read that right – buoyancy. Desktop automation can be your secret weapon in keeping those seemingly irreplaceable legacy systems afloat, even when they’re driving your CIO crazy. After all, many of your colleagues are still in love with those systems because they just work – that’s the magic of automation.

But desktop automation isn’t limited to legacy system support; it can also enhance your everyday tasks, like automating Microsoft Word. Now, you might be thinking, “I can do that with a cloud flow,” and you’re not wrong. Cloud-based automation is fantastic for updating templates and structured data. However, what I’m proposing is taking automation to the next level by working with free text.

But, before we dive into the exciting world of free-text automation, let’s talk safety first. There’s no point in automating something if we can’t roll it back in case of a mishap. We’ve all been there – that heart-pounding moment when you’ve pushed the proverbial ‘red button,’ and suddenly, you’re in a lonely, isolating place where your brain feels like it’s losing blood, and you start wondering if you’ll still have a job in the next five minutes. That’s why it’s crucial to implement safety measures to avoid such nerve-wracking situations.

The Guard Rails

In this exercise, we’ll be focusing on a SharePoint document library, which is already equipped with robust document management features such as check-in/check-out and version history. However, one feature that might be missing from your SharePoint arsenal is the ability to activate ‘Track Changes.’

Desktop automation opens up exciting possibilities, allowing us to activate ‘Track Changes’ effortlessly. One of my personal favorites for achieving this is harnessing the power of PowerShell in combination with desktop flows.

PowerShell provides the ultimate level of control and efficiency, eliminating the need for multiple unnecessary actions by allowing us to solve complex tasks with a single script. It’s a game-changer when it comes to automating tasks and streamlining processes in desktop flows.

The Solution

To work with a document in SharePoint and access its settings, follow these steps:

  1. Right-click on the document you want to work with within your SharePoint document library.
  2. From the context menu that appears, select “Copy Link.”
  3. After copying the link, proceed to select the “Settings” link or option to access and configure the document’s settings as needed. This step may vary slightly depending on your specific SharePoint environment and version.

4. In the sharing settings, you should see an option to invite people or add users. Enter the email addresses of the users you want to grant “Can Edit” permissions to. You can also use SharePoint groups if applicable.

5. Select apply and the link will be copied to your clipboard and settings for sharing saved.

In Power Automate Desktop

  1. Add the ‘Terminate’ action
  2. Configure the “Terminate” action settings as follows:
    • Process Name: Enter “WINWORD.EXE” (without quotes) in the “Process Name” field. This is the executable name for Microsoft Word.
    • Action: Choose “Terminate” to close any running instances of Microsoft Word.
  3. Save your flow with the “Terminate” action in place.

2. Next we’ll add an action called ‘Run application’

For the “Run application” action with the specified parameters, here’s how you can configure it:

  1. Application Path: Enter “winword.exe” (without quotes) as the application path. This specifies that you want to run Microsoft Word.
  2. Command Line Arguments: Enter “/t” followed by the sharing link from the Word document in your document library. Make sure to replace “sharing link” with the actual URL or path to your Word document. For example, if your document’s sharing link is “https://example.com/document.docx,” your command line argument would be “/t https://example.com/document.docx.”
  3. Window Style: Set the window style to “Maximized.” This will ensure that the Microsoft Word application window is opened in a maximized state.

With these parameters, the “Run application” action will launch Microsoft Word with the specified command line arguments, opening the document in a maximized window.

Sidebar – sort of

Introducing the concept of command line switches is crucial when working with Microsoft Office products and many other applications. Command line switches provide a convenient way to customize how an application behaves when launched from the command line or as part of an automation process.

In our specific case, the “/t” switch used before the document link is a common command line switch for Microsoft Word, indicating that we want to open an existing file. By including this switch in the command line arguments, we instruct Microsoft Word to treat the provided link as the path to an existing document that should be opened.

Back to regularly scheduled programming…


Next, we’ll insert two left clicks to the foreground window, which should be Microsoft Word, you can use the “Mouse Click” action. The goal is to mitigate any potential dialog interruptions:

  1. Add a “Mouse Click” action to your automation.
  2. In the “Mouse Click” action settings, specify the following:
    • Click Type: Choose “Left Click” to perform a single left-click.
    • Target: Select “Foreground Window” to ensure that the click is directed to the currently active window, which should be Microsoft Word.
    • Repeat: Set the “Repeat” option to “1” to perform the click once.
  3. After the first “Mouse Click” action, add another “Mouse Click” action with the same settings as the first one.

Trust me this step is warranted; I’ve seen some weird things in my time.

Now, let’s incorporate a PowerShell script into our workflow to achieve the goal of enabling track changes for our document. What makes this script particularly useful is its precision: it focuses solely on enabling track changes. Importantly, if track changes are already active, the script won’t “bat an eye”. However, if track changes are not yet enabled, the script will take action, enforcing track changes and ensuring that revisions are visible as they occur.

  1. Add a “Run PowerShell Script” action to your automation.
  2. In the “Run PowerShell Script” action settings, you can paste the provided script into the script editor. Make sure to include the entire script:
$wordApp = [System.Runtime.Interopservices.Marshal]::GetActiveObject("Word.Application")

# Get the active document
$document = $wordApp.ActiveDocument

# Enable track changes
$document.TrackRevisions = $true
$document.ShowRevisions = $true

# Save changes (optional)
$document.Save()
  1. Save your flow with the “Run PowerShell Script” action included.

Let’s introduce a step to test our automation by using the ‘Send Keys’ action. In the input parameters, we’ll enter a specific text of our choice. For instance, I’ll input “tested.” This action will transmit this free-text input directly to our Word document, allowing us to verify the effectiveness of our automation process.

Run the flow