Problem:
Sometimes while testing or if an application does not support ADAL you need to disable MFA, particularly if you have admin accounts. The problem is that when you disable MFA you also lose your user methods and settings, and are required to set it up again. Ugh.
If you want to enable or disable MFA in bulk the GUI is clunky. Seriously.
Solution:
We can solve both of these problems with a PowerShell function. Take a look.
function Set-xMSOLUserMFA {
<#
.SYNOPSIS
Supports disabling or enabling MFA for a user or users (through pipeline).
.DESCRIPTION
Supports disabling or enabling MFA for a user or users (through pipeline).
When disabling MFA the function will maintain the users current MFA methods
so that they dont need to be set up again.
.EXAMPLE
Enable MFA for the following users.
"[email protected]", "[email protected]" | Set-xMSOLUserMFA -Action Enable
Set-xMSOLUserMFA -UserPrincipalName [email protected] -Action Disable -Verbose
.NOTES
AUTHOR : Steve Rackham
BLOG : https://siliconwolf.net
GIT : https://github.com/siliconWOLF
TWITTER : https://twitter.com/siliconW0LF
LINKEDIN : https://nz.linkedin.com/in/steverackham
#>
[cmdletbinding()]
param (
[Parameter(
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
HelpMessage = "Enter the UserPrincipalName (UPN)"
)]
[String]$UserPrincipalName,
[Parameter(
Mandatory,
HelpMessage = "What SET action to perform: ON | OFF (Save User Settings) "
)]
[ValidateSet ('Enable', 'Disable')]
[string]$Action
) # END PARAMS
BEGIN {
Write-Verbose "[BEGIN ] : Setting MFA Options:"
} # END BEGIN
PROCESS {
Write-Verbose "[PROCESS] : PROCESSING $UserPrincipalName -Action $Action"
# SET OUTPUT CUSTOM OBJECT TO $NULL (AVOID ANY ERRORS WITH PREVIOUS CALLS).
$Output = [pscustomObject] @{
'Status' = $null
'UserPrincipalName' = $null
'MFAState' = $null
'UserMethods' = $null
} # END-PSCUSTOMOBJECT
# CAPTURE THE USER OBJECT AND PROPERTIES.
try {
$User = Get-MSOLUser -UserPrincipalName $UserPrincipalName -ErrorAction Stop
Write-Verbose "[PROCESS] : CHECK USER: $($USER.UserPrincipalName) | GET SUCCESSFUL :)"
}
# IF CANNOT FIND THE USER PRODUCE A WARNING AND SET THE OUTPUT STATUS AS AN ERROR FOR REPORTING.
# RETURN THE OUTPUT AND GO NO FURTHER.
catch {
Write-Warning "CHECK USER: $UserPrincipalName | FAILURE :("
Write-Warning $Error[0].Exception.Message
$Output.Status = "ERROR!"
Return $Output
} # END TRY/CATCH
switch ($Action) {
'Enable' {
# Build the MFA Settings object.
$mfa =
New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$mfa.RelyingParty = "*"
$mfa.State = "Enabled"
$mfa.RememberDevicesNotIssuedBefore = (Get-Date)
# Parameters for the SET operation. Splatting to make it easier to read...
$params = @{
UserPrincipalName = $User.UserPrincipalName
StrongAuthenticationRequirements = $mfa
} # Params
} # END ON
'Disable' {
# Capture the users current settings.
$userAuthMethods = $User.StrongAuthenticationMethods |
Select-Object MethodType, IsDefault
$setUserAuthMethods = @()
# Build the users current MFA methods.
foreach ($userAuthMethod in $userAuthMethods) {
$mfa =
New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$mfa.IsDefault = $userAuthMethod.IsDefault
$mfa.MethodType = $userAuthMethod.MethodType
$setUserAuthMethods += $mfa
} # END FOREACH ($userAuthMethod in $userAuthMethods)
# Parameters for the SET operation. Splatting to make it easier to read...
$params = @{
UserPrincipalName = $User.UserPrincipalName
StrongAuthenticationRequirements = @()
StrongAuthenticationMethods = $setUserAuthMethods
} # Params
} # END OFF
} # END SWITCH
try {
Set-MsolUser @params -ErrorAction Stop
Write-Verbose "[PROCESS] : SET MFA [$Action] | SET SUCCESSFUL :)"
$Output.Status = "SUCCESS :)"
}
catch {
Write-Warning "[PROCESS] : SET MFA [$Action]:| SET FAILURE :("
Write-Warning $Error[0].Exception.Message
$Output.Status = "ERROR :("
} # END TRY/CATCH
# REPORTING
$User = Get-MSOLUser -UserPrincipalName $User.UserPrincipalName
$Output = [pscustomObject] @{
'Status' = $Output.Status
'UserPrincipalName' = $User.UserPrincipalName
'UserMethods' = $User.StrongAuthenticationRequirements.MethodType
'MFAState' = $User.StrongAuthenticationRequirements.State
} # END-PSCUSTOMOBJECT
Write-Output $Output
} # END PROCESS
} # END FUNCTION
Summary
Phew. Hope that helps.
While I have tried to make this as robust as practical, you should never, ever simply copy and paste code, especially in production. Read it. Understand it. Learn and share