I'm having real trouble finding any code examples in how to add a Schema Extension value against a User in Azure AD.
So far I have successfully created my own schema extension, marked as 'User' TargetType, and updated the status as 'Available'. This was all achieved through the MS Graph SDK
Below is a screenshot showing the extension I created and listed within my app:
This extension is very basic, just a single property exists called 'name' that is set to a type string.
I now want to perform the following functions:
The only examples given by MS Docs is using the MS Graph API, NOT the SDK which I am using in my app. In addition their only example given is adding a schema extension when creating a new Group.
https://learn.microsoft.com/en-us/graph/extensibility-schema-groups
In their notes, MS say the following: Note: This topic shows you how to create and read schema extension values on a group resource (steps 3-5). The same methods are supported for the administrativeUnit, device, event, message, organization, post, and user resource types as well. You can carry out operations similar to the request examples in this article on any of those resources.
Can someone please advise where I get code example that allows me to create/update users with this extension, as well as using a filtered search for all users in my tenant that have a certain value set in their profile for this particular extension?
UPDATE: In conjunction with the dicussion with Allen Wu in answers below, I have implemented his code example in adding the schema extension as "AdditionalData" when creating a new user. I havent managed to get this working yet as I receive a error saying "Code: BadRequest\r\nMessage: Unsupported Schema Extension Property value of type String\r\nInner error:\r\n\tAdditionalData:\r\n\tdate: 2021-03-31T18:51:32\r\n\trequest-id"
Code example for creating a new user with the schema extension:
var user = new User();
user.UserPrincipalName = TenantUser.UserPrincipalName + "@" + Domain; // * Required
//user.UserPrincipalName = TenantUser.UserPrincipalName; // * Required
user.DisplayName = TenantUser.GivenName + " " + TenantUser.Surname; // * Required
user.GivenName = TenantUser.GivenName; // * Required
user.Surname = TenantUser.Surname; // * Required
if (TenantUser.Password != null)
{
if (TenantUser.Password != TenantUser.ConfirmPassword)
{
ModelState.AddModelError(string.Empty, "\n Passwords do not match!");
return Page();
}
else
{
user.PasswordProfile = new PasswordProfile
{
Password = TenantUser.ConfirmPassword,
};
}
}
user.AccountEnabled = AccountEnabled;
user.JobTitle = TenantUser.JobTitle;
user.Department = TenantUser.Department;
user.EmployeeId = TenantUser.EmployeeId;
user.OfficeLocation = TenantUser.OfficeLocation;
user.CompanyName = TenantUser.CompanyName;
user.StreetAddress = TenantUser.StreetAddress;
user.State = TenantUser.State;
user.City = TenantUser.City;
user.PostalCode = TenantUser.PostalCode;
user.Country = TenantUser.Country;
user.MobilePhone = TenantUser.MobilePhone; // * Required
if (BusinessPhone != null)
{
user.BusinessPhones = new List<String>()
{
BusinessPhone // see public string
};
}
user.Mail = TenantUser.Mail; // * Required
user.MailNickname = TenantUser.MailNickname;
user.AdditionalData = new Dictionary<string, object>()
{
{"ext7bxc3e0l_appRoleTemplate", "{\"name\":\"Template1\"}"}
};
try
{
await graphClient.Users
.Request()
.AddAsync(user);
LogData = "New User with name [" + UserFullName + "] created by user with forename [" + currentUser.Forename + "] surname [" + currentUser.Surname + "] Succesfully";
// See helper method at bottom.
logExtension.WriteLogEvent<EditModel>("Information", "Users", "Created", UserFullName, currentUser.Id, currentUser.Username, currentUser.Forename, currentUser.Surname, LogData, null, _scopeFactory);
}
catch (ServiceException ex)
{
// Graph service exception friendly message
var errorMessage = ex.Error.Message;
LogData = " Error creating the User. Microsoft Graph API encountered a Service Exception with message [" + errorMessage + "]'";
logExtension.WriteLogEvent<EditModel>("Error", "User", "Created", $"User with Id = {currentUser.Id}", currentUser.Id, currentUser.Username, currentUser.Forename, currentUser.Surname, LogData, null, _scopeFactory);
ModelState.AddModelError(string.Empty, errorMessage + " Error creating the User.\n Please check the system logs for details");
return Page();
}
I create a schema extension:
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#schemaExtensions/$entity",
"id": "ext253rtfdu_name",
"description": "user name extensions",
"targetTypes": [
"User"
],
"status": "InDevelopment",
"properties": [
{
"name": "userId",
"type": "String"
},
{
"name": "userName",
"type": "String"
},
{
"name": "userType",
"type": "String"
}
]
}
Create a user whit a ext253rtfdu_name
schema extension:
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
string extStr = "{\"userId\":\"321\",\"userName\":\"Adele test02\",\"userType\":\"member\"}";
JObject jsonObj = JObject.Parse(extStr);
var user = new User
{
AccountEnabled = true,
DisplayName = "Adele test01",
MailNickname = "AdeleVtest01",
UserPrincipalName = "AdeleVtest01@contoso.onmicrosoft.com",
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "password-value"
},
AdditionalData = new Dictionary<string, object>()
{
{"ext253rtfdu_name", extStr}
}
};
await graphClient.Users
.Request()
.AddAsync(user);
Update the user:
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
string extStr = "{\"userId\":\"456\",\"userName\":\"Adele test02\",\"userType\":\"member\"}";
JObject jsonObj = JObject.Parse(extStr);
var user = new User
{
AdditionalData = new Dictionary<string, object>()
{
{"ext253rtfdu_name", jsonObj}
}
};
await graphClient.Users["AdeleVtest01@contoso.onmicrosoft.com"]
.Request()
.UpdateAsync(user);
I tried to use https://graph.microsoft.com/v1.0/users?$filter=ext253rtfdu_name/userId eq ‘456’&$select=displayName,id,userPrincipalName,ext253rtfdu_name
to filter with the extension to get the user but it shows Invalid filter clause
. But according to Filtering on schema extension properties known issues, it should be supported.
I don't understand what happen to this filter but the code sample should be:
var res = await _graphClient.Users.Request()
.Filter($"ext253rtfdu_name/userId eq '456'").GetAsync()
A similar post here for your reference.
You can have a try from your side.