Obtenga el estado MFA de los usuarios de Office 365 con Microsoft Graph
Realizar un seguimiento del estado MFA de su usuario es importante para mantener protegido a su inquilino. Por ahora, todavía podemos usar el módulo Msol para esto en PowerShell, pero Microsoft planea retirar este módulo. Así que he recreado mi exitoso script MFA Status con el módulo Microsoft Graph.
Entonces, este nuevo script de estado de MFA puede hacer prácticamente las mismas cosas que el script anterior:
- Enumerar los tipos de MFA configurados de todos los usuarios
- Obtenga todos los usuarios que no tienen MFA habilitado
- Verifique la configuración MFA de un solo usuario
- Comprueba si un usuario es administrador o no
- Obtenga solo los usuarios habilitados y con licencia
Pero con Graph también podemos recuperar un poco más de información que con el módulo anterior. Por lo tanto, ahora también se recupera la siguiente información:
- Nombre del dispositivo autenticador
- Obtenga el método MFA preferido del usuario
- Comprueba si Hello for Business está registrado
- Dirección de correo electrónico registrada para el restablecimiento de contraseña de autoservicio (SSPR)
Lo que actualmente no podemos verificar es si MFA está realmente habilitado o deshabilitado para los usuarios, o si MFA se aplica (por ejemplo, el usuario necesita configurar MFA la próxima vez después de iniciar sesión).
Como siempre, encontrarás el guión completo al final del artículo.
Obtenga el estado MFA con Microsoft Graph y PowerShell
Microsoft Graph se actualiza continuamente y, con las últimas versiones, ya no tenemos que usar los puntos finales beta. Esto significa que podemos conectarnos a Graph de la forma normal con los alcances necesarios para recuperar todos los datos utilizando el cmdlet Get-MgUser.
Una vez que hayamos recopilado todos los usuarios, podemos usar el cmdlet Get-MgUserAuthenticationMethod para obtener todos los detalles de MFA.
Nota
Con Graph no podemos verificar si MFA está habilitado o deshabilitado para el usuario. Solo podemos verificar qué métodos de autenticación están configurados.
Microsoft se está alejando de la configuración MFA por usuario, necesitaremos pasar a políticas de acceso condicional para MFA. Actualmente, MFA se puede deshabilitar para un usuario en particular en el Centro de administración y no podemos detectarlo con Graph.
Sin embargo, si tiene Azure P1 o P2, consulte este script. O aún puede usar el antiguo módulo MSOL para esto, así que asegúrese de verificar también este script si todavía usa MFA por usuario.
Requisitos
Necesitará tener instalado el módulo Microsoft Graph. El script comprobará si el módulo está instalado; de lo contrario, se le dará la opción de instalarlo.
Obtener todos los usuarios y su estado MFA
El script viene con un par de parámetros que podemos usar para ajustar los resultados de la exportación. Pero de forma predeterminada, obtendrá todos los usuarios con licencia, enumerará los administradores y guardará la exportación CSV en la misma ubicación que el script. El script abrirá el archivo CSV cuando esté completo.
Entonces, para obtener todos los usuarios, simplemente podemos ejecutar el script:
# Get all licensed users:
Get-MgMFAStatus.ps1Obtenga solo usuarios sin MFA
Cuando tiene un inquilino grande, probablemente solo desee ver los usuarios que no tienen MFA habilitado. Para hacer esto, puede agregar el interruptor - withoutMFAOly:
Get-MgMFAStatus.ps1 -withOutMFAOnlyVerifique el estado de MFA solo de administrador
El script enumerará a todos los administradores de forma predeterminada, pero también puede verificar el estado de MFA de los administradores solo con el modificador -adminsOnly:
Get-MgMFAStatus.ps1 -adminsOnlyComprobar el estado de un usuario específico o de una selección de usuarios
También es posible comprobar el estado de MFA de un usuario específico. Podemos especificar el nombre UserPrincipal del usuario usando el parámetro -UserPrincipalName:
Get-MgMFAStatus -UserPrincipalName 'johndoe@contoso.com'
El parámetro acepta una matriz de cadenas, por lo que puede separar con comas los usuarios que desea recuperar:
Get-MgMFAStatus -UserPrincipalName 'johndoe@contoso.com','janedoe@contoso.com'Otra opción es utilizar el filtro del cmdlet Get-MgUser y luego canalizar el script Get-MgMFAStatus:
Get-MgUser -Filter "country eq 'Netherlands'" | ForEach-Object { Get-MgMFAStatus -UserPrincipalName $_.UserPrincipalName }El guión completo
El script completo se puede descargar desde mi repositorio de Github, que recomiendo usar para tener siempre la última versión.
Consejo
Obtenga rápidamente el estado de MFA de sus usuarios agregando una referencia al script en su perfil de PowerShell. Lea todo sobre esto en este artículo.
<#
.Synopsis
Get the MFA status for all users or a single user with Microsoft Graph
.DESCRIPTION
This script will get the Azure MFA Status for your users. You can query all the users, admins only or a single user.
It will return the MFA Status, MFA type and registered devices.
Note: Default MFA device is currently not supported https://docs.microsoft.com/en-us/graph/api/resources/authenticationmethods-overview?view=graph-rest-beta
Hardwaretoken is not yet supported
.NOTES
Name: Get-MgMFAStatus
Author: R. Mens - LazyAdmin.nl
Version: 1.2
DateCreated: Jun 2022
Purpose/Change: Added MFA preferred method
.LINK
https://lazyadmin.nl
.EXAMPLE
Get-MgMFAStatus
Get the MFA Status of all enabled and licensed users and check if there are an admin or not
.EXAMPLE
Get-MgMFAStatus -UserPrincipalName 'johndoe@contoso.com','janedoe@contoso.com'
Get the MFA Status for the users John Doe and Jane Doe
.EXAMPLE
Get-MgMFAStatus -withOutMFAOnly
Get only the licensed and enabled users that don't have MFA enabled
.EXAMPLE
Get-MgMFAStatus -adminsOnly
Get the MFA Status of the admins only
.EXAMPLE
Get-MgUser -Filter "country eq 'Netherlands'" | ForEach-Object { Get-MgMFAStatus -UserPrincipalName $_.UserPrincipalName }
Get the MFA status for all users in the Country The Netherlands. You can use a similar approach to run this
for a department only.
.EXAMPLE
Get-MgMFAStatus -withOutMFAOnly| Export-CSV c:\temp\userwithoutmfa.csv -noTypeInformation
Get all users without MFA and export them to a CSV file
#>
[CmdletBinding(DefaultParameterSetName="Default")]
param(
[Parameter(
Mandatory = $false,
ParameterSetName = "UserPrincipalName",
HelpMessage = "Enter a single UserPrincipalName or a comma separted list of UserPrincipalNames",
Position = 0
)]
[string[]]$UserPrincipalName,
[Parameter(
Mandatory = $false,
ValueFromPipeline = $false,
ParameterSetName = "AdminsOnly"
)]
# Get only the users that are an admin
[switch]$adminsOnly = $false,
[Parameter(
Mandatory = $false,
ValueFromPipeline = $false,
ParameterSetName = "Licensed"
)]
# Check only the MFA status of users that have license
[switch]$IsLicensed = $true,
[Parameter(
Mandatory = $false,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
ParameterSetName = "withOutMFAOnly"
)]
# Get only the users that don't have MFA enabled
[switch]$withOutMFAOnly = $false,
[Parameter(
Mandatory = $false,
ValueFromPipeline = $false
)]
# Check if a user is an admin. Set to $false to skip the check
[switch]$listAdmins = $true,
[Parameter(
Mandatory = $false,
HelpMessage = "Enter path to save the CSV file"
)]
[string]$path = ".\MFAStatus-$((Get-Date -format "MMM-dd-yyyy").ToString()).csv"
)
Function ConnectTo-MgGraph {
# Check if MS Graph module is installed
if (-not(Get-InstalledModule Microsoft.Graph)) {
Write-Host "Microsoft Graph module not found" -ForegroundColor Black -BackgroundColor Yellow
$install = Read-Host "Do you want to install the Microsoft Graph Module?"
if ($install -match "[yY]") {
Install-Module Microsoft.Graph -Repository PSGallery -Scope CurrentUser -AllowClobber -Force
}else{
Write-Host "Microsoft Graph module is required." -ForegroundColor Black -BackgroundColor Yellow
exit
}
}
# Connect to Graph
Write-Host "Connecting to Microsoft Graph" -ForegroundColor Cyan
Connect-MgGraph -Scopes "User.Read.All, UserAuthenticationMethod.Read.All, Directory.Read.All" -NoWelcome
}
Function Get-Admins{
<#
.SYNOPSIS
Get all user with an Admin role
#>
process{
$admins = Get-MgDirectoryRole | Select-Object DisplayName, Id |
%{$role = $_.DisplayName; Get-MgDirectoryRoleMember -DirectoryRoleId $_.id |
where {$_.AdditionalProperties."@odata.type" -eq "#microsoft.graph.user"} |
% {Get-MgUser -userid $_.id }
} |
Select @{Name="Role"; Expression = {$role}}, DisplayName, UserPrincipalName, Mail, Id | Sort-Object -Property Mail -Unique
return $admins
}
}
Function Get-Users {
<#
.SYNOPSIS
Get users from the requested DN
#>
process{
# Set the properties to retrieve
$select = @(
'id',
'DisplayName',
'userprincipalname',
'mail'
)
$properties = $select + "AssignedLicenses"
# Get enabled, disabled or both users
switch ($enabled)
{
"true" {$filter = "AccountEnabled eq true and UserType eq 'member'"}
"false" {$filter = "AccountEnabled eq false and UserType eq 'member'"}
"both" {$filter = "UserType eq 'member'"}
}
# Check if UserPrincipalName(s) are given
if ($UserPrincipalName) {
Write-host "Get users by name" -ForegroundColor Cyan
$users = @()
foreach ($user in $UserPrincipalName)
{
try {
$users += Get-MgUser -UserId $user -Property $properties | select $select -ErrorAction Stop
}
catch {
[PSCustomObject]@{
DisplayName = " - Not found"
UserPrincipalName = $User
isAdmin = $null
MFAEnabled = $null
}
}
}
}elseif($adminsOnly)
{
Write-host "Get admins only" -ForegroundColor Cyan
$users = @()
foreach ($admin in $admins) {
$users += Get-MgUser -UserId $admin.UserPrincipalName -Property $properties | select $select
}
}else
{
if ($IsLicensed) {
# Get only licensed users
$users = Get-MgUser -Filter $filter -Property $properties -all | Where-Object {($_.AssignedLicenses).count -gt 0} | select $select
}else{
$users = Get-MgUser -Filter $filter -Property $properties -all | select $select
}
}
return $users
}
}
Function Get-MFAMethods {
<#
.SYNOPSIS
Get the MFA status of the user
#>
param(
[Parameter(Mandatory = $true)] $userId
)
process{
# Get MFA details for each user
[array]$mfaData = Get-MgUserAuthenticationMethod -UserId $userId
# Create MFA details object
$mfaMethods = [PSCustomObject][Ordered]@{
status = "-"
authApp = "-"
phoneAuth = "-"
fido = "-"
helloForBusiness = "-"
helloForBusinessCount = 0
emailAuth = "-"
tempPass = "-"
passwordLess = "-"
softwareAuth = "-"
authDevice = ""
authPhoneNr = "-"
SSPREmail = "-"
}
ForEach ($method in $mfaData) {
Switch ($method.AdditionalProperties["@odata.type"]) {
"#microsoft.graph.microsoftAuthenticatorAuthenticationMethod" {
# Microsoft Authenticator App
$mfaMethods.authApp = $true
$mfaMethods.authDevice += $method.AdditionalProperties["displayName"]
$mfaMethods.status = "enabled"
}
"#microsoft.graph.phoneAuthenticationMethod" {
# Phone authentication
$mfaMethods.phoneAuth = $true
$mfaMethods.authPhoneNr = $method.AdditionalProperties["phoneType", "phoneNumber"] -join ' '
$mfaMethods.status = "enabled"
}
"#microsoft.graph.fido2AuthenticationMethod" {
# FIDO2 key
$mfaMethods.fido = $true
$fifoDetails = $method.AdditionalProperties["model"]
$mfaMethods.status = "enabled"
}
"#microsoft.graph.passwordAuthenticationMethod" {
# Password
# When only the password is set, then MFA is disabled.
if ($mfaMethods.status -ne "enabled") {$mfaMethods.status = "disabled"}
}
"#microsoft.graph.windowsHelloForBusinessAuthenticationMethod" {
# Windows Hello
$mfaMethods.helloForBusiness = $true
$helloForBusinessDetails = $method.AdditionalProperties["displayName"]
$mfaMethods.status = "enabled"
$mfaMethods.helloForBusinessCount++
}
"#microsoft.graph.emailAuthenticationMethod" {
# Email Authentication
$mfaMethods.emailAuth = $true
$mfaMethods.SSPREmail = $method.AdditionalProperties["emailAddress"]
$mfaMethods.status = "enabled"
}
"microsoft.graph.temporaryAccessPassAuthenticationMethod" {
# Temporary Access pass
$mfaMethods.tempPass = $true
$tempPassDetails = $method.AdditionalProperties["lifetimeInMinutes"]
$mfaMethods.status = "enabled"
}
"#microsoft.graph.passwordlessMicrosoftAuthenticatorAuthenticationMethod" {
# Passwordless
$mfaMethods.passwordLess = $true
$passwordLessDetails = $method.AdditionalProperties["displayName"]
$mfaMethods.status = "enabled"
}
"#microsoft.graph.softwareOathAuthenticationMethod" {
# ThirdPartyAuthenticator
$mfaMethods.softwareAuth = $true
$mfaMethods.status = "enabled"
}
}
}
Return $mfaMethods
}
}
Function Get-Manager {
<#
.SYNOPSIS
Get the manager users
#>
param(
[Parameter(Mandatory = $true)] $userId
)
process {
$manager = Get-MgUser -UserId $userId -ExpandProperty manager | Select @{Name = 'name'; Expression = {$_.Manager.AdditionalProperties.displayName}}
return $manager.name
}
}
Function Get-MFAStatusUsers {
<#
.SYNOPSIS
Get all AD users
#>
process {
Write-Host "Collecting users" -ForegroundColor Cyan
# Collect users
$users = Get-Users
Write-Host "Processing" $users.count "users" -ForegroundColor Cyan
# Collect and loop through all users
$users | ForEach {
$mfaMethods = Get-MFAMethods -userId $_.id
$manager = Get-Manager -userId $_.id
$uri = "https://graph.microsoft.com/beta/users/$($_.id)/authentication/signInPreferences"
$mfaPreferredMethod = Invoke-MgGraphRequest -uri $uri -Method GET
if ($null -eq ($mfaPreferredMethod.userPreferredMethodForSecondaryAuthentication)) {
# When an MFA is configured by the user, then there is alway a preferred method
# So if the preferred method is empty, then we can assume that MFA isn't configured
# by the user
$mfaMethods.status = "disabled"
}
if ($withOutMFAOnly) {
if ($mfaMethods.status -eq "disabled") {
[PSCustomObject]@{
"Name" = $_.DisplayName
Emailaddress = $_.mail
UserPrincipalName = $_.UserPrincipalName
isAdmin = if ($listAdmins -and ($admins.UserPrincipalName -match $_.UserPrincipalName)) {$true} else {"-"}
MFAEnabled = $false
"Phone number" = $mfaMethods.authPhoneNr
"Email for SSPR" = $mfaMethods.SSPREmail
}
}
}else{
[pscustomobject]@{
"Name" = $_.DisplayName
Emailaddress = $_.mail
UserPrincipalName = $_.UserPrincipalName
isAdmin = if ($listAdmins -and ($admins.UserPrincipalName -match $_.UserPrincipalName)) {$true} else {"-"}
"MFA Status" = $mfaMethods.status
"MFA Preferred method" = $mfaPreferredMethod.userPreferredMethodForSecondaryAuthentication
"Phone Authentication" = $mfaMethods.phoneAuth
"Authenticator App" = $mfaMethods.authApp
"Passwordless" = $mfaMethods.passwordLess
"Hello for Business" = $mfaMethods.helloForBusiness
"FIDO2 Security Key" = $mfaMethods.fido
"Temporary Access Pass" = $mfaMethods.tempPass
"Authenticator device" = $mfaMethods.authDevice
"Phone number" = $mfaMethods.authPhoneNr
"Email for SSPR" = $mfaMethods.SSPREmail
"Manager" = $manager
}
}
}
}
}
# Connect to Graph
ConnectTo-MgGraph
# Get Admins
# Get all users with admin role
$admins = $null
if (($listAdmins) -or ($adminsOnly)) {
$admins = Get-Admins
}
# Get MFA Status
Get-MFAStatusUsers | Sort-Object Name | Export-CSV -Path $path -NoTypeInformation
if ((Get-Item $path).Length -gt 0) {
Write-Host "Report finished and saved in $path" -ForegroundColor Green
# Open the CSV file
Invoke-Item $path
}else{
Write-Host "Failed to create report" -ForegroundColor Red
}Concluyendo
Tener MFA habilitado realmente ayuda a proteger a su inquilino. Este script de PowerShell le permite comprobar fácilmente el estado de MFA de sus usuarios.
Asegúrese de consultar también este artículo con otros 20 consejos de seguridad para Office 365. Puede encontrar la versión Msol de este script aquí y la nueva versión basada en Microsoft Entra aquí.
Si este script le resultó útil, compártalo. Si tiene alguna pregunta, simplemente deje un comentario a continuación.
Es posible que también le guste uno de los siguientes scripts de informes de PowerShell:
- Informe de permisos de buzón
- Informe de tamaño del buzón
- Informe de tamaño de OneDrive
