/ PowerShell

Managing Azure AD MFA with PowerShell

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

        Sample Output
        PS C:\temp> "[email protected]", "[email protected]" |
            Set-xMSOLUserMFA -Action Disable -Verbose
        VERBOSE: [BEGIN  ] : Setting MFA Options:
        VERBOSE: [PROCESS] : PROCESSING [email protected] -Action Disable
        VERBOSE: [PROCESS] : CHECK USER: [email protected] | GET SUCCESSFUL :)
        VERBOSE: [PROCESS] : SET MFA [Disable] | SET SUCCESSFUL :)

        VERBOSE: [PROCESS] : PROCESSING [email protected] -Action Disable
        VERBOSE: [PROCESS] : CHECK USER: [email protected] | GET SUCCESSFUL :)
        VERBOSE: [PROCESS] : SET MFA [Disable] | SET SUCCESSFUL :)
        Status     UserPrincipalName      UserMethods MFAState
        ------     -----------------      ----------- --------
        SUCCESS :) [email protected]
        SUCCESS :) [email protected]

    #>

    [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

Steve Rackham

Steve Rackham

By day, IT professional with advanced skills across a broad spectrum of technology stacks and enterprise platforms. By night, happiest learning while tinkering under the hood and writing :)

Read More
Managing Azure AD MFA with PowerShell
Share this