Using Azure Automation with Managed Identities to remove unredeemed B2B guests

A walkthrough of using Managed Identity with Azure Automation using PowerShell MS Graph SDK module for cleaning up stale invited B2B users

· 8 min read
Using Azure Automation with Managed Identities to remove unredeemed B2B guests
Using Managed Identity with MS Graph SDK PowerShell V2 Preview

I was having a discussion the other day about helping organizations to cleanup ungoverned guests in their organization.  While the discussion was cenered around using Azure AD Access Reviews to review the existing guests to determine if they should remain or be removed,  I wanted to see about reducing the number of guests that need to be reviewed first.

With the recent announcement of Microsoft Graph PowerShell v2 is now in public preview, half the size and speeds up automation I knew one of the exciting new features is to connect with the module using managed identities, so I thought I would see what that experience would be look like for this solution.

👋
We recently published a doc on using the V3 PowerShell module for Exchange Online which uses managed identities which you can find at Use Azure managed identities to connect to Exchange Online PowerShell | Microsoft Learn and look forward for a similar doc on using managed identities with MS Graph SDK PowerShell module in the future.

The v2 module is currently in public preview, so I'll walk through the steps on how you can import this prerelease version into your Azure Automation environment to use in your runbook.

I also want to use other features of the platform to limit the scope of what the automation can manage, so we'll be using the dynamic administrative units feature to scope the process only to guest users.

So below we will walk through:

  • Using the Microsoft Graph SDK Module v2 pre-release to execute PowerShell commands using managed identities
  • Constrain the ability to remove guests only in a specific administrative unit
  • Automate identifying guests which were invited over XX days ago, but who never redeemed the invitation. (This can happen due to email typos, etc.)

Create the Azure Automation Account

Running PowerShell without local machines

  1. You can create the Azure Automation account in the Azure portal
Create an Automation Account

2. Confirm the Managed Identity Service Principal ID

In this case the ObjectID of the Service Principal that represents the system managed identity is 84836a0e-c213-4184-b7fe-10cc88ad13c6 as shown below.

Retrieve the Service Principal Object ID for the system assigned managed Identity

Grant the Managed Identity Permissions

Granting the SP the ability to manage users in a dynamic administrative unit

For this scenario we are going to grant the service principal the User Administrator role over a dynamic administrative unit which is scoped to users with userType == guest.

👋
We are using the Azure AD directory role of "User Administrator" after consulting the Least privileged roles by task - Azure Active Directory - Microsoft Entra | Microsoft Learn for the task of deleting users.
  1. Create an administrative unit for guests to be managed

Using the Entra admin portal, create the Administrative Unit (AU) that will contain all the guests in the tenant

Add Administrative Unit

2. Update the administrative unit to be dynamic assignment

After the administrative unit is created, open it's properties and set the Membership type to Dynamic user

Update Membership type to dynamic user

3. Configure Dynamic membership rules for AU membership

For this scenario, we want only guest users to be contained in this administrative unit, so we will use a dynamic filter based upon (user.userType -eq "Guest") and save the AU configuration.

Guest User Filter for membership
👋
There can be a few different types of "External" or "Guest" users. In this scenario we are scoping to the default when a user is invited using Azure AD B2B. See https://learn.microsoft.com/en-us/azure/active-directory/external-identities/authentication-conditional-access#assigning-conditional-access-policies-to-external-user-types-preview for the other types of guests.

4. Assign the Service Principal the User Administrator role on the AU

In order to grant the AU scoped permissions, we can assign the service principal for he managed identity we created the User Administrator role on the AU scope as a permanent active assignment.

You can use the SP object ID or display name to select the member in the dialog for assignment.

Select the Service Principal for the managed identity
Assign active permanent assignment

Since we are scoping the application identity permissions using directory roles to the scope of the AU, we also need to assign Directory Reader to the tenant scope.  

Assign Directory Reader at the tenant scope for the SP
Permantent Active Assignment

Import Modules into Azure Automation Account

In order to do these tasks using the public preview of the V2 MS Graph SDK PowerShell module, we'll manually import these into our 7.1 runspace.

😊
I expect once the modules move from prerelease to release you can add them directly in the Azure Automation module picker instead of manually importing the pre-release versions. PowerShell 7.1 support in Azure Automation is also currently in preview as of the time time of this post. I personally only target PS 7.x or newer for maximum compatibility across devices since I often use Windows/Linux/MacOS for PowerShell.

We will also be using the MSIdentityTools module from the PowerShell Gallery since it already contains a cmdlet (Get-MsIDUnredeemedInviteUser) which makes it easy for us to enumerate guest users who exist in the tenant who were invited in the past but have not redeemd the invitation.

  1. Download the latest v2 version of the Microsoft.Graph.Authentication module

You can visit the PowerShell Gallery and see the Manual Download link of the nupkg for the v2 version of the Microsoft.Graph.Authentication module (This would be the 2.0.0-preview4 version at the time of this post)

