Получить состояние MFA пользователей Office 365 с помощью Microsoft Graph
Отслеживание статуса MFA вашего пользователя важно для защиты вашего арендатора. На данный момент мы все еще можем использовать модуль Msol для этого в PowerShell, но Microsoft планирует отказаться от этого модуля. Поэтому я переработал свой успешный скрипт статуса MFA с использованием модуля Microsoft Graph.
Итак, этот новый скрипт статуса MFA может делать практически то же самое, что и старый скрипт:
- Перечислите настроенные типы MFA для всех пользователей
- Получите всех пользователей, у которых не включена MFA
- Проверьте конфигурацию MFA для отдельного пользователя
- Проверяет, является ли пользователь администратором или нет
- Получите только лицензированных и активированных пользователей
Но с помощью Graph мы также можем получить немного больше информации, чем с помощью старого модуля. Поэтому следующая информация теперь также извлекается:
- Название устройства аутентификатора
- Получите предпочтительный метод MFA пользователя
- Проверьте, зарегистрирован ли Hello for Business
- Зарегистрированный адрес электронной почты для сброса пароля службы самопомощи (SSPR)
Что мы в настоящее время не можем проверить, включен ли MFA на самом деле для пользователей или отключен, или если MFA является обязательным (то есть пользователь должен настроить MFA в следующий раз после входа в систему).
Как всегда, полный текст будет в конце статьи.
Получите статус MFA с помощью Microsoft Graph и PowerShell
Microsoft Graph постоянно обновляется, и с последними версиями нам больше не нужно использовать бета-эндпоинты. Это означает, что мы можем подключаться к Graph обычным способом с необходимыми правами доступа, чтобы получить все данные с помощью команды Get-MgUser.
После того как мы соберем всех пользователей, мы можем использовать командлет Get-MgUserAuthenticationMethod для получения всех деталей многофакторной аутентификации.
Заметка
С помощью Graph мы не можем проверить, включена или отключена многофакторная аутентификация (MFA) для пользователя. Мы можем только проверить, какие методы аутентификации настроены.
Microsoft отказывается от настройки MFA для каждого пользователя и нам необходимо перейти к политикам условного доступа для MFA. Таким образом, в настоящее время MFA может быть отключена для конкретного пользователя в центре администрирования, и мы не можем это определить с помощью Graph.
Тем не менее, если у вас есть Azure P1 или P2, посмотрите этот скрипт. Или вы все еще можете использовать старый модуль MSOL для этого, поэтому убедитесь, что вы также проверили этот скрипт, если вы все еще используете MFA для каждого пользователя.
Требования
Вам потребуется установить модуль Microsoft Graph. Скрипт проверит, установлен ли модуль, и если нет, вы получите возможность его установить.
Получение всех пользователей и их статуса MFA
Сценарий поставляется с несколькими параметрами, которые мы можем использовать для тонкой настройки результатов экспорта. Но по умолчанию он получит всех лицензированных пользователей, перечислит администраторов и сохранит экспорт CSV в том же месте, что и сценарий. Сценарий откроет файл CSV по завершении.
Чтобы получить всех пользователей, мы просто можем запустить скрипт:
Get all licensed users:
Get-MgMFAStatus.ps1Получите только пользователей без MFA
Когда у вас есть крупный арендатор, вы, вероятно, хотите видеть только пользователей, у которых не включена многофакторная аутентификация (MFA). Чтобы сделать это, вы можете использовать переключатель -withoutMFAOnly:
Get-MgMFAStatus.ps1 -withOutMFAOnlyПроверить статус MFA только для администратора
Скрипт по умолчанию будет перечислять всех администраторов, но вы также можете проверить статус MFA только для администраторов с помощью параметра -adminsOnly:
Get-MgMFAStatus.ps1 -adminsOnlyПроверьте статус конкретного пользователя или выборки пользователей
Также возможно проверить статус MFA для конкретного пользователя. Мы можем указать имя пользователя UserPrincipal, используя параметр -UserPrincipalName:
Get-MgMFAStatus -UserPrincipalName 'johndoe@contoso.com'
Параметр принимает массив строк, поэтому вы можете разделять пользователей запятыми, которых хотите получить:
Get-MgMFAStatus -UserPrincipalName 'johndoe@contoso.com','janedoe@contoso.com'Другой вариант - использовать фильтр команды Get-MgUser, а затем передать результат в скрипт Get-MgMFAStatus:
Get-MgUser -Filter "country eq 'Netherlands'" | ForEach-Object { Get-MgMFAStatus -UserPrincipalName $_.UserPrincipalName }Полный сценарий
Полный скрипт можно скачать из моего репозитория на Github, который я рекомендую использовать, чтобы у вас всегда была последняя версия.
Совет
Быстро получите статус MFA ваших пользователей, добавив ссылку на скрипт в свой профиль PowerShell. Узнайте об этом в статье.
<#
.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://a-d.site
.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
}Завершение
Включение MFA действительно помогает защитить ваш тенант. Этот скрипт PowerShell позволяет вам легко проверить статус MFA ваших пользователей.
Не забудьте также ознакомиться с этой статьей с 20 другими советами по безопасности для Office 365. Вы можете найти версию этого скрипта для Msol здесь, а новую версию на основе Microsoft Entra здесь.
Если вы нашли этот скрипт полезным, пожалуйста, поделитесь им. Если у вас есть какие-либо вопросы, просто оставьте комментарий ниже.
Вам также могут понравиться один из следующих скриптов отчетов PowerShell:
- Отчет о разрешениях почтового ящика
- Отчет о размере почтового ящика
- Отчет о размере OneDrive
