Table of Contents
Use Microsoft Graph PowerShell SDK Cmdlets to Report Accounts Not Yet Set Up for SSPR
A tweet by Nathan McNulty about the Get-MgReportAuthenticationMethodUserRegistrationDetail cmdlet attracted my attention. The cmdlet generates a report about the registered authentication methods for Azure AD accounts. Nathan used the cmdlet to identify accounts that aren’t set up for self-service password reset (SSPR) by filtering the results to find only member accounts where the IsSSPRCapable property is set to False. SSPR is a premium Azure AD feature.
Get-MgReportAuthenticationMethodUserRegistrationDetail outputs filtered results, but two problems exist before the data is really usable. First, the default output for the cmdlet is user identifiers (GUIDs) instead of human-friendly display names for each account. Second, while the filter can isolate member accounts, it can’t refine the query further to drop accounts created for shared mailboxes, resource mailboxes, and other purposes. The first issue is resolved by explicitly selecting the userPrincipalName and userDisplayName properties for output; the second takes more work.
Exploring a Solution
One potential solution is illustrated below. The script uses the Get-MgUser cmdlet to find all accounts with at least one assigned license (the set of returned accounts can include those used for shared mailboxes). Information about account identifiers and display names are loaded into a hash table to make it possible to lookup an identifier very quickly. We can then loop through the set returned by Get-MgReportAuthenticationMethodUserRegistrationDetail and check each account against the hash table. If a match occurs, we know that we have a licensed account that isn’t currently enabled for self-service password result and can report that fact.
Although the Get-MgReportAuthenticationMethodUserRegistrationDetail cmdlet can output user principal name and user display name properties, looking up the user account details against a table created by Get-MgUser allows us to drop the non-user accounts and lay the foundation for retrieving other data, as explained below. Here’s the code:
Connect-MgGraph -Scope Directory.Read.All, UserAuthenticationMethod.Read.All, AuditLog.Read.All Select-MgProfile Beta Write-Host "Finding licensed Azure AD accounts" [array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All # Populate a hash table with the details $UserTable = @{} $Users.ForEach( { $UserTable.Add([String]$_.Id, $_.DisplayName) } ) Write-Host "Finding user accounts not capable of Self-Service Password Reset (SSPR)" [array]$SSPRUsers = Get-MgReportAuthenticationMethodUserRegistrationDetail | Where-Object {$_.userType -eq 'member' -and $_.IsSSPRCapable -eq $False} | Select-Object Id, userDisplayName, userPrincipalName, DefaultMfaMethod, IsAdmin, IsMfaCapable, IsMfaRegistered, IsPasswordlessCapable, IsSSPRCapable Write-Host "Cross-checking against licensed users..." [array]$NonSSPR = $Null ForEach ($S in $SSPRUsers) { $DisplayName = $UserTable.Item($S.Id) If ($DisplayName) { $NonSSPR += $DisplayName } } $PNonSSPR = ($NonSSPR.count/$Users.Count).toString("P") Write-Host ("{0} out of {1} licensed accounts ({2}) are not enabled for Self-Service Password Reset" -f $NonSSPR.count, $Users.count, $PNonSSPR ) Write-Host ($NonSSPR -join ", ")
Only a list of account display names is output. When I ran the script in my tenant, the following output was generated:
Finding licensed Azure AD accounts Finding user accounts not capable of Self-Service Password Reset (SSPR) Cross-checking against licensed users... 23 out of 32 licensed accounts (71.88%) are not enabled for Self-Service Password Reset Andy Ruth (Director), Ben James, Ben Owens (DCPG), Bruno Satlier, Chris Bishop, , Jackson Hoare, James Abrahams, Jeff Guillet, John C. Adams, Ken Bowers, Lotte Vetler, Marc Vigneau, Michael King, Paul Howett, Peter Bridges, Rene Artois, Sean Landy, Terry Hegarty, Tony Redmond (Office 365 for IT Pros), Vasil Michev (Technical Guru)…
Improving the Output
We can improve the output by including more information in the lookup table. A hash table is fast, but it’s limited to a key and a value, but the value can any PowerShell object. The hash table can then hold more information about each user. For example:
$UserTable = @{} ForEach ($U in $Users) { $ReportLine = [PSCustomObject] @{ Id = $U.Id DisplayName = $U.DisplayName Department = $U.Department Office = $U.OfficeLocation Country = $U.Country } $UserTable.Add([String]$U.Id, $ReportLine) }
I’ve selected five properties for a user account. It’s easy to add more as necessary. With the hash table populated like this, we can grab the information from the PowerShell object in the value when a match occurs for an account and use it to build a nicer report.
ForEach ($S in $SSPRUsers) { $Data = $UserTable.Item($S.Id) If ($Data) { # We found a match $ReportLine = [PSCustomObject] @{ Id = $Data.Id DisplayName = $Data.DisplayName Department = $Data.Department Office = $Data.Office Country = $Data.Country } $NonSSPRUsers.Add($ReportLine) } }
Figure 1 shows the output of the report file.

Checking Accounts Regularly
This is exactly the kind of check against user accounts that tenants might want to run regularly. A scheduled runbook executed by Azure Automation is a good way to process these kinds of operations and the code discussed here would move over easily to a runbook. In the interim, here’s the link to the full script in GitHub for you to improve and enhance it as you like.
Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.
Missing a closing bracket on line 21
There are human-friendly properties returned by Get-MgReportAuthenticationMethodUserRegistrationDetail: userDisplayName and userPrincipalName
https://learn.microsoft.com/en-us/graph/api/resources/userregistrationdetails?view=graph-rest-beta#properties
It’s absolutely true that Get-MgReportAuthenticationMethodUserRegistrationDetail can return user principal name and user display name properties (if specified in the output). I’ve made this clearer in the text. My intention was to use the hash table of licensed accounts to return other information that might be useful to identifying accounts, like the department and office. Thanks for the comment – it’s always helpful to get feedback like this.
I received an error due to a missing scope permission against the MSGraph API:
Get-MgReportAuthenticationMethodUserRegistrationDetail_List: Calling principal does not have required MSGraph permissions AuditLog.Read.All
Fixed by adding the scope during the initial Connect to MSGraph, e.g.:
Connect-MgGraph -Scopes Directory.Read.All, UserAuthenticationMethod.Read.All, AuditLog.Read.All
Yep. I updated the GitHub script with a new scope. This was reported as an issue there.
Pretty cool script, however it is showing disabled azure users in the report.
You mean users with AccountEnabled = $False? If so, those accounts must still have licenses because that’s what is used to find accounts. To fix, apply a filter to remove any disabled accounts from the $Users array.