
What is the deal, everybody!!! I am back yet again. Sit back and try to relax. Take your mind off of all the stressful stuff going on in the world and get excited to read about using Power Automate for Active Directory task automation for (also known as Active Directory Domain Services or AD DS). Not only is this about using Power Automate for Active Directory tasks, it is about using cloud services to make this happen! We will be using Microsoft Power Automate to orchestrate this and we will also be using Microsoft Azure Automation.

Keep it together!

Overview

In part one of this blog series, I demonstrated how you can use Power Automate to automate tasks against Azure AD via the Microsoft Graph. This is a continuation of that post. We will be adding additional actions to the flow we started creating previously. In essence, we will connect to Azure Automation and kick off a PowerShell runbook. The runbook job will be submitted and picked up by a hybrid worker in my on-prem environment. The PowerShell script (using the AD DS PowerShell module) will run as a service account with limited Active Directory rights and will update the risky users going back to the scenario from from the previous blog post. Here is an article list for this blog series for reference:

Article List

Getting Started

First, you’ll want to login to the Power Automate web portal again. Additionally, you will need to have the Azure Portal open for the Azure Automation related tasks. Lastly, you will need the following prerequisites:

A Windows or Linux server to install and configure the Hybrid worker agent which has: Outbound internet connectivity AD DS PowerShell module Connectivity to AD DS domain controller

An Azure Log Analytics workspace for heartbeat logging and to obtain the agent installer package

Administrative rights to install the hybrid worker package

An Azure Automation Account to configure the PowerShell runbook

Configure Prerequisites

In this section we will walk through the steps to get us up to the point where we can add some actions to our existing Power Automate flow so we can use Power Automate for Active Directory tasks. This includes creating and configuring the Azure Automation account, creating a PowerShell script to run against AD DS, creating a service account in AD DS and installing as well as configuring the hybrid worker agent.

Azure Automation Account Setup

To create an Azure Automation account, follow the steps here. During the creation of the account, you have the option of creating a Run As account. This is not useful for us in this scenario as the Run As account will not be able to obtain permissions to our AD DS forest.

When deploying an automation account, keep the pricing in mind. You do get 500 free minutes every month to do some Proof-of-Concept testing which is useful!

Hybrid Worker Agent Server Configuration

The steps below walk through how to set up the hybrid workers to connect to the Azure Automation Account. Keep in mind that you will probably want more than one agent server running the hybrid worker agent for high availability. It may make sense to have a hybrid worker server in two different Active Directory sites. Also, you may want to create more than one worker group if you want to have different sets of servers running separate sets of runbooks. The hybrid worker is a critical component needed to use Power Automate for Active Directory tasks.

Navigate to the newly created Azure Automation account blade Under the ‘Process Automation’ section click on the ‘Hybrid worker groups’ blade Click the ‘Configure’ button

Clicking on the ‘Configure’ button shows a blade which has a link to the hybrid worker setup documentation

You can download the Windows or Linux agent from the Advanced settings blade of your log analytics workspace

Install the agent using the setup wizard and make sure the ‘Connect to Azure Log Analytics’ option is selected Enter the Workspace ID and key copied previously

Navigate to the Logs blade in the Log Analytics workspace and run the following query to validate the agent is able to connect to the Azure service:

Heartbeat | where Category == "Direct Agent" | where TimeGenerated > ago(30m) | project TimeGenerated, ComputerIP, Computer, Category, OSType, Type

After a few minutes, you should see some events returned similar to the following:

If all is working as expected, heartbeat events will appear in the query results

Open a cloud shell in the Azure portal by clicking the cloud shell button in the top right of the browser

The cloud shell is a terminal window that appears in your browser!

Run the following cmdlet to enable the Automation Account service for the the agent server (this automatically sends a job to the agent server to download the Automation Account agent files and the hybrid registration PS module within a couple of minutes)

Set-AzOperationalInsightsIntelligencePack -ResourceGroupName <Automation Account Resource Group Name> -WorkspaceName <Log Analytics workspace name> -IntelligencePackName "AzureAutomation" -Enabled $true

