It’s time to Set Users’ MFA with a nice little function. This function is designed to gather information and set a user’s MFA with the method you want. It even allows you to reset and disable MFA. We are going to break this blog up a little differently. We will go through each area of the function as the breakdown. Let’s get started.
Function and Parameters
The first thing we are going to build out is the Function and the Parameters. The function command is like a wrapper for a script. This way you can add this to your PowerShell tool kit module.
Function Set-SHDUserMFA {
[CmdletBinding()]
param(
)
}
Parameters
User Principal Name
The parameters are where people select items that they want. We have a few here. The First parameter is the User Principal Name. This is like an email address. This parameter is a List of strings. Basically, you are allowed to add more than one user name to this field. To make life easier we have set a Parameter set name. The PSN is called UPN. So the end user can either type UPN or UserPrincipalName for this parameter. This parameter is Mandatory.
Function Set-SHDUserMFA {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ParameterSetName = 'UPN', Position = 0),ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true,][string[]]$UserPrincipalName,
)
}
Status
Afterward, The status parameter allows you to set the MFA status that you want. Here we have Enabled, Disable, Enforced, and Reset. The Enabled will enable MFA. Disable of course disables. Enforced will skip the text and go straight to the Apps. Finally, the reset will reset all the MFA token flags. This is how you Set Users’ MFA. This parameter isn’t mandatory.
Function Set-SHDUserMFA {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ParameterSetName = 'UPN', Position = 0)][string[]]$UserPrincipalName,
[Parameter(Mandatory = $false)][validateset("Enabled", "Disable", "Enforced", "Reset")][string]$Status,
)
}
Info
Finally, we have the Info switch. This switch tells the script to produce an in-depth MFA report on the user. This parameter is not mandatory. We choose not to make it mandatory because we might not care.
Function Set-SHDUserMFA {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ParameterSetName = 'UPN', Position = 0)][string[]]$UserPrincipalName,
[Parameter(Mandatory = $false)][validateset("Enabled", "Disable", "Enforced", "Reset")][string]$Status,
[Parameter()][Switch]$Info
)
}
Begin
PowerShell Version
Chiefly, I stated that we were targeting one section at a time. Here in the begin, we will check the environment that we are working with. The MSOnline module only runs in PowerShell 5 and not PowerShell 7. Thus we need to check. Thus, we use the PS Version Table variable. This will produce the PowerShell version number. We can test against that and end the script if the user is using PowerShell 7. In the below example, we are using the write-error to let the user know what’s going on.
#Checks PS version
if ($PSVersionTable.psversion.major -ne 5) {
Write-Error "Your Powershell Version is $($PSVersionTable.psversion.major). Msonline service only works on Powershell 5. Ending."
end
}
Module Test
Aftward, we test the MSOnline module. The Get-InstalledModule tests the installation status of MSOnline. Running MSOnline command tests the status of the module load. Afterward, we either connect or error out.
#Checks to see if the module is installed if not, tells the end user to install.
if (Get-InstalledModule -name MSOnline -ErrorAction SilentlyContinue) {
#Checks to see if the msolservice if it isn't connected, we connect
if (-not (Get-MsolDomain -ErrorAction SilentlyContinue)) {
Connect-MsolService
}
} else {
Write-Error "MSOnline Services are not installed. Please install the MSOnline services with the following command `n Install-module MSOnline `n"
}
Process – Set Users’ MFA
Confirming the User
Next, we start the process section. The process is where most of the meat and potatoes are. Firstly we have the User Principal Name loop. This loop is very important. The parameter we created beforehand has multiple possible inputs. Thus, it’s best to loop through those possible inputs. We are going to call the Internal variable UPN.
foreach ($UPN in $UserPrincipalName) {
#Do Stuff Yall
}
After that, we will be building out a try/catch to test if the user exists. The try/catch will give us the ability to test the user without blowing up the script. Get-MsolUser is the command we will be using with an error action of “stop”. The catch will contain the error write-out.
#Checks if the user exists, if not, ends the upn and writes an error.
try {
$User = Get-MsolUser -UserPrincipalName $UPN -ErrorAction Stop
} catch {
Write-Error $_.Exception.Message
}
The Switch
Now that we have the user verified, it’s time to move forward. We start with the switch. The switch is a process of if statements but formatted nicely. In our case, we will be building the switch of the status parameter. If the user selected blah, then we take blah action. Here is the basic structure of a switch. It’s switch and the parameters name. Then each possible answer to that parameter. The status is a “validate set” parameter. This means all the answers are inside the parameter.
switch ($Status) {
#If enabled then we enable mfa
'Enabled' {
#Do Something
}
'Enforced' {
#Do Something
}
'Reset' {
#Do Something
}
'Disable' {
#Do Something
}
}
Enabled
The enabled will enable the MFA of a target user. We went over some of this code in a previous blog. Firstly, we want to create a new object. This object is a Microsoft Online Administration object that focuses on Strong authentication requirements. Once we create this object we will assign properties different values. Finally, we use the Set-Msoluser to set the user accordingly.
$sar = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$sar.RelyingParty = "*"
$sar.State = "Enabled"
Set-MsolUser -UserPrincipalName $UPN -StrongAuthenticationRequirements $sar
Enforced
On the other hand, We have enforced. Enforced forces the user to use an authentication app. We will follow the same path as before. Create the object, and set the properties. Then set the object to the user with the set-msoluser command. Notice the sar.state property.
$sar = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$sar.RelyingParty = "*"
$sar.State = "Enforced"
Set-MsolUser -UserPrincipalName $UPN -StrongAuthenticationRequirements $sar
Reset
Before we created an object, this time we only need a command. We are using the Reset-Msolstrongauthenticationmethodbyupn. Don’t even try saying the command without spaces. This is a beast of a command, but it works. What it does is it resets the methods that the user uses to login in. If the user selected an authentication app, this will allow the user to set another one up. Great command if a user lost their phone.
Reset-MsolStrongAuthenticationMethodByUpn -UserPrincipalName $UPN
Disable
Finally, we have “disable”. Unlike before methods we will be setting the strong authentication requirements to NOTHING! ABSOLUTELY NOTHING! (UHF reference).
Set-MsolUser -UserPrincipalName $UPN -StrongAuthenticationRequirements @()
This is what the switch block looks like when fully put together.
switch ($Status) {
#If enabled then we enable mfa
'Enabled' {
$sar = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$sar.RelyingParty = "*"
$sar.State = "Enabled"
Set-MsolUser -UserPrincipalName $UPN -StrongAuthenticationRequirements $sar
}
#if enforced, we enforce mfa
'Enforced' {
$sar = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$sar.RelyingParty = "*"
$sar.State = "Enforced"
Set-MsolUser -UserPrincipalName $UPN -StrongAuthenticationRequirements $sar
}
#if reset, resets mfa
'Reset' { Reset-MsolStrongAuthenticationMethodByUpn -UserPrincipalName $UPN }
#if disable, it removes mfa requirements
'Disable' { Set-MsolUser -UserPrincipalName $UPN -StrongAuthenticationRequirements @() }
}
Info Flag
Grab user Info
Finally, the Info Flag piece. Here we are going to be gathering information about the user. It’s at the end of the command because we want the information after we set the user’s MFA. The first step we take is to grab user information. We do this with the Get-Msoluser command. “But couldn’t we use the previous $user grab?” The answer is no because we want the most up-to-date. We want to reflect on the changes we have made beforehand.
#Grabs the user information
$User = Get-MsolUser -UserPrincipalName $UPN -ErrorAction Stop
Confirm Strong Authentication Requirements
Afterward, we want to test this data. The first test is, does the user have strong authentication requirements. “Strongauthenticationrequirements” property is our target. Since the property has data, we place that data into the “MFAState” parameter. However, if it doesn’t, we put “Disabled” into this variable.
#If it has a strong authentication requirement we grab the state, if the state is blank, then we return disabled
if ($User.StrongAuthenticationRequirements) {
$MFAState = $User.StrongAuthenticationRequirements.State
} else {
$MFAState = 'Disabled'
}
Find the Default
Next, we want to grab the default method type. We do this with a where-object that searches for “isdefault”. Then we expand the method types.
#grabs the Strong authentication methods
$MethodType = $User.StrongAuthenticationMethods | Where-Object { $_.IsDefault -eq $true } | select-object -ExpandProperty MethodType
Determine the Default
This will produce a string if there is a default. However, it will produce null if there is not. So we test to see if the $MethodType has data. Once we do that we start another switch. I like switches. Inside this switch we are comparing the unique names to real names. This makes life easier and allows non-admin answers they can understand. Here is a list of names and their translations.
- OneWaySMS = SMS
- TwoWayVoiceMobile = Phone call
- PhoneAppOTP = TOTP
- PhoneAppNotification = Authenticator App
However, it’s none of these, we just say, disabled.
#if the methods are not blank, we find out which one is the right method. and make since of the code. If it is blank, we say disabled.
if ($MethodType) {
switch ($MethodType) {
'OneWaySMS' { $DefaultMethodType = 'SMS' }
'TwoWayVoiceMobile' { $DefaultMethodType = 'Call' }
'PhoneAppOTP' { $DefaultMethodType = 'TOTP' }
'PhoneAppNotification' { $DefaultMethodType = 'Authenticator App' }
}
} else {
$DefaultMethodType = 'Disabled'
}
PS Custom Object
Finally, the PS custom object. This is where we return the information the user wants. The PowerShell custom object will contain the following information, the username, display name, the mfa state, and the default method type.
[PSCustomObject]@{
UserPrincipalName = $User.UserPrincipalName
DisplayName = $User.DisplayName
MFAState = $MFAState
DefaultMethodType = $DefaultMethodType
}
The last thing we do is we null out the methodtypes. Sometimes PowerShell 5 will carry over these items in a loop.
#Nulls out the method type variable because we are in a loop.
$MethodType = $null
Conclusion
When you Set Users’ MFA, you make people mad. However, life gets way more secure. This function is inside my tool belt and it helps me out almost every day. I can push hundreds of users through it quickly. I will leave you with the script itself.
The Script
Function Set-SHDUserMFA {
<#
.SYNOPSIS
Sets the MFA status of a user.
.DESCRIPTION
The script can grab the Status information of MFA of a user. It can set the users mfa to enabled, enforced, disabled, and even reset the mfa of a user.
.PARAMETER UserPrincipalName
A list of strings, the user principal names of the users you wish to preform the actions against.
.PARAMETER SetStatus
The action you wish to preform
Enabled: Enables MFA
Disable: Disables MFA
Reset: Resets MFA
Enforced: Enforces MFA
.PARAMETER Info
Grabs UPN, Displayname, The MFA state, and Default Method Type
.NOTES
Name: Set-SHDUserMFA
Author: therandomadmin
Version: 1.0
DateCreated: 8/3/2022
.LINK
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ParameterSetName = 'UPN', Position = 0,ValueFromPipeline = $true,valueFromPipelineByPropertyName = $true,)][string[]]$UserPrincipalName,
[Parameter(Mandatory = $false)][validateset("Enabled", "Disable", "Enforced", "Reset")][string]$Status,
[Parameter()][Switch]$Info
)
BEGIN {
#Checks PS version
if ($PSVersionTable.psversion.major -ne 5) {
Write-Error "Your Powershell Version is $($PSVersionTable.psversion.major). Msonline service only works on Powershell 5. Ending."
end
}
#Checks to see if the module is installed if not, tells the end user to install.
if (Get-InstalledModule -name MSOnline -ErrorAction SilentlyContinue) {
#Checks to see if the msolservice if it isn't connected, we connect
if (-not (Get-MsolDomain -ErrorAction SilentlyContinue)) {
Connect-MsolService
}
}
else {
Write-Error "MSOnline Services are not installed. Please install the MSOnline services with the following command `n Install-module MSOnline `n"
}
}
PROCESS {
#Starts the UPN loop
foreach ($UPN in $UserPrincipalName) {
#Checks if the user exists, if not, ends the upn and writes an error.
try {
$User = Get-MsolUser -UserPrincipalName $UPN -ErrorAction Stop
}
catch {
Write-Error $_.Exception.Message
}
#Checks status
switch ($Status) {
#If enabled then we enable mfa
'Enabled' {
$sar = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$sar.RelyingParty = "*"
$sar.State = "Enabled"
Set-MsolUser -UserPrincipalName $UPN -StrongAuthenticationRequirements $sar
}
#if enforced, we enforce mfa
'Enforced' {
$sar = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$sar.RelyingParty = "*"
$sar.State = "Enforced"
Set-MsolUser -UserPrincipalName $UPN -StrongAuthenticationRequirements $sar
}
#if reset, resets mfa
'Reset' { Reset-MsolStrongAuthenticationMethodByUpn -UserPrincipalName $UPN }
#if disable, it removes mfa requirements
'Disable' { Set-MsolUser -UserPrincipalName $UPN -StrongAuthenticationRequirements @() }
}
#if you flip the flag for info we grab the info.
if ($Info) {
#Grabs the user information
$User = Get-MsolUser -UserPrincipalName $UPN -ErrorAction Stop
#If it has a strong authentication requirement we grab the state, if the state is blank, then we return disabled
if ($User.StrongAuthenticationRequirements) {
$MFAState = $User.StrongAuthenticationRequirements.State
}
else {
$MFAState = 'Disabled'
}
#grabs the Strong authentication methods
$MethodType = $User.StrongAuthenticationMethods | Where-Object { $_.IsDefault -eq $true } | select-object -ExpandProperty MethodType
#if the methods are not blank, we find out which one is the right method. and make since of the code. If it is blank, we say disabled.
if ($MethodType) {
switch ($MethodType) {
'OneWaySMS' { $DefaultMethodType = 'SMS' }
'TwoWayVoiceMobile' { $DefaultMethodType = 'Call' }
'PhoneAppOTP' { $DefaultMethodType = 'TOTP' }
'PhoneAppNotification' { $DefaultMethodType = 'Authenticator App' }
}
}
else {
$DefaultMethodType = 'Disabled'
}
#creates a ps object and displays all the information collected
[PSCustomObject]@{
UserPrincipalName = $User.UserPrincipalName
DisplayName = $User.DisplayName
MFAState = $MFAState
DefaultMethodType = $DefaultMethodType
}
#Nulls out the method type variable because we are in a loop.
$MethodType = $null
}
}
}
END {}
}
More Links: