Thoughts, Dynamics 365, random business ideas, etc.

How to find users in Azure B2C by email address

I’m using Azure AD B2C to keep track of a bunch of external users and I have some custom extension properties that are being tracked in addition to the standard fields available in Entra. I’m using a custom policy and then allowing uses to create their own records in my Azure B2C tenant.

For some reason (and if someone knows why, I’d love to hear about it in the comments), but my Azure AD B2C tenant uses {the user’s object ID} + {@} + {my tenant} as the user’s userPrincipalName. I wanted to do a mass clean-up of these records via a PowerShell script, but I only had the user’s email addresses that they used to initially create their account. I was having a tough time trying to find the user record with the email address, but Claude and ChatGPT came to the rescue.

Where I started

I had found a PowerShell script using the Get-AzureADUser cmdlet that would loop through the records in a CSV, pull the relevant data, find the user, and then update the record. IThe AzureAD module is going to be deprecated, so I switched to using the Microsoft Graph PowerShell module instead. I had never used that before, so I took my script, copied and pasted it into ChatGPT and said “I want to do this, but I want to use the graph PowerShell module instead.”

Thankfully, that worked, but I also needed to account for these extension properties. I asked ChatGPT to figure that out for me, as well, and it did. The biggest problem arose when I realized that most of my user accounts didn’t have their primary email address as the userPrincipalName – they had some sort of GUID.

Searching for the user record

This part took a minute. I didn’t really understand what the object even looked like or which fields I should be trying to query on, so I needed to troubleshoot.

The first thing I did was I noticed that the email address I wanted to search on was shown in the Azure portal under “identities.” Not 100% sure what field that was or how the data looked, I opened developer tools in Chrome, opened up an object in Azure, and saw that one of the API calls returned an identities object. It looked like this:

"identities": 
[
  {
    "signInType": "emailAddress",
    "issuer": "JACRODexternalnusers.onmicrosoft.com",
    "issuerAssignedId": "jake@jacrod.com"
  },
  {
    "signInType": "userPrincipalName",
    "issuer": "JACRODexternalusers.onmicrosoft.com",
    "issuerAssignedId": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX@JACRODexternalusers.onmicrosoft.com"
  }
]

I mean, it was my first attempt at something. It at least gave me information that the email address I wanted to find was stored on the object somewhere, and it looked like it was stored in the identities object.

Next step was using the Microsoft Graph Explorer. I have a bit of a tricky situation here, and I was struggling with the Graph Explorer at first – it was only connecting to my default Entra tenant and not my B2C tenant. Thankfully, a post on StackOverflow told me you just need to append the ?tenant= query string to the end of the URL and it’ll connect to whatever tenant you’d like.

Finally able to connect to the correct tenant, I was able to use the graph explorer to both query the user object and also test out some of the stuff from ChatGPT.

ChatGPT troubleshooting

I then tried something on my own and got an error message, so I sent that back to ChatGPT. Interestingly enough, this time I got some troubleshooting suggestions in addition to just a suggested action.

The error message you’re encountering indicates that the request you made to filter users in the Microsoft Graph API contains unsupported properties, values, or combinations of properties and operations. This is common when working with B2C tenants, which might have different supported properties and query capabilities compared to regular Azure AD tenants.

Here are some steps to troubleshoot and resolve the issue:

  1. Review the Filter Syntax: Ensure that the filter query is using properties that are supported for filtering in a B2C tenant. Some properties might not be filterable or might have restrictions on the operations that can be used.
  2. Check Supported Properties: Verify which properties are supported for filtering in the B2C tenant. You can refer to the Microsoft Graph API documentation to see the list of supported properties for filtering users.
  3. Simplify the Query: Try simplifying the query to isolate the issue. Start with a basic filter and gradually add more conditions to see which part of the query is causing the error.
  4. Use the Correct API Version: Ensure you are using the correct version of the Microsoft Graph API. Some features or properties might be available only in specific versions.

Here is an example of a basic filter query to get users:

It then gave me a broken-down approach to troubleshooting – had me start with a basic query, try another basic query, and then added them together to see where it broke.

Where I ended up is this:

Get-MgUser -Filter "identities/any(id:id/issuer eq '$tenant' and id/issuerAssignedId eq '$email')"

Obviously, there’s a part of the script ahead of this that loops through each record of my CSV file and saves the email address in the $email variable, but this seemed to work pretty well.

Extension properties

The other thing I kept having problems with were the extension properties. I wanted to track extra data about my users on the user record above and beyond the standard fields, so I created custom extension properties in my custom policy.

In order to update them, I needed to create a customproperties object and then pass that into the Update-MgUser cmdlet to update the custom fields.

$extensionProperties = 
@{
  "extension_XXXXXXXXXX_HairColor" = $user.'Hair Color'
  "extension_XXXXXXXXXX_ShoeSize" = $user.'Shoe Size'
  "extension_XXXXXXXXXX_TShirtSize" = $user.'T-Shirt Size'
 }

After building that object, I passed it into the Update-MgUser cmdlet.

Update-MgUser -UserId $userPrincipalName 
-AdditionalProperties $extensionProperties 
-GivenName $user.'First Name' -Surname $user.'Last Name' -JobTitle $user.'Job Title'

If you have standard properties you want to update, you can just pass them in directly in combination with the extension properties.

Debugging

It’s hard to see these extension properties – in fact, they’re not even visible in the Azure portal. Claude helped me add a separate section at the end that wrote the updated values to the console.

        $updatedUser = Get-MgUser -UserId $userPrincipalName -Select @(Id", "DisplayName", "UserPrincipalName", "GivenName", "Surname", "JobTitle", "extension_XXXXXXXXXX_HairColor", "extension_XXXXXXXXXX_ShoeSize", "extension_XXXXXXXXXX_TShirtSize")

        # Write the updated properties to the console
        Write-Output "Updated user: $($updatedUser.UserPrincipalName)"
        Write-Output "Properties:"
        Write-Output "  Given Name: $($updatedUser.GivenName)"
        Write-Output "  Surname: $($updatedUser.Surname)"
        Write-Output "  Job Title: $($updatedUser.JobTitle)"
        Write-Output "  Hair Color: $($updatedUser.AdditionalProperties['extension_XXXXXXXXXX_HairColor'])"
        Write-Output "  Shoe Size: $($updatedUser.AdditionalProperties['extension_XXXXXXXXXX_ShoeSize'])"
        Write-Output "  T-Shirt Size: $($updatedUser.AdditionalProperties['extension_XXXXXXXXXX_TShirtSize'])"
        Write-Output "---------------------------------"

Obviously, for a bulk export, you wouldn’t want to do this – it’s more for debugging and testing.

Hope this helps.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Exit mobile version