Deploying users with pre-registered MFA
A couple of weeks ago a friend of mine asked would it be possible to pre-register MFA for users in Azure AD. For short, yes it is!
In this blog, I’ll show how to pre-register OTP and SMS MFA methods using AADInternals’ Register‑AADIntMFAApp and Set‑AADIntUserMFA.
Introduction
When deploying users to Azure AD, one can provide the basic user information, including the password. Nowadays, when MFA is (hopefully) required in most organisations, pre-registering MFA would make it easier for users to start using Microsoft cloud services.
Also, when deploying users for trainings or demos, pre-registered MFA would remove one extra step from the users.
Deploying users
There are many ways to deploy users, one could use the Azure AD portal or one of the many PowerShell module options.
To pre-register MFA, the user deployment method doesn’t matter, as long as we know the users’ username and password.
The following script examples will use users.csv file as an input. The file must have the following columns populated:
Column | Description |
---|---|
Username | UPN of the user |
Password | Password of the user (complexity requirements) |
MSOnline module
The following script will provide users using MSOnline module.
# Connect to MSOnline
Connect-MsolService
# Read usernames from a .csv file
$users = Import-Csv -Path .\users.csv
# Deploy users
foreach($user in $users)
{
# Extract the name from UPN
$name = $user.Username.Split("@")[0]
# Deploy the user
New-MsolUser -UserPrincipalName $user.Username -DisplayName $name -PasswordNeverExpires $true -ForceChangePassword $false
}
AzureAD module
The following script will provide users using AzureAD module.
# Connect to AzureAD
Connect-AzureAD
# Read usernames and passwords from a .csv file
$users = Import-Csv -Path .\users.csv
# Deploy users
foreach($user in $users)
{
# Create a password profile
$passwordProfile = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordProfile
$passwordProfile.Password = $user.Password
$passwordProfile.EnforceChangePasswordPolicy = $false
$passwordProfile.ForceChangePasswordNextLogin = $false
# Extract the name from UPN
$name = $user.Username.Split("@")[0]
# Deploy the user
New-AzureADUser -UserPrincipalName $user.Username -DisplayName $name -MailNickName $name -AccountEnabled $true -PasswordProfile $passwordProfile
}
MgGraph Module (Microsoft Graph PowerShell SDK)
The following script will provide users using MgGraph module.
# Import AADInternals and get access token to MgGraph (so no need to give consent to MgGraph app)
Import-Module AADInternals
$at = Get-AADIntAccessTokenForMSGraph
# Connect to MgGraph
Connect-MgGraph -AccessToken $at
# Read usernames and passwords from a .csv file
$users = Import-Csv -Path .\users.csv
# Deploy users
foreach($user in $users)
{
# Create a password profile
$passwordProfile = @{
Password = $user.Password
ForceChangePasswordNextSignIn = $false
}
# Extract the name from UPN
$name = $user.Username.Split("@")[0]
# Deploy the user
New-MgUser -UserPrincipalName $user.Username -DisplayName $name -MailNickName $name -AccountEnabled -PasswordProfile $passwordProfile
}
Deploying MFA
OTP
The following script will deploy a new OTP app for the given users and saves the OTP secret to a .csv file.
The script below is using a users.csv file as an input. The .csv file must have the following columns deployed:
Column | Description |
---|---|
Username | UPN of the user |
Password | Password of the user |
The script is using Register-AADIntMFAApp function to register a new OTP app to each user. This can take up to 30 seconds per user. You can use -Verbose switch to see what’s happening under-the-hood.
The OTP secret will be saved in the users.csv in OathSecretKey column. The secret can then be used in authenticator apps, like Microsoft Authenticator and Google Authenticator.
# Import AADInternals
Import-Module AADInternals
# Read usernames and passwords from a .csv file
$users = Import-Csv -Path .\users.csv
# Deploy MFA
foreach($user in $users)
{
# Create PSCredentials object
$creds = [pscredential]::new($user.Username,($user.Password | ConvertTo-SecureString -AsPlainText -Force))
# Get access token for MySignins
$at = Get-AADIntAccessTokenForMySignins -Credentials $creds
try
{
# Deploy new OTP
$result = Register-AADIntMFAApp -AccessToken $at -Type OTP
# Set the OTP secret
$user | Add-Member -NotePropertyName "OathSecretKey" -NotePropertyValue $result.OathSecretKey
}
catch{}
}
# Export to a .csv file
$users | Export-Csv -Path .\users.csv
The resulting .csv file have the following columns:
Column | Description |
---|---|
Username | UPN of the user |
Password | Password of the user |
OathSecretKey | OTP secret to be used with authenticator apps |
SMS
The following script will set MFA phone number and select SMS as the default MFA method for the given users.
Note: This script is using AADGraph API, which is scheduled to be deprecated by June 30, 2023.
The script below is using a users.csv file as an input. The .csv file must have the following columns deployed:
Column | Description |
---|---|
Username | UPN of the user |
PhoneNumber | Phone number of the user in format “+CCC NNNNNNN” where CCC is the country code and NNNNNNN the phonenumber without the leading zero. |
The script is using Set-AADIntUserMFA function to set MFA phone number of each user and select SMS as the MFA method.
# Import AADInternals
Import-Module AADInternals
# Get access token
Get-AADIntAccessTokenForAADGraph -SaveToCache
# Read usernames and passwords from a .csv file
$users = Import-Csv -Path .\users.csv
# Deploy MFA
foreach($user in $users)
{
try
{
# Set the phone number and the default MFA method
Set-AADIntUserMFA -UserPrincipalName $user.Username -PhoneNumber $user.PhoneNumber -DefaultMethod OneWaySMS
}
catch{}
}
Summary
AADInternals can be used to automate pre-registering OTP and SMS MFA methods for users.
AADInternals will “verify” the OTP app automatically, so it can be used right after registration (as well as SMS method).
References
- Microsoft: Authentication methods in Azure Active Directory - OATH tokens
- Microsoft: Azure AD password policies