Script to Bulk Invite Guest Users to Azure Entra ID

Introduction

Last week, I was on service desk duty. It’s not my favorite field of endeavour, and I’m past my due date for that kind of work. However, doing it once in a while is an eye-opener to how disorganized and chaotic many organizations are. Some requests are ideal to solve by automating them and handing them over to the team to leverage. That is how I wrote a script to bulk invite guest users to Azure Entra ID, as I could not bring myself to click through the same action dozens of times in the portal. You can find the script on my GitHub page https://github.com/WorkingHardInIT/BulkInviteGuestUsersToEntraIdAzure

Script to Bulk Invite Guest Users to Azure Entra ID

📌 Overview

This PowerShell script allows administrators to bulk invite guest users to an Azure Entra ID (formerly Azure Active Directory) tenant using Microsoft Graph. It includes retry logic for connecting to Microsoft Graph, supports both interactive and device code login, and reads user details from a CSV file.

✨ Features

  • Connects to Microsoft Graph securely using MS Graph PowerShell SDK
  • Retry logic with customizable attempt count
  • Supports both interactive and device-based authentication
  • Invites guest users based on a CSV file input
  • Allows optional CC recipients in the invitation email (limited to one due to API constraints)
  • Includes meaningful console output and error handling

📁 Prerequisites


📄 CSV File Format

Create a file named BulkInviteGuestUsersToAzureEntraID.csv in the same folder as the script with the following columns:

emailAddress,displayName,ccRecipients
[email protected],Guest One,[email protected]
[email protected],Guest Two,

Note: Only the first ccRecipient will be used due to a known Microsoft Graph API limitation.


🔧 Script Configuration

Open the script and configure the following variables:

$Scopes = "User.Invite.All" # Required scope
$csvFilePath = ".\BulkInviteGuestUsersToAzureEntraID.csv"
$TenantID = "<your-tenant-id-guid-here>" # Replace with your tenant ID
$emailAddresses = $Null # Optional static list of CC recipients

▶️ How to Run

  1. Open PowerShell as Administrator
  2. Install Microsoft Graph module (if not already):Install-Module Microsoft.Graph -Scope CurrentUser
  3. Execute the script:.\InviteGuestsToAzureEntraID.ps1Or specify login type:Test-GraphConnection -TenantID “<tenant-id>” -Scopes $Scopes -UseDeviceLogin

🧠 Function: Test-GraphConnection

This helper function ensures a valid Microsoft Graph session is established:

  • Disconnects any stale Graph sessions
  • Attempts up to $MaxRetries times to connect
  • Verifies that the session is for the specified Tenant ID
  • Supports -UseDeviceLogin switch for non-interactive login (e.g., headless servers)

📬 Inviting Users

The script loops through all entries in the CSV file and sends out personalized invitations using the New-MgInvitation cmdlet.

Each invite includes:

  • Redirect URL (https://mycompany.portal.com)
  • Display name from CSV
  • Custom message
  • Optional CC recipient (only first address is respected by Graph API)

⚠️ Known Issues

  • CC Recipients Limitation: Only the first email in ccRecipients is honored. This is a known issue in the Microsoft Graph API.
  • Multi-user CC: If different users need unique CCs, adapt the script to parse a ccRecipients column with user-specific values.

📤 Example Output

✅ Using device login for Microsoft Graph...
✅ Microsoft Graph is connected to the correct Azure tenant (xxxx-xxxx-xxxx).
✅ Invitation sent to Guest One using [email protected]
⚠️  Skipped a user due to missing email address.
⚠️  Failed to invite Guest Two: Insufficient privileges to complete the operation

🧽 Cleanup / Disconnect

Graph sessions are managed per execution. If needed, manually disconnect with:

Disconnect-MgGraph

📚 References


🛡️ License

This script is provided as-is without warranty. Use it at your own risk. Feel free to adapt and extend as needed.


✍️ Author

Didier Van Hoye

Contributions welcome!

LDAP_ALTERNATE_LOGINID_ATTRIBUTE is a gem

Introduction

The registry value LDAP_ALTERNATE_LOGINID_ATTRIBUTE is a gem. It is found under the HKLM\SOFTWARE hive in the key \Microsoft\AzureMfa. It plays a critical part to get the NPS extension for Azure MFA to work in real-life scenarios.

LDAP_ALTERNATE_LOGINID_ATTRIBUTE is a gem

For the NPS extension for Azure MFA to work we need to have a match between the User Principal Name (UPN) in the on-premises Active Directory and in Azure Active Directory (AzureAD). The mapping between those two values is not always one on one. You can have Azure AD Connect use different a attribute to populate the Azure Active Directory UPN than the on-premises UPN.

There are many reasons you can need to do so and it happens a lot in real-world environments. Changing a UPN is possible but not always in the manner one wants. Sometimes these reasons are technical, political, or process-driven. In the end, you don’t want to break other processes, confuse your users or upset the powers that be. No matter what the reason, what can you don when you cannot change the UPN to make them match up?

LDAP_ALTERNATE_LOGINID_ATTRIBUTE is a gem

When you have installed the NPS extension for Azure MFA you will find part of its configuration in the registry. In there you can add values or leverage existing ones. One of those is LDAP_ALTERNATE_LOGINID_ATTRIBUTE. It allows using the NPS extension for Azure MFA despite the fact the UPN for users does not match between on-premises Active Directory and the UPN in Azure Active Directory.

What it does is instead of sending the on-premises UPN to Azure AD it uses an alternate value. The trick is the select the attribute that was used to populate the Azure AD UPN in scenarios where these do not match. In our example that is the mail attribute.

AD connect uses the mail attribute to populate the Azure AD UPN for our users. So we have [email protected] there.

AD DS mail attribute set to a different value than the UPN.

In our example here we assume that we cannot add an alternate UPN suffix to our Active Directory and change the users to that. Even if we could, the dots in the user name would require a change there. That could get messy, confuse people, break stuff etc. So that remains at [email protected].

Our AD DS UPN is set to the domain name suffix and the account name has no dots.

When we have the NPS extension for Azure MFA set up correctly and functioning we can set the LDAP_ALTERNATE_LOGINID_ATTRIBUTE to “mail” and it will use that to validate the user in Azure and send an MFA challenge.

LDAP_ALTERNATE_LOGINID_ATTRIBUTE to the rescue

Need help configuring the NPS extension for Azure MFA ?

By the way, if your need help configuring the NPS extension for Azure MFA you can read these two articles for inspiration.

Conclusion

There are a lot of moving parts to get an RD Gateway deployment with NPS extension for Azure MFA to work. It would be a pity to come to the conclusion it takes a potentially disruptive change to a UPN, whether on-premises and/or in Azure is required for it to work. Luckily there is some flexibility in how you configure the NPS extension for Azure MFA via its registry keys. In that respect, LDAP_ALTERNATE_LOGINID_ATTRIBUTE is a gem!