Azure B2C custom user attributes with PowerShell Core
azure b2c powershell
How to create an Azure AD B2C user with custom attribute using PowerShell Core.
September 29, 2021
This post is a beginning of my Azure AD B2C scripting journey...
- Azure B2C custom user attributes with PowerShell Core
- Automating Azure B2C creation with PowerShell Core
- Update Redirect URIs from Azure DevOps
- Automating Azure AD B2C creation with Terraform
There's also a GitHub repository with full scripts.
For a recent project I was writing a provisioning script for test users in Azure AD B2C. As straightforward as it may look, there are some difficulties when it comes to custom attributes (extension properties, custom claims - these all refer to the same thing in this context) and creating users that have them.
The B2C documentation mentions that it's possible to create and update users with extension attributes, but unfortunately doesn't specify how to do that. Let's figure it out in this post.
tl;dr
Use the Microsoft.Graph
PowerShell module with User.ReadWrite.All
and Application.Read.All
scopes.
- Get the
AppId
of the tenant-specificb2c-extensions-app
. - Construct the custom attribute name like this:
extension_$((Get-MgApplication | Where-Object { $_.DisplayName.StartsWith("b2c-extensions-app") }).AppId.Replace('-', ''))_attribute
.
- Create a hashtable with the attribute name and value.
- Create user with
New-MgUser
and add the attribute in-AdditionalProperties
.
Custom B2C attributes
Azure AD B2C supports custom attributes on user accounts and ASP.NET Core is then able to process them directly from authorization claims. The complication is that there's no UI in the B2C portal which would allow editing these attributes.
Let's imagine that we have a custom attribute called "GameMaster" which was created using the Azure portal.
There are two main ways to assign this attribute to a user:
- Using the
AzureAD
PowerShell module (Windows only, doesn't support Core).(Get-AzureADExtensionProperty | Where-Object { $_.Name.Contains("GameMaster") }).Name
$extension = [System.Collections.Generic.Dictionary[string, string]]::new()
$extension.Add($gameMasterExtensionProp, $userGameMaster)
New-AzureADUser ... -ExtensionProperty $extension
- Using Microsoft Graph.
- Directly through REST API.
- With .NET SDK, sample here: https://github.com/Azure-Samples/ms-identity-dotnetcore-b2c-account-management
- With
Microsoft.Graph
PowerShell module.
I used all of them, but to bypass the need of using the Windows-only AzureAD module in a scripted environment, I ended up with the Microsoft.Graph module method.
This post is about a PowerShell script which will create an user and assign them the GameMaster
attribute.
The b2c-extensions-app
application
Every Azure AD B2C tenant stores custom attributes in a dedicated application registration just for this tenant. Its name is kind of strange, but self-explanatory:
When assigning custom attributes to users, we can't simply use the attribute name (GameMaster
), but it's necessary to also include this b2c-extensions-app's ID like this:
extension_<extensionsAppID>_GameMaster
Thankfully, for the actual access token that our application will get from Azure AD this gets shortened to:
"extension_GameMaster": false
Creating a user with PowerShell Core
Equipped with the knowledge from previous sections, we can start creating users with PowerShell Core.
First, make sure that you have the Microsoft.Graph
module installed.
Get-InstalledModule Microsoft.Graph
And if not, install it:
Install-Module Microsoft.Graph
Authenticating to MS Graph can be done interactively, using the Connect-MgGraph
commandlet.
Yes, it's indeed MgGraph and not MsGraph, which caught me by suprise :)
Connect-MgGraph -TenantId $tenantId -Scopes "User.ReadWrite.All Application.Read.All"
Where $tenantId
can be either the GUID or tenant name (like mytenant.onmicrosoft.com
).
And then the tricky part is creating the accurate custom property name for this tenant. I'm using this contraption:
$gameMasterExtensionProp = "extension_$((Get-MgApplication | Where-Object { $_.DisplayName.StartsWith("b2c-extensions-app") }).AppId.Replace('-', ''))_GameMaster";
It's basically looking for an app with the well-known b2c-extensions-app
name and removing all -
from its ID.
Following is the creation of user's password and login identity (using just e-mail and registering as local account):
$passwordProfile = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphPasswordProfile
$passwordProfile.Password = $userPassword
$passwordProfile.ForceChangePasswordNextSignIn = $false
$identity = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphObjectIdentity
$identity.SignInType = "emailAddress"
$identity.Issuer = $tenantId
$identity.IssuerAssignedId = $userEmail
And our extension:
$extension = @{
$gameMasterExtensionProp = $userGameMaster # 'true' or 'false'
}
Finally, the New-MgUser
commandlet creates this user:
New-MgUser -DisplayName $user.displayName `
-AccountEnabled `
-Identities $identity `
-PasswordProfile $PasswordProfile `
-CreationType LocalAccount `
-AdditionalProperties $extension
To test that this worked, Microsoft Graph Explorer can be used.
Hint: To sign into a specific tenant, use:
https://developer.microsoft.com/en-us/graph/graph-explorer?tenant=<tenant>.onmicrosoft.com
.This is useful, because the B2C tenant is separate from its "parent" Azure tenant.
Sign in with your admin account and use the /users
endpoint to list all users. In order to display the custom attribute, you have to explicitly ask for it:
https://graph.microsoft.com/v1.0/users?$select=id,displayName,extension_<extensionAppId>_GameMaster
References
Feedback
Found something inaccurate or plain wrong? Was this content helpful to you? Let me know!
š§ codez@deedx.cz