In this blog post I want to share with you how to run PowerShell scripts in an Entra ID Governance Lifecycle Workflows. In my blog post about creating onboarding Lifecycle Workflows I wrote about how you could use Lifecycle Workflows in Entra ID Governance to add a new user to selected security groups and selected Teams using default tasks. The Lifecycle Workflows in Entra ID Governance comes with great default tasks options out-of-the-box, but it becomes so much more powerful when you start to use the Custom extension task in your Lifecycle Workflows. This is the one feature that will enable you to do almost any task you can think of like adding user to distribution lists or a shared mailbox in Exchange (on-premises or online) or add a Teams PSTN number to a new user or even add a user to security groups in Active Directory. If you can code it in PowerShell, you can get Entra ID Governance Lifecycle Workflows to perform the task on the user using Lifecycle workflows.
Please note that this is the same procedure when creating Custom extensions for entitle management access packages. You can’t run the same Custom extension in both Lifecycle workflows and Access packages, they have to be created separately, but the procedure is the same. You can use the same PowerShell script if you wish however.
Pre-requisites
You need the following resources in Azure already setup – I will not cover setting those up in this blog post.
- Azure Automation Account – Create an Azure Automation account
- An Azure Automation Runbook
- Azure VM (Optional)
The overall the design for running PowerShell script in Lifecycle workflows is like this:
Note: The green path is an optional way of running the PowerShell script that I’ll explain later in this blog post.
A Custom extension is based on an Azure Logic App, so we are going to create a Logic app via the Entra ID Governance portal, and then configure the Logic app to run a PowerShell runbook (script) from an Automation account.
Creating the Custom extension
To create a Custom extension, we first need to navigate to Identity Governance portal in Entra ID, and select Custom extensions and then Add a custom extension – You can use this link: https://portal.azure.com/#view/Microsoft_AAD_LifecycleManagement/CommonMenuBlade/~/customExtension
Now the first thing we need to do is provide a name for the Custom extension. This may seem like simple task, but it’s something you should put some thoughts into, because the odds are you might create a lot of these Custom extensions that will run various PowerShell scripts, so you should think of a good naming convention to help keep it simple for next person looking at it and for your own sake. I personally went with the following naming convention for the Custom extensions:
100 – Entra ID – My PowerShell Script
200 – Active Directory – My Powe Shell Script
300 – Exchange – My PowerShell Script
400 – Teams – My PowerShell Script
500 – SharePoint Online – My PowerShell Script
1001 is a pre-fix that tells me this a Custom extension for Lifecycle Workflows (I use 101 (uneven numbers) for Entitle Management). The name of the “main” service the script runs at, like adding a user to a Share Mailbox using the Exchange Online PowerShell module. My PowerShell Script is the same name as the PowerShell script that I have added as a run book to my Automation Account. By taking the sample of adding a user to shared mailbox, the name would then be: 300 – Exchange – Add user to shared mailbox X
With the naming of the Custom extension out of the way, you need to provide a description for it as well (mandatory), this should again be something that makes it clear to the next person reading it and yourself what the Custom extension do.
When name and description is added, select next in the bottom to continue, we then need to configure the behavior of the task – where the is two choices: Launch and continue or Launch and wait.
Select, Launch and wait. The reason for this is we want the Logic app to “signal” back to the Lifecycle Workflow if job is successful or not so that we may take action if it not successful. You can read more about monitoring of Lifecycle Workflow here: https://www.christianfrohn.dk/2024/05/31/monitor-lifecycle-workflows-status-in-entra-id-governance/
The wait time is up to you do decide. When set to 30 minutes, the Lifecycle Workflow will consider the task in progress for up to 30 min, or until it gets a signal back with a status from the logic app about status whether it ran successful or not. If the status is failed in the logic app, the task in your Lifecycle Workflow will be marked as failed.
Leave the Response authorization to system-assigned managed identity (default)
Then press next – We are now at the point where the Logic app will be created, you need to select the Azure subscription and resource group you want the Logic app to be created in, and then choosing a name. This should be the same as the name you choose in the first step (But without spaces)
Press Create a logic app and wait. You will then be able to press Review + create at the bottom, when the deployment of the Logic app is completed. As last step in the next window, press create to complete the creation of the Custom extension.
The Custom extension is now created and should now be visible to you in the list of Custom extensions.
Steps to run PowerShell script in the Logic App
Now that we have created the logic app, we need to put it together with the Automation Account. The Automation account will be responsible for running the PowerShell script, the logic app’s part is to tell the Automation account what PowerShell script to run. In this part we are going to “connect” the automation with the Logic app.
Start by navigating to the Logic app that was created – you can use this link: Logic apps – Microsoft Azure to find in the list, once you located it, select it.
Now select Logic app designer in the window.
Notice the Tag (green) on the Logic app, this will help you to identify “where a Logic app belongs” – The tag is set doing creation of the logic app
It’s in the designer we are going to add the Automation Account – Start by pressing the + between the two default tasks in the logic, and then add an action.
In search box that opens up, search for Azure Automation, and then select Azure Automation in the search results.
Select Create Job.
After you selected Create job, you will be presented with an authentication method to choose from. Provided it with a fitting name first. Then select the authentication type you are most comfortable with. I’m going to use Logic Apps Managed Identity.
OAuth default, Logic Apps Managed Identity and Service principal authentication requires the following permission on the Resource group: Automation Operator.
Before you will be able to select any values in the next step, you need to navigate to the Resource group where the Automation account is located (in a new tab) and add the Automation Operator permission to the Logic App. Like this:
When you have done this, you might need to re-add the Create Job in your logic app in order to able to select any values. (Remember to select Yes in Wait for job)
Subscription: The Azure subscription where the automation account is created.
Resource Group: Resource Group where the automation account is created.
Automation Account: The name of the Automation Account
Wait for Job: Yes
Runbook name: The name of the PowerShell script you want to run in the life Cycle Workflow
Now add a new step by selecting the “+” again and Add Azure Automation and Get status of job, and then add the same information again, with the only difference being you need to ad Job ID in the last box like so:
Now you are done, select save in the top of window.
We have now configured a Logic App to run a PowerShell runbook (Script) in an Automation account that is being trigger by any Lifecycle workflow that we choose to add the Custom extension task to. Before we start testing what we just created. I want to share with you how to can run the PowerShell scripts on a domain joined Azure VM instead and why you should consider it.
The virtual Machine (Optional)
When you set out with the desire to run PowerShell scripts in Lifecycle Workflows you will eventually run into some walls when it comes to accessing resources like Active Directory or Exchange on-premises or even an Azure Key Vault to get credentials. The solution for this could be an Azure Virtual machine (VM) that is domain joined and then using the VM to run the PowerShell scripts (runbooks) from the Automation Account. This is called a Hybrid Worker. The basic of this is that instead of running your PowerShell scripts in Azure (on the Automation account so to speak), you are running them on the Aure VM instead. By doing so you won’t run into authentication or line-of-sight problem with on-premises resources, and by enabling a Managed Identity on the VM, you are able to provide the VM with access to an Azure Key Vault where you can safely store credentials. You can read more about that part here: https://www.christianfrohn.dk/2024/04/30/securely-storing-and-retrieving-credentials-with-azure-key-vault-in-powershell-scripts/
You are also able to cherry pick witch PowerShell scripts you want to run on the VM and which PowerShell scripts you want to run directly on the Automation account.
Here is how to setup a Hybrid worker:
Start by navigating to your Automation Account and then select Hybrid Worker Groups in the left side menu, and then select Create hybrid worker group
You will then need to type in a name for your Hybrid worker group:
The next step is to add the VM you want to use in your hybrid worker group – Select Add Machine and select it from the list. You only need to select one – By selecting more than one VM for your hybrid worker you are only achieving redundancy. All jobs will be process on the same VM regardless. Only in the event of the first VM being offline will the jobs run on the second one.
When the VM is selected, press Add in the bottom of the page, and in the next window select Review + create, and then finally create.
The deployment of Hybrid Worker will take a few minutes. You don’t need to do anything else at the point.
Now the Hybrid Worker has been configured you can then select Hybrid Automation Worker Group in the Logic App task Create job from earlier. Fill out the Hybrid Automation Worker group name and save it, then the Logic app will now run Automation account PowerShell Runbook (script) on the VM in your Hybrid Worker group.
Note: You have to write the name of in Hybrid Automation Worker Group you. You can’t select from a drop-down menu.
Wrapping up and testing
The logic App and the Automation has now been combined to run PowerShell script and you have also been shown the option to run the PowerShell script on a Azure VM for more convenience. Now is the time to test it out.
We are going to create a Lifecycle Workflow based on the Onboard pre-hire employee template (but it can be template you want), and in the task selection we are going to select Run a Custom Task Extension
Now click on Run a Custom Task Extension – You will then need to provide a name for this task and selecting the Custom extension we build earlier:
Select Save, and select review + create and then create.
Now in your Lifecycle Workflows list, select the one you just created with the Custom extension task and select Run on demand
Then select a user you want to test it with, and select Run workflow – You should then be able to see status of the task in a few seconds in Workflow History of the Lifecycle workflow you selected
You can also navigate your PowerShell script on Automation Account to see the output of the code:
One more thing
I know this blog post I lengthy, but I want to leave you with something more than a “Hello world” PowerShell script. You will probably wonder: How can you pass the object id or the UPN of the user that the Lifecycle workflow is being used on, into the PowerShell code when you run commands like Update-MgUser or set-mailbox etc.
Add this code to your PowerShell script in your Automation Account:
Then in the Lifecycle Workflow Logic app go to the Create job step and select Add new Parameter, you will then be able to see Runbook Parameter ObjectIdOrUPN, select it, and then in dynamic content select Subject.UserPrincipalName
Then save the Logic app and run the Lifecycle Workflow on demand again on the user you want. Now the output from the Runbook jobs should look like this:
Over the next couple of days/weeks I will try to share some of the PowerShell scripts I’m using in my production environment to help inspirer you for your Custom extension task. Stay tuned!
- I regeret not using LW (Lifecycle Workflow) and EM (Entitle Management) instead of 100, 101, 200, 300 etc. ↩︎