Obtenga el estado de MFA de los usuarios de Office 365 con Microsoft Graph

Hacer un seguimiento del estado de MFA de su usuario es importante para mantener protegido a su arrendatario.

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 secuencia de comandos MFA Status exitosa con el módulo Microsoft Graph.

El módulo de Microsoft Graph aún no está completo. No solo carece de documentación, sino que aún no podemos recuperar toda la información.

Por ejemplo, no podemos recuperar (o configurar) el método MFA predeterminado con Graph en este momento.

Entonces, este nuevo script de estado de MFA puede hacer prácticamente las mismas cosas que el script anterior:

  • Listar el estado de MFA de todos los usuarios
  • Lista de tipos de MFA configurados para cada usuario
  • Obtener todos los usuarios que no tienen MFA habilitado
  • Verifique el estado de 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. Así que ahora también se recupera la siguiente información:

  • Nombre del dispositivo del autenticador
  • Comprobar si Hello para empresas está registrado
  • Dirección de correo electrónico registrada para el restablecimiento de contraseña de autoservicio (SSPR)

Lo que actualmente no podemos recuperar es el método MFA predeterminado y si MFA se aplica a los usuarios (como si el usuario necesita configurar MFA la próxima vez después de iniciar sesión).

Como siempre, encontrará el guión completo al final del artículo.

Obtenga el estado de MFA con Microsoft Graph y PowerShell

Microsoft Graph todavía tiene muchas características que solo están disponibles en su versión beta.

Entonces, lo primero que hace el script es conectarse a Graph con los alcances requeridos y cambiar al perfil beta.

Luego podemos recuperar todos los usuarios con el cmdlet Get-MgUser.

gráfico de microsoft de estado de mfa
Obtenga el estado de MFA con Microsoft Graph

Una vez que hayamos recopilado a todos los usuarios, podemos usar el cmdlet Get-MgUserAuthenticationMethod para obtener todos los detalles de MFA.

Requisitos

Deberá tener instalado el módulo Microsoft Graph. El script verificará si el módulo está instalado, si no, se le dará la opción de instalarlo.

Obtener todos los usuarios y su estado de 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 se complete.

Entonces, para obtener todos los usuarios, simplemente podemos ejecutar el script:

# Get all licensed users:
Get-MgMFAStatus.ps1

Obtener solo usuarios sin MFA

Cuando tiene un inquilino grande, probablemente solo quiera ver a los usuarios que no tienen MFA habilitado. Para hacer esto, puede agregar usar el interruptor -withoutMFAOnly:

Get-MgMFAStatus.ps1 -withOutMFAOnly

Comprobar solo el estado de administrador de MFA

El script mostrará una lista de todos los administradores de forma predeterminada, pero también puede verificar el estado de MFA de los administradores solo con el -adminsOnly cambiar:

Get-MgMFAStatus.ps1 -adminsOnly

Consultar el estado de un usuario específico o una selección de usuarios

También es posible verificar el estado de MFA de un usuario específico. Podemos especificar el nombre UserPrincipal del usuario usando el parámetro -UserPrincipalName:

Get-MgMFAStatus -UserPrincipalName '[email protected]'

El parámetro acepta una matriz de cadenas, por lo que puede separar con comas los usuarios que desea recuperar:

Get-MgMFAStatus -UserPrincipalName '[email protected]','[email protected]'

Otra opción es usar 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 guión completo se puede descargar desde mi 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.

[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"

  # Select the beta profile
  Select-MgProfile Beta
}

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 | Where-Object {($_.AssignedLicenses).count -gt 0}}
                } | 
                Select @{Name="Role"; Expression = {$role}}, DisplayName, UserPrincipalName, Mail, ObjectId | 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  = "-"
      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"
          } 
          "#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-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

      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 Default type" = ""  - Not yet supported by MgGraph
          "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
        }
      }
    }
  }
}

# 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
}

Terminando

Tener MFA habilitado realmente ayuda a proteger a su inquilino. Este script de PowerShell le permite verificar 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í.

Si encuentra útil este script, compártalo. Si tiene alguna pregunta, simplemente deje un comentario a continuación.

También le puede gustar uno de los siguientes scripts de informes de PowerShell:

Otros artículos relacionados

ADUser - Cómo encontrar y exportar usuarios de AD con PowerShell

ADUser – Cómo encontrar y exportar usuarios de AD con PowerShell

Active Directory es nuestra fuente principal cuando se trata de administrar cuentas de usuario. La consola de administración es excelente ...
Leer Más
Cómo agregar o configurar MailboxFolderPermission con PowerShell

Cómo agregar o configurar MailboxFolderPermission con PowerShell

En Exchange Online podemos compartir buzones completos con otros usuarios. Pero, ¿qué sucede si desea compartir solo una carpeta? ¿O ...
Leer Más
Los 10 principales comandos de PowerShell que debe conocer

Los 10 principales comandos de PowerShell que debe conocer

PowerShell es realmente poderoso y puede hacer que su trabajo diario sea mucho más fácil. Con todos los módulos que ...
Leer Más
Cómo usar Test-NetConnection en PowerShell

Cómo usar Test-NetConnection en PowerShell

¿Sabías que el comando ping, con sus 38 años, es más antiguo que el símbolo del sistema? Probablemente ya haya ...
Leer Más
Encuentra direcciones de correo electrónico en Office 365 con PowerShell

Encuentra direcciones de correo electrónico en Office 365 con PowerShell

A veces necesita encontrar el usuario o un buzón que está usando una dirección de correo electrónico en particular. En ...
Leer Más
Cómo crear un perfil de PowerShell

Cómo crear un perfil de PowerShell

¿Quiere sacar más partido a su PowerShell? Luego, asegúrese de configurar su perfil de PowerShell para mejorar su consola de ...
Leer Más

Deja un comentario