On the agent server, navigate to the following path: C:\Program Files\Microsoft Monitoring Agent\Agent\AzureAutomation The folder in that path is the version number of the agent. Make sure to take note of this. Run the following cmdlets (be sure to update the file path with the version number referenced earlier):

Set-Location "C:\Program Files\Microsoft Monitoring Agent\Agent\AzureAutomation\<version>\HybridRegistration" Import-Module .\HybridRegistration.psd1

In the Azure portal, navigate to your Azure Automation account created earlier and click on the keys blade. Be sure to record the following highlighted fields:

Record the Primary access key and URL values

Run the following cmdlet on the agent server and update the parameters with the real values from your environment:

Add-HybridRunbookWorker –GroupName <Provide a name for the new group> -EndPoint <Url> -Token <String>

Navigate to the ‘Hybrid worker groups’ blade in your Azure Automation account and verify the newly added agent server is listed

Your agent server should appear on the hybrid workers blade

Add the AD DS PowerShell module to the agent server by running the following command:

Add-WindowsCapability –Online –Name “Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0”

Test the AD DS PowerShell module by running Get-ADDomain on the hybrid worker server to ensure you receive a response Repeat steps these steps for each hybrid worker node in your environment.

NOTE: The steps for the cloud shell and the Set-AzOperationalInsightsIntelligencePack cmdlet only need to be executed once for any given workspace

AD DS Preperation

As mentioned earlier, you need to ensure there is connectivity between the server with the hybrid worker agent installed and at least one domain controller in the AD DS forest. Other than that there is not a lot of preparation required for AD DS. A service account will be required to execute the tasks in our runbook script. In this example, we are following the principal of least privilege. I have created a service account in Active Directory which has been delegated rights to manage user accounts using the good old fashioned delegation wizard.


The Service Account for the hybrid worker has delegated rights for user objects

If your organization has more stringent requirements, feel free to manually delegate rights on the OUs required. One other important note is to keep the service account credentials handy. We will need to store them in the Azure Automation account later on!

PowerShell Runbook Setup

Back a few years ago when I used to write a lot more PowerShell code for automation of tasks related to various Office 365 and AD DS tasks I had a management server with a bunch of scheduled tasks in an on-prem datacenter. Every once in a while the server would have an issue or get patched and the scheduled tasks would stop running. Of course we had logging and alerting in place for these jobs but it was a lot of overhead to keep this management server going.

Benefits of using Azure Automation Runbooks

The beauty of Azure Automation is you can run these very same scripts in the cloud! No more worrying about a management server. These hybrid worker servers have no overhead or management required (other than normal maintenance activities and compliance requirements you would expect for an enterprise organization). As long as you have more than one hybrid worker server within a hybrid worker group you have high availability! The hybrid worker servers make an outbound connection to Azure to standby for jobs to run (no inbound firewall rules required).

Steps for Azure Automation Runbook Creation

There is no configuration required on these servers after the initial setup is completed. It is worth noting that you can create other types of runbooks including Python runbooks. Here are the steps required to set up the PowerShell runbook:

Open the Azure portal and navigate to your Azure Automation account Locate the ‘Shared Resources’ section and click on the ‘Credentials’ blade Click the ‘Add a credential’ button and enter your service account credentials from the last section

The service account credentials are securely stored in the Azure Automation account and are not retrievable

Locate the ‘Process Automation’ section and click on the ‘Runbooks’ blade Click on the ‘Create a runbook’ button (or you can import a runbook including an existing .PS1 file) Provide a name for the runbook and select ‘PowerShell’ as the runbook type This brings you to the edit blade, enter the PS code below:

###Script to disable user account in on-prem AD #Set Parameters param ( [parameter(Mandatory = $true)] [string]$ImmutableId, [parameter(Mandatory = $true)] [string]$UserObjectId ) #Import Modules Import-Module ActiveDirectory #Set Variables $ErrorActionPreference = "Stop" $Creds = Get-AutomationPSCredential -Name 'SVC-ADWorker' #Output Result Function Function OutputResult($result,$UserObjectId,$ObjectGUID,$Exception){ If ($result -eq "Error") { Write-Output "$result : The attempt to disable the user account with Azure AD ObjectId $UserObjectId failed due to the following error:`r`n`r`n$Exception" } Else { Write-Output "$result : User with Azure AD ObjectId $UserObjectId was successfully disabled." } } #Set Force Change Password at Next Login Flag Function Function SetFlag ($ImmutableId,$UserObjectId) { Try { $ObjectGUID = [GUID][system.convert]::frombase64string($ImmutableId) Set-ADUser -Identity $ObjectGUID -Enabled $false -Credential $creds } Catch { $ErrorMessage = Write-Output $Error[0].Exception.Message return OutputResult -Result "Error" -UserObjectId $UserObjectId -ObjectGuid $ObjectGUID -Exception $ErrorMessage } If ($Result -ne "Error") { return OutputResult -Result "Success" -UserObjectId $UserObjectId -ObjectGuid $ObjectGUID } } SetFlag -ImmutableId $ImmutableId -UserObjectId $UserObjectId

DISCLAIMER: This is just basic sample code I wrote to quickly test these concepts.

Runbook Overview and Key Items

Before moving on I wanted to call out some items and provide a summary of what the script is doing. Please note:

We are setting mandatory parameters named ImmutableId and UserObjectId which are both being set in the Power Automate flow (remember this was in part one of this blog series)

We are importing the AD DS PowerShell module (this is not usually required with PS v3 or higher as far as I recall, but I am doing it anyway!)

The Get-AutomationPSCredential cmdlet is being used to retrieve the service account credentials (notice the password is not required for this!) using the name property defined when the credentials were added to the Automation Account

The Set-ADUser cmdlet is used to disable users in AD DS

The Power Automate flow is going to kick off this runbook as a job later in this post

Runbooks could be triggered directly from the Automation Account manually, via a web hook or a schedule

PowerShell Runbook Test

For this section, you will need to identify a test user in AD DS you can disable. You will need to obtain the values required for our mandatory variables (ImmutableId and UserObjectId) If you recall, these values are actually the id property and the onPremisesImmutableId property in the Microsoft Graph. You can pull down these properties a few different ways. One way is to run this query against the Microsoft Graph (using Graph Explorer, Postman or your scripting language of choice): https://graph.microsoft.com/beta/users/?$select=UserPrincipalName,displayName,id,onPremisesImmutableId

Test Steps

Select one of these users and record the id and onPremisesImmutableId attribute values. Here is how you can test the PowerShell runbook:

Based on where we left off at the previous section, we should be on the “Edit PowerShell Runbook” blade Click the ‘Test pane’ button

The test pane button allows the runbook to be tested without having to publish the runbook

Enter the mandatory parameters of the AD DS test user This is important! : Under ‘Run Settings’, click on the ‘Hybrid Worker’ selection and select the correct Hybrid Worker group in the drop down menu

Selecting the ‘Hybrid Worker’ button allows the job to be executed by a hybrid worker server

Click the ‘Start’ button After the job is queued and submitted the status should change to completed If successful, the script output should appear similar to the following:

Success message from the PS runbook

If the runbook test operation was successful validate the user was disabled in AD DS Click the Publish button to make the runbook available which will allow us to trigger it via Power Automate

The publish button makes the runbook available in the Azure Automation account

Update Power Automate Flow for AD DS Automation Tasks

If you are still with me, you have made it to the point where we are able to add an action to the existing flow we built in Power Automate from the first part of the blog series. This part is the easiest of them all as we have already finished all of the hard work! You will need to navigate to your existing flow in the Power Automate web portal to complete this section.

First, we need to add the SP (service principal) that was created in part one of this blog series and give it Azure ‘Automation Operator‘ rights: Navigate to the Azure Automation account in the Azure Portal

Click on the ‘Access Control (IAM)’ blade

Click the ‘Add’ button

Search for the name of the SP that was used in the HTTP Connector settings and assign the ‘Automation Operator’ role to it

Use the display name of your SP to search for it in the Access Control blade

In the Microsoft Flow portal add an Azure Automation ‘Create job’ action to the existing flow Fill out the fields for the action so they match the configuration of your Azure Automation account and your PS runbook:

Field Name Field Description Subscription Azure subscription where your Azure Automation account exists Resource Group Resource Group where your Azure Automation Account exists Automation Account The Azure Automation account where your runbook exists Hybrid Automation Worker Group The name of the hybrid worker group as it appears in the Automation Account hybrid worker blade Runbook name The PS runbook you created which will disable users in AD DS Wait for Job Select ‘Yes’ so the flow will wait for job to complete, suspend, or fail before moving on (suspend could mean there is an issue with the hybrid worker agent or hybrid worker server) Runbook Parameters There are two mandatory parameters defined in our runbook. Make sure to add the dynamic content below using the variables we have already defined in our flow (UserObjectId and ImmutableId)

We are specifying the mandatory parameters of the runbook here in the flow action!

NOTE: Make sure to fill out the ‘Hybrid Automation Worker Group’ field so the job runs on one of your hybrid worker servers and not in Azure!

Click on the elipsis on the top of the newly created ‘Create Job’ action and select ‘+ Add New Connection’

Clicking the ‘Add new connection’ item allows you to add a service account or SP so the action can run in a specific context

Click the ‘Connect with Service Principal’ option on the bottom left of the dialog box which appears Add the same details previously used for the HTTP connector (this will allow the Azure Automation actions in your flow to use the same SP context throughout the whole flow)

Use the same SP details from the app registration created for use with the HTTP connector actions from part one of this blog series

Add another action by searching for ‘Get Job Output’ which is another Azure Automation item Fill out the action details so it appears similar to the image below ensuring the Job ID from the previous action is entered into the Job ID field using the Dynamic content dialog box:

This action will allow the output of the runbook to appear in the results of the flow run history

Ensure this action is also using the same SP connection and then save the flow by clicking the ‘Save’ button Perform a test by clicking the ‘Test’ button! Navigate to the ‘Flow Runs’ page

Click the ‘Flow Runs Page’ link to see a run history of the flow

Click on the start time for the test flow run which was just executed

The Flow Runs page shows a run history for the flow being viewed

Navigate to the newly added Azure Automation ‘Get Job Output’ action and click on it so it expands Confirm that the Output field shows the following:

The job output will appear the same way as it did when we tested the PS runbook directly in the Azure Automation runbook Test Pane

Repeat the validation check for all users in the RiskyUsersArray by cycling through each item in the array (the output of the flow run history allows you to view each item in an array)

Use the previous and next links to view all items in an array

You are done! You have now used Power Automate to disable users in AD DS!

Final Thoughts

We made it! If you are reading this you have seen a demonstration on how we can use Power Automate for Active Directory. We used the power of a Power Automate flow, Azure Automation runbooks and Azure Automation hybrid workers.

Power Automate Error Handling

You might be thinking about the flow and noticing we didn’t really add any logic within the flow for error handling and alerting. You would be correct. However, this is definitely possible and one of the most important actions you can use for this is Expressions. Here is an example:

This illustrates an expression which checks if the call to the MS Graph had a 204 response or not and results in different actions based on the expression result

This expression checks the status code returned from the Graph call we made earlier in our flow. If the status code is 204, the Azure Automation runbook job is submitted. If the status code is not 204 (failure) the object is added to the failed users array for further action such as alerting and logging. Speaking of alerting, that is easy to do as well using the ‘Send an email’ action in the Office 365 Outlook collection.

Your Feedback Matters

I hope this blog series was valuable for you and illustrated how you can use Power Automate to automate tasks in Azure AD (or really any task MS Graph supports) and how to use Power Automate for Active Directory tasks (or really any task you can complete in your datacenter using any PowerShell module). Please leave comments and share feedback! Thanks for reading. If you want to check out a post on Azure AD Tenant Restrictions check this post out. Until next time, rock on and stay safe!