I have a client with a parent company in Asia and a subsidiary in the USA and Europe. To provide cross-tenant access to the Intranet and other resources we have used Entra ID Cross-Tenant Sync to populate users from the Asian tenant into the USA based tenant. The issue with this is that the Asian tenant does not use the western script and so display names on the synced users are unreadable to those in the subsidiary.
So we use the expression builder which is part of cross-tenant sync to rewrite the displayname of the synced users in the USA tenant based on their mailNickname attribute in the parent tenant. We could have used other attributes, such as ExtensionAttributeXX (the Exchange Online custom attributes) as well to achieve this, but in our case the email nickname, also known in Exchange as the “alias” was in an ASCII format.
To get all this going we create a standard cross-tenant sync either in Entra ID (if you want some advanced settings such as one-way sync) or via the Microsoft 365 Admin Portal, if you want the default settings of two-way sync. Once the sync is in place, from the Entra ID portal visit the “Cross-Tenant Synchronization” settings > Configuration > Provisioning > Mappings > “Provision Microsoft Entra ID Users”.
![](https://c7solutions.com/wp-content/uploads/2024/07/image-1024x376.png)
Our requirements are to change the displayName in the target tenant to match an adjusted version of the mailNickname (for example a nickname of “asa.tanaka” to become “Asa Tanaka (C7 Solutions)”, capitalised and split and ending with the company name). So for this we locate displayName in the Attribute Mappings list, which shows that displayName in the source tenant will match displayName in the target tenant, so in my example “田中あさ” will be the displayName on both sides. Click Edit on the displayName row to change this. We will end up with the following:
![](https://c7solutions.com/wp-content/uploads/2024/07/image-1-1024x999.png)
We are allowed a single expression, an attribute value or a fixed string in the sync engine. So complex manipulations of text require embedded expressions (known as functions).
Microsoft’s list of functions
https://learn.microsoft.com/en-us/entra/identity/hybrid/cloud-sync/reference-expressions
So for example if we want to join the users displayName to a fixed company name, we could use “Append” which will add a value to the end of the current value. But if we want to join a number of values together we need to use “Join” instead and they include any delimiter in the join, for example a space ” ” or nothing “”. In the above screenshot we also use “Split” to break the mailNickname on the “.” to create an array for each part. So this is what we end up with, which we decipher from the middle!
Append(Join(" ", Join("", ToUpper(Left(Item(Split([mailNickname], "."), 1), 1), ), ToLower(Mid(Item(Split([mailNickname], "."), 1), 2, 999), )), Join("", ToUpper(Left(Item(Split([mailNickname], "."), 2), 1), ), ToLower(Mid(Item(Split([mailNickname], "."), 2), 2, 999), ))), " (C7 Solutions)")
This is entered into the cross-tenant sync as a single string, but might be easier to read parsed like this:
Append(
Join(" ",
Join("",
ToUpper(
Left(
Item(
Split([mailNickname], "."),
1),
1),
),
ToLower(
Mid(
Item(
Split([mailNickname], "."),
1),
2, 999),
)
),
Join("",
ToUpper(
Left(
Item(
Split([mailNickname], "."),
2),
1),
),
ToLower(
Mid(
Item(
Split([mailNickname], "."),
2),
2,
999),
)
)
),
" (C7 Solutions)"
)
The Split() function takes the mailNickName and splits it into two on the dot, resulting in a array of multiple items – two in this case. So our example of “asa.tanaka” becomes “asa” and “tanaka”. We can work with these individual items using Item(Split([mailNickName],”.”),1) or 2.
The rest of the function then takes the first letter – Left() and makes it upper case – ToUpper() and joins it back again to the rest of the name – Mid(…,2,999) where 999 is just long enough so that all the rest of the word is returned without having to calculate the actual length of the word. So Join(“”,ToUpper(Left(Item(…,1),1),2,999)) now returns “Asa” and for Item 2, that returns “Tanaka”.
We then in this example Append(…,” (C7 Solutions)”), which is a fixed string containing a space and the company name, but adding things like a company name and country code are possible with ,” (Contoso “),ToUpper([country]),
The expression builder has a test expression form, and that looks like this for an existing user:
![](https://c7solutions.com/wp-content/uploads/2024/07/image-2-1024x637.png)
Or, where you can test without having to create a working user first:
![](https://c7solutions.com/wp-content/uploads/2024/07/image-3-1024x659.png)
For the full expression, set the displayName as the value to use if the expression generates “null”, so that the target user always has a displayName – this can be seen in the second screenshot at the top of this post.
Save your changes, and ensure that your users in scope have the correct attributes populated, in this case mailNickname, and then wait 40+ minutes for the sync to restart and update your existing users.
Here is how the user “田中あさ” looked in the NBConsult tenant:
![](https://c7solutions.com/wp-content/uploads/2024/07/image-4-1024x391.png)
Addendum: After I had written all of the above, I was made aware of the PCase function. This automatically splits strings on a given character and capitalizes the first letter of each. PCase though is NOT listed on the Microsoft Learn page about expressions for cross-tenant sync, but is listed on the Microsoft Learn page about expressions for SaaS provisioning. SaaS provisioning uses the same underlying sync engine!
So the above expression, though it works, is more cleanly done as:
Append(PCase(Replace([mailNickname],".",,," ",,),)," (C7Solutions)")
And apologies for any unintentionally confusing or incorrect uses of Japanese in my example usernames.
Photo by Nien Tran Dinh: https://www.pexels.com/photo/photo-of-himeji-castle-behind-white-cherry-blossoms-1654748/
Leave a Reply