Table of contents
In a previous article about using Entra ID B2B users, I needed to set up some user extensions. In that article, I also mentioned that many customers needed to access the environment, which meant that multiple users needed to be changed.
As this is an ongoing business and we like to automate these kinds of tasks, I looked for an automation option. Creating a script wasn’t the problem, but using it to connect to Entra ID by entering credentials every time or putting them into the script was the hard part of the search.
After some time, I stumbled upon Azure Automation, where you can create runbooks (scripts) and add them to a scheduled task.
What’s Azure automation
Azure Automation is a cloud-based service provided by Microsoft Azure that enables users to automate various manual, time-consuming, and repetitive tasks across Azure and on-premises environments. It offers tools for process automation, configuration management, and update management. Using PowerShell or Python to automate complex tasks, users can create, schedule, and manage runbooks (workflow scripts). Azure Automation also provides Desired State Configuration (DSC) to define and enforce system configurations. Additionally, it integrates with other Azure services, allowing users to orchestrate end-to-end workflows for efficient and consistent management of resources in the Azure cloud.
Creating an Azure Automation account
We must create an Azure Automation account before using Azure Automation and deploying our script. Sign in to the Azure portal and search for Azure Automation. Click on “Create” and follow the wizard, here, you will see the output of “Review + Create.”
Powershell Modules
When using Azure Automation, verifying the availability of the intended PowerShell modules is crucial. For this situation, the following modules are essential:
- Microsoft.Graph.Authentication:
Responsible for establishing connections (Connect-MgGraph) and severing connections (Disconnect-MgGraph) to MgGraph. - Microsoft.Graph.Groups:
Required for retrieving group members (Get-MgGroupMember) and obtaining information based on a group ID (Get-MgGroup). - Microsoft.Graph.Identity.SignIns:
Necessary for initiating invitations (New-MgInvitation) through identity sign-ins. - Microsoft.Graph.Users:
Utilized for fetching user information (Get-MgUser) and facilitating user updates (Update-MgUser).
To add the modules to the Azure Automation account, open the account and go to “Modules,” then follow the below steps to add the module. Repeat these steps until all required modules are added:
- Click on “Add a Module”
- Select “Browse from gallery”
- Click on “Click here to browse from gallery”
- Search the module and select
- click on “Select” at the bottom of the page.
- Now set the “Runtime Version”. In our case, it’s 5.1.
- Click “Import”
To verify if all of the required Powershell modules are available or still being imported, click on “Modules” within the Azure Automation account.
After adding the appropriate Powershell modules, we need to add the required permissions.
Permissions
To get our script working with the appropriate permissions, we need the following permissions:
- User.ReadWrite.All
- User.Invite.All
- Directory.Read.All
As we use a Managed Identity, we need to add the permissions using Graph Explorer. First, we must connect to the Graph Explorer: https://aka.ms/ge and sign in using an account in the correct tenant. You can’t switch tenant/directory when using Graph Explorer.
Step 1: Finding the Service Principal
We first need to find the service principal for our managed identity (automation account). To do so, we need to perform the following query, where displayname equals our Managed Identity name, in our case, “CTX-DaaS”:
GET https://graph.microsoft.com/v1.0/servicePrincipals?$search="displayName:CTX-Daas"
Write down the ID. We need this in step 4.
Step 2: Finding the Microsoft Graph Service principal ID
As the Microsoft Graph API always has the following AppId “00000003-0000-0000-c000-000000000000”, we can create a filter and only look for this AppId. We can use the following query to get the ID:
GET https://graph.microsoft.com/v1.0/servicePrincipals?$filter=appId eq '00000003-0000-0000-c000-000000000000'
Write down the ID. We need this in steps 3 and 4.
Step 3: Finding the Application Roles (Permissions) id
Now, we need to get the App Role IDs, as these are always the same and well-documented by Microsoft. We can search for them on the following site: https://learn.microsoft.com/en-us/graph/permissions-reference.
- User.ReadWrite.All: “741f803b-c850-494e-b5df-cde7c675a1ca”
- User.Invite.All: “09850681-111b-4a89-9bed-3f2cae46d706”
- Directory.Read.All”: “7ab1d382-f21e-4acd-a863-ba3e13f7da61”
When you would like to use Graph Explorer, this is also possible, and you follow the below step: As we can’t add a filter to the query, we need to use the old-fashioned way and use CTRL+F to search for the appropriate IDs. First, we need to run the below query, replacing the {ServicePrincipalID} with the ID we found in step 2.
GET https://graph.microsoft.com/v1.0/servicePrincipals/{ServicePrincipalID}/approles
After running the query, we get a list of all the Application Roles. Luckily, the output only shows 100 results. Now, use CTRL+F to search for the permissions mentioned above and write down the IDs.
Step 4: Assigning the Application Roles to the Managed Identity
To assign the Application Roles, we need the following IDs:
- PrincipalId (step 1)
- ResourceId (step 2)
- AppRoleIId (step 3)
To add the Application Roles to the Managed Identity, we need to use a POST query in combination with a Content-Type application/json in the header and the following request body:
POST https://graph.microsoft.com/v1.0/servicePrincipals/{your-graph-serviceprincipal-id}/appRoleAssignedTo
Content-Type: application/json
{
"principalId": "{your-managed-identity-service-principal-id}",
"resourceId": "{your-graph-serviceprincipal-id}",
"appRoleId": "{your-app-role-id}"
}
Repeat step 4 until you assigned all the Application Roles.
Step 5: Verifying the permissions in Entra ID
Now that we have set the Application Roles (Permissions), we can verify this within the Entra ID portal. To do so, we go to Entra ID, Enterprise Applications, then set the Application Type to “Managed Identities”.
Now, we select the Managed Identity we create to perform the Azure Automation tasks and go to Permissions. Here, we will see the permissions we just assigned.
Creating the runbook
Now that we have set all the appropriate permissions, we can start creating the runbook. For this case, we will look for users who are members of a certain security group called “CTX-DaaS-B2B” and verify if the Extension (Created in the previous blog) and CreationType are equal to Invitation. We will check this for each user who’s a member of the security group and check each setting, and if needed, we will apply changes.
Below, you can see the script we are using to automate the process of invitations and setting the extensions so the user can sign in to the Citrix Environment, which is mentioned in the previous blog.
Connect-MgGraph -Identity -NoWelcome
$Group = "CTX-DaaS-B2B"
$group = Get-MgGroup -Filter "DisplayName eq '$Group'"
$members = Get-MgGroupMember -GroupId $group.Id
$ExtensionUPN = "extension_c8ef4d2cb6694d76974c5a05be13affa_guestShadowUPN"
$ExtensionSID = "extension_c8ef4d2cb6694d76974c5a05be13affa_guestUserOnPremSID"
$CreationType = "Invitation"
$RedirectURL = "https://newyard.Cloud.com"
$UserMessage = "You have been invited to the Citrix New Yard environment. `
Redeem this invitation to get started and you’ll be redirected to the Citrix New Yard"
foreach ($member in $members) {
$user = Get-MgUser -UserId $member.Id -Property ID, DisplayName, Mail, UserPrincipalName, UserType, CreationType, ExternalUserState, OnPremisesSecurityIdentifier
if ($user.UserType -ne "Guest"){
Write-output "User $($user.displayname) is Member, changing to Guest!"
Update-MgUser -UserId $user.Id -UserType "Guest"
}
$UserExtensions = (Get-mguser -UserID $user.Id -Property $ExtensionUPN).AdditionalProperties
if ($UserExtensions.keys -NotContains $ExtensionUPN) {
Write-Output "User $($user.displayname) has nu Extension, updating UPN and SID Extensions"
Update-mguser -UserId $user.id -AdditionalProperties @{$ExtensionUPN = $user.UserPrincipalName}
Update-mguser -UserId $user.id -AdditionalProperties @{$ExtensionSID = $user.OnPremisesSecurityIdentifier}
}
Write-output "$($user.displayname) has CreationType $($user.creationType)"
if ($user.CreationType -ne $CreationType) {
Write-output "User $($user.displayname) isn't invited, inviting user!"
New-MgInvitation -InvitedUser $user -InvitedUserEmailAddress $user.Mail -InviteRedirectUrl $RedirectURL -SendInvitationMessage:$true -InvitedUserMessageInfo:@{CustomizedMessageBody=$UserMessage}
}
}
disconnect-MgGraph
We published the runbook to production once we tested it (using the test pane in the PowerShell runbook) and verified everything was correct. This can be done using the Publish button inside the PowerShell runbook.
Create a Schedule
Now that we have the runbook published, we can start with scheduling the runbook. As we start migrating users to the new environment, we have set the schedule to run every hour. When the migration is done, we can change the schedule to once a day, as we normally don’t make that many changes or create multiple users a day.
Let’s start with creating the schedule. We go to the Schedules from the Automation account and add a schedule.
Once the schedule is created, we need to assign the runbook to the schedule. Therefore, we go to the runbook, click on the “Link to schedule” button, click on the link to a schedule in your runbook, select the correct schedule, and click OK. To verify if the runbook is successfully linked to the schedule, click “Schedules” within the runbook and verify that the correct schedule is linked.
Verify the Azure Automation Task
Now that we successfully have followed all the steps:
- Creating Azure Automation Account
- Add PowerShell Modules
- Set permissions
- Create the runbook
- Create and linked a Schedule
We can now see in the overview of the Azure Automation account if the runs are completed successfully. As you can see in the screenshot below, the job has run once and was successful. The users will receive an invite every hour unless they already received one.
Conclusion
We can conclude that Azure Automation is a powerful tool for automating repetitive tasks, such as sending invites to new guests. I couldn’t achieve this without the guidance of GoToGuy’s blog, where the Graph Explorer is explained to configure all the necessary permissions. I will undoubtedly utilize Azure Automation more frequently now that I know its capabilities.