Before we start: I hate PowerShell’s lack of consistency for error handling so I did not bother to handle all error since this is only a code snippet.
I wanted to check how one can set and force MFA authentication right from the start. While there is no real practical use for this, it was a good exercice.
Nota: All names where generated using Fake Name Generator so don’t bother sending me GDPR notices. As lawyers say: This is a work of fiction. Names, characters, business, events and incidents are the products of the author’s imagination. Any resemblance to actual persons, living or dead, or actual events is purely coincidental.
For my example we need to create a csv file (we could use a SQL database or anything else, but csv it is…).
DisplayName, MailNickName, UserPrincipalName, Password, Group, Done, Mobile
"Denise Berthelette", "dbe", "denise.berthelette@opium.io", "ShittyPassword001;", "Marketing", 0,"+33 712345678"
"Robert Chesnay", "rch", "robert.chesnay@opium.io", "ShittyPassword002;", "Sales", 0,"+33 712345679"
"Jacqueline Couturier", "jco", "jacqueline.couturier@opium.io", "ShittyPassword003;", "Accounting", 0, "+33 712345670"
We first start the script with the usual parameters definition and modules check (once again, this is a code snippet and not intended for production…)
param (
[switch]$delete = $False,
[switch]$mfa = $False
)
## --- Module Checks
if ((Get-Module -ListAvailable -Name MSOnline) -And (Get-Module -ListAvailable -Name AzureADPreview)) {
Import-Module MSOnline
Import-Module AzureADPreview
}
else {
Write-Host "Please install the following modules: MSOnline & AzureADPreview"
exit 1
}
clear-host
Write-Host @"
--------------------------
AZure AD User Utils by jme
--------------------------
use -delete to remove users
use -mfa to activate SMS OTP during account creation
"@
write-host "-- Verifying Azure AD authentication" -ForegroundColor Cyan
try {
$session = Get-AzureADCurrentSessionInfo -ErrorVariable error
}
catch {
write-host "-- No Connection to Azure AD : launching Connect-AzureAD" -ForegroundColor Red
Connect-AzureAD -TenantDomain "opium.onmicrosoft.com" -ErrorVariable myError# TODO: use AzADServicePrincipal -ea 0
Connect-MsolService -ea 0
}
try {
write-host "-- Importing users.csv where the 'done' field is not 1" -ForegroundColor Cyan
$users = import-csv "users.csv" | where-object {$_.Done -eq "0"}
write-host "-- Initialisation of the AzureAD password model" -ForegroundColor Cyan
$PasswordProfile = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordProfile
}
catch { Write-Host "Fucked-up the initialisation procedure :(" -ForegroundColor Red
Exit 1
}
if (!$delete) {
Write-host "-- Creating users" -ForegroundColor Yellow
} else {
Write-host "-- DELETING USERS" -ForegroundColor Yellow
}
ForEach ($user in $users) {
$_DisplayName = $($user.DisplayName)
$_MailNickName = $($user.MailNickName)
$_UserPrincipalName = $($user.UserPrincipalName)
$PasswordProfile.Password = $($user.Password)
$_Group = $($user.Group)
$_Done = $($user.Done)
$_Mobile = $($user.Mobile)
if (!$delete) {
try {
# ---------------- CREATING USER
$groupID = Get-AzureADGroup -SearchString $_Group
try {$test = [bool] (Get-AzureADUser -ObjectId $_UserPrincipalName -ea 0)} catch {$test = $false} #pwshell = caca...
if (-Not $test) {
write-host " - Creating user " $_DisplayName -ForegroundColor Green
$createdUSer = New-AzureADUser -AccountEnabled $True -DisplayName $_DisplayName -PasswordProfile $PasswordProfile -MailNickName $_MailNickName -UserPrincipalName $_UserPrincipalName -Mobile $_Mobile
Add-AzureADGroupMember -ObjectID $groupID.ObjectID -RefObjectId $createdUser.ObjectID
} else {
write-host " - exists, skipping..." -ForegroundColor Red
}#if
-Mobile $_Mobile
) is different from the SMS FMA number (-MobilePhone $_Mobile
)
That’s where the MSOnline module enters into play. While it is deprecated, AzureAD (even in preview) does not have the facility to manage MFA parameters. Once again, because it is a code snippet, I did put all methods. However, you can find more information on Microsoft’s website. if ($mfa) {
# ---------------- ENABLING MFA
$test = $False
while (-Not ($test = [bool] (Get-MsolUser -UserPrincipalName $_UserPrincipalName -ea 0))) {
Write-Host "." -NoNewline
Start-Sleep -s 1
}#while
write-host "Activating MFA for " $_UserPrincipalName
## --
$APP = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$APP.IsDefault = $false
$APP.MethodType = "PhoneAppNotification"
$OTP = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$OTP.IsDefault = $false
$OTP.MethodType = "PhoneAppOTP"
$SMS = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$SMS.IsDefault = $true
$SMS.MethodType = "OneWaySMS"
$Phone = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$Phone.IsDefault = $false
$Phone.MethodType = "TwoWayVoiceMobile"
$PrePopulate = @($SMS, $Phone) #We do not set OTP or APP as they are not setup
Set-MsolUser -UserPrincipalName $_UserPrincipalName -MobilePhone $_Mobile -StrongAuthenticationMethods $PrePopulate -ea 0
}#mfa
}#try
catch {
Write-Host " - Error Creating user" $_DisplayName -ForegroundColor Red
}#catch
if (!$error) {
Write-Host "Creation OK" -ForegroundColor DarkGreen
}
} #if NOT delete
if ($delete) {
try {$test = [bool] (Get-AzureADUser -ObjectId $_UserPrincipalName -ea 0)} catch {$test = $false}
if ($test) {
try {
write-host " - Deleting user " $_DisplayName -ForegroundColor Yellow
Remove-AzureADUser -ObjectId $_UserPrincipalName -ea 0
} catch {
Write-Host " - Error DELETING user" $_DisplayName -ForegroundColor Red
}
} else { write-host " - User $_DisplayName not found : SKIPPING" -ForegroundColor Red}
} #if delete
} #Foreach
Exit 0
./NewUser.ps1 -mfa
) we get the following output (as stated, each dot is a 1 second wait event loop)--------------------------
AZure AD User Utils by jme
--------------------------
use -delete to remove users
use -mfa to activate SMS OTP during account creation
-- Verifying Azure AD authentication
-- Importing users.csv where the 'done' field is not 1
-- Initialisation of the AzureAD password model
-- Creating users
- Creating user Denise Berthelette
.......Activating MFA for denise.berthelette@opium.io
Creation OK
- Creating user Robert Chesnay
............Activating MFA for robert.chesna@opium.io
Creation OK
- Creating user Jacqueline Couturier
...............Activating MFA for jacqueline.couturier@opium.io
Creation OK
PS C:\Users\jme\Documents\WindowsPowerShell>
The issue with setting the MFA on behalf of the user is that it more or less kills Microsoft’s nice onboarding journey. My recommendation is to set a strong random password upon user creation and force the user to change it on first connection. They will be forced to do the full MFA onboarding (I sill recommend deactivating SMS and callback (unless Microsft releases their in-house voicecallback with PIN code method for the general public)).
Anyways, the futur is now Microsoft Graph which is good news for me since I fucking hate PowerShell… :).