I have published a major update to my Azure AD MFA Management script: https://github.com/blakebourgeois/Manage-MgUserAuthenticationMethods
A few years ago, I spent a weekend with a test Azure AD Tenant creating a way to streamline viewing and clearing a user’s MFA methods. It definitely helped my understanding of the whole process, and I was able to fork the tool for daily use. It’s performed thousands of MFA resets since and has grown over time to include new features like resetting tokens and viewing relevant sign in logs for troubleshooting.
One issue with the script was that it was written using the MSOnline and AzureADPreview cmdlets, which made the script Windows only. Things began moving more and more to Graph, but when I looked at our needs versus what was available in Graph, it didn’t make sense to spend a lot of time pursuing it.
One failing of the MSOnline/AzureADPreview cmdlets is that they could “blank” out a user’s available MFA enrollment (similar to hitting re-require MFA registration from the Azure AD Portal) but did not actually clear the phone number or remove app enrollments. Over time, this caused some small quality of life issues. Users potentially saw their number in the enrollment portal, but it wasn’t activated for MFA (and didn’t realize they needed to re-initialize it). Users with resets would have orphaned app entries in their authentication methods list. In cases where the user deleted the app or had a device with the same name, the portal would show two indistinguishable entries, making it difficult to clean up and wasting one of the user’s 5 slots for authenticator apps.
For a while, it only seemed possible to go do this in the Azure portal. It didn’t make a lot of sense to run the script for resets and still have to perform a bunch of manual steps in the portal.
Fortunately, new abilities in Graph make it possible to actually remove these apps in a programmatic way. After reading the docs and performing some manual tests, I realized it was probably time to spend another weekend looking to adapt the old script to use Graph. Luckily, the Microsoft.Graph Powershell module has some wrappers that make all the necessarily functions readily available and I didn’t have to do any kind of Invoke-WebRequest work to interact with Graph.
There are still a couple of challenges, and I’ll likely find a few things I want to change once I fork it and adapt it for daily use in production.
It is not currently possible to determine what a user’s default authentication method is. (If it’s necessary to know, you can likely infer it from the logs).
On the topic of logs–it was difficult to decide how to display them. With the AzureADPreview module, I was using Out-GridView (since it was Windows only anyway…) to view log results. This was working great for a while, then the log results changed formats and it was no longer possible to get detailed information from MFA attempts. Status results like “fraud code entered” or “phone call went to voicemail” were present in the log results, but after a shuffling of how results were organized in the Azure AD sign on logs, these results were nested under a different result and not retrievable via the AzureADPreview cmdlets–or at least I don’t recall they were or I was unable to figure out how to expose them.
This shift had implications when getting to view the logs with Graph. The good news is that I was able to get the detailed description again. But, the authentication details became nested under the sign on log entry, and it was possible for a single sign on attempt to have multiple MFA events. Because of this, it wasn’t possible to just use a calculated field to pull out the nested properties and display them in line with the rest of the log (this does work, however, and is used to get device details in the script’s log viewer).
Time will tell if my log implementation makes sense. Currently, you can view a detailed log which cycles through all the MFA-relevant log entries, displays some desired columns, and then outputs all of the MFA details under that result. It could be a long list of events, but it should give a reasonably filtered view of how MFA authentication is going for the selected user.
Outside of that, the other two log views each present a single half of this information. You can view all the MFA summary with messages for MFA attempts–successes and failures. However, no information other than a timestamp is available. No IP addresses, user agents, applications, etc. It’s good for troubleshooting MFA alone but provides an incomplete picture if apps or devices require additional scrutiny. It’s also not useful for correlating access attempts, for instance, if you’re researching a fraud alert submission. The sign on log summary contains brief information related to MFA successes and failures, but does include the IP, location, and device information for each event. Initially, I planned to offer just these two methods, forcing the analyst to do correlation alone by timestamp. Then I realized I could change the way I was looping through the log and access the entries in the nested properties.
Anyways, that’s enough rambling! For now, I chose to create a new repo for the “fork” of the original script–since there are still places and conditions where the old script probably makes sense. Looking at what all is available through Graph is very interesting, and very promising: https://docs.microsoft.com/en-us/graph/api/resources/azure-ad-overview?view=graph-rest-beta&preserve-view=true