Click on the manual download tab, and click on the Download raw nupkg file which will start the download.   Once download is complete, rename file to microsoft.graph.authentication.zip

2. Download the latest v2 version of the Microsoft.Graph.Users module

You can visit the PowerShell Gallery and see the Manual Download link of the nupkg for the v2 version of the microsoft.graph.users module (This would be the 2.0.0-preview4 version at the time of this post)

Click on the manual download tab, and click on the Download raw nupkg file which will start the download.   Once download is complete, rename file to microsoft.graph.users.zip

3. Import microsoft.graph.authentication pre-release module into Azure Automation

We will first import the microsoft.graph.authentication modul since it is a dependency for other subsequent modules.

In the module section, click add a module. and browse for file for the microsoft.graph.authentication.zip file you downloaded and renamed earlier.  Set the runtime version to 7.1 (preview) and click import.

Import the microsoft.graph.Authentication v2 module

It will take some time to import which you can monitor by filtering on the Importing status.

Module import status

4. Import microsoft.graph.users pre-release module into Azure Automation

Once the previous model has completed importing, we will now import the microsoft.graph.users module

In the module section, click add module. and browse for file for the microsoft.graph.users.zip file you downloaded and renamed earlier.  Set the runtime version to 7.1 (preview) and click import.

importing microsoft.graph.users module

5. Import the MSIdentityTools module from the PowerShell Gallery

Since this module exists in the PowerShell Gallery we don't need to manually import it.

In the module section, click add module. and browse from gallery for"MSIdentityTools" module, and select it.  Set the runtime version to 7.1 (preview) and click import.

Browser PowerShell Gallery for MSIdentityTools module
Import MSIdentityTools module
💡
You may need to assign Directory.Read.All application permissions to the SP since the MSIdentityTools module checks for scopes currently, and will error if it is null. This is not needed for the base Microsoft.Graph cmdlets.

Create Runbook for PowerShell code

Using MS Graph SDK Module V2 pre-release

  1. Create the Runbook in your Azure Automation account

Using the Azure Portal, you can create new runbook in the Azure Automation account you created earlier.  Give it a name that makes sense to your organization, a PowerShell runbook type and a 7.1 (preview) runtime version.

2. Edit Runbook to insert your PowerShell Code

Here is an example piece of code to enumerate guests invited before XX days ago, who have not redeemed, to use as a the population to remove from the tenant.  This is just a quick example, so use your own logic to determine the actions you want to take to remove the unredeemed users.

💡
While this is based on when the user was invited and not redeemed, you may also do additional checks to see if the user is in any mail-enabled groups as recipient in case they are only receiving email but have not signed in to redeem.
Import-Module -Name Microsoft.Graph.Authentication -MinimumVersion 2.0.0
Import-Module -Name Microsoft.Graph.Users -MinimumVersion 2.0.0
Import-Module MSIdentityTools

$InvitedDaysAgo = 90
Connect-MgGraph -Identity
#Write-Output (Get-MgContext|out-string)

$StaleGuests = Get-MsIdUnredeemedInvitedUser -InvitedBeforeDaysAgo $InvitedDaysAgo|where-object -FilterScript {$_.UserType -eq 'Guest'}


Write-Output ("{0} Guests to be removed!" -f $($StaleGuests|measure-object).count)

if ($StaleGuests.count -lt 100 -and $StaleGuests.count -gt 0)
{
foreach ($u in $StaleGuests)
{
    Write-Output ("Removing Unredeemed User {0} [{1}] ({2})" -f $u.UserPrincipalName,$u.UserId,$u.mail)
    try
    {
        Remove-mgUser -UserId $u.UserId -ErrorAction Stop
        Write-Output ("{0} User has been removed!" -f $u.UserPrincipalName)
    }
    catch
    {
        Write-Error $_
    }
}
}
else
{
    Write-Output ("Stale Guests count ({0}) is 0 or greater than 100. Skipping!" -f $($StaleGuests.count))
}

Save code in your runbook.  You can now use the test pane to execute your code to see the results.

Test Results showing connection using Managed Identity

Once tested, you can now publish your runbook and schedule it to run on a schedule or on-demand.  I would recommend checking out the docs on Configure runbook output and message streams | Microsoft Learn to optimize the information signaling for yoru runbook jobs as well.

On-Demand Run Results

Conclusion

Using Managed Identities is easy with Powershell SDK Module v2

With the pre-release v2 module, we can see how managed identity support helps simplify how we use PowerShell to do automation activities for Entra and Microsoft Graph.  As the previous identity focused PowerShell modules are deprecated I look forward to improving the MS Graph SDK module's capablities and improving the user experience.

Once the modules progress to release and supporting modules are updated to take advantage of the new v2 capabilities, I am excited to see how customers can utilize them to use minimal code when needed, while they also use no-code solutions like Logic Apps for workflows and identity actions in their environment.