Knowing Which Accounts Are MFA-Enabled and Those That Don’t
When an issue like the November 19 2018 Azure outage occurs, the first thing that an administrator needs to know is what users are affected. In this case, the problem was that users whose accounts were enabled for multi-factor authentication (MFA) couldn’t complete the sign-in process and therefore weren’t able to access Exchange, SharePoint, and other Office 365 apps.
You can, of course go to the Microsoft 365 Admin Center and manage the MFA status of accounts there (Go to Active Users, click the More drop-down, and select Multifactor Authentication setup). However, the GUI is awful (Figure 1). It’s not part of Office 365 (it comes from Azure), hasn’t been updated in years, is slow, and is painful to navigate when you have a large tenant with many accounts.
Figure 1: Managing the MFA status of Office 365 Accounts – Just terrible!
Because the GUI is so terrible and slow, I usually turn to PowerShell to manage MFA for Office 365 accounts. The cmdlets you need are in the MSOnline module.
PowerShell Report
To start, let’s find out what accounts are MFA-enabled. Here’s a script to find and report the MFA status of all user accounts. The output is a CSV file. In a situation where an MFA outage is happening and you can’t access your normal administrative account, you’ll need to sign into Office 365 with a breakglass account.
Figure 2 shows the contents of the report as viewed through the Out-GridView cmdlet.
Figure 2: Reporting MFA status for accounts in an Office 365 tenant
Update: The script described in this post uses the Microsoft Services Online module (MSOL). Microsoft will deprecate the module at the end of 2022. You should upgrade scripts to use Graph API queries or cmdlets from the Microsoft Graph PowerShell SDK. See this post for information about how to extract and report details of authentication methods used by Azure AD accounts.
Azure Active Directory Sign-in Log
Because the refresh token of MFA-enabled accounts don’t necessarily expire during an outage, a more nuanced approach is to check the Azure Active Directory sign-in logs for events with error codes 50076, 50074, or 50058, all of which flag problems signing in with an MFA-enabled account. You can review sign-ins interactively or download events to a CSV file. You can then use Excel to look through the failed sign-ins or import the CSV file into Power BI to analyze it there. In either case, you’ll end up with a set of accounts who are experiencing problems signing into Office 365.
Disabling MFA for Accounts
When a cloud outage happens, there’s no guarantee when normal service will resume. As everyone discovered on November 18, the process to figure out the root cause of a problem, come up with a fix, test it, and then deploy into production across a massive multi-tenant infrastructure can take many hours. While this process was in going on, the only workaround administrators had was to disable MFA for user accounts. This is easily done for a specific user:
To disable a batch of users, simply form a collection and call the Set-MsolUser cmdlet for each account. In this case, we disable MFA for all members of the Marketing department. If you extract failed sign-in data from Azure Active Directory, you can create a CSV file holding the set of accounts to process and use it as the input.
Later on when the outage is over, we need to re-enable MFA for the same set of accounts (we’ll assume that you have saved details of the accounts and populated those names in the $Accounts variable). The PowerShell snippet shown below sets up MFA based on one-way SMS (text) messages containing 6-digit codes.
These examples aren’t a complete solution. Instead, they’re intended to give administrators a start to figure out how to manage MFA settings with PowerShell.
I haven’t tried. The script depends on the information written into the Azure AD accounts, so I imagine that it would – but it’s good to check and easy to test.
In my organization, I have delegated the “Authentication Administrator” role to our helpdesk, and I created some PowerShell scripts to enable/disable MFA, and to reset MFA contact methods. The helpdesk uses these tools effectively. We have another issue which I haven’t been able to resolve. Occasionally, someone in our organization gets their MFA blocked. Right now, a Global Administrator must use the GUI to review and unblock these users. It would be nice to delegate this. I can’t find an Azure cmdlet to report on or block/unblock users, and I don’t know if we can even delegate permissions to do so. Any idea if this is possible?
{"id":null,"mode":"button","open_style":"in_modal","currency_code":"EUR","currency_symbol":"\u20ac","currency_type":"decimal","blank_flag_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":100,"top_media_type":"featured_image","featured_image_url":"https:\/\/office365itpros.com\/wp-content\/uploads\/2022\/11\/cover-141x200.jpg","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":true,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Virtual Tip Jar","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"Office 365 for IT Pros","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"Office 365 for IT Pros","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for supporting the work of Office 365 for IT Pros!","payment_confirmation_title":"Office 365 for IT Pros","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":null,"terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}
is there a way to get the MFA status for a particular domain using Powershell?
We have multiple domains, and I would like to know in what domain the MFA is enabled.
Just add the following condition to this statement to narrow down the search down to your domain.
-and $_.userprincipalname -match “@yourdomain.com”
$Accounts = (Get-MsolUser -All | ? {$_.StrongAuthenticationMethods -ne $Null -and $_.userprincipalname -match “@yourdomain.com”} | Sort DisplayName)
Hi, I tried the main report script but it only cam eback with my own account (should have over 80K users). Any ideas?
Are you signed into PowerShell with an account that has administrative permissions for the tenant?
Great script many thanks!
The best script I found so far, for exporting MFA information. Thank you!
Hi, is this script going to work if MFA conditional access is enabled?
I haven’t tried. The script depends on the information written into the Azure AD accounts, so I imagine that it would – but it’s good to check and easy to test.
I might try and report back. What privileges do you need to run this script successfully?
Tenant administrator or user account administrator, I believe.
In my organization, I have delegated the “Authentication Administrator” role to our helpdesk, and I created some PowerShell scripts to enable/disable MFA, and to reset MFA contact methods. The helpdesk uses these tools effectively. We have another issue which I haven’t been able to resolve. Occasionally, someone in our organization gets their MFA blocked. Right now, a Global Administrator must use the GUI to review and unblock these users. It would be nice to delegate this. I can’t find an Azure cmdlet to report on or block/unblock users, and I don’t know if we can even delegate permissions to do so. Any idea if this is possible?