Potentially More Flexibility and Control Available in Azure AD

On December 1, Microsoft announced the preview of Azure AD Custom Security Attributes. In a nutshell, tenants with Azure AD Premium P1 or P2 licenses can use custom security attributes to store business-specific information for user accounts, security principals, and managed identities. The requirement for premium licenses reflects the targeting of large enterprises for this capability. In their FY22 Q1 results, Microsoft said that the Enterprise Mobility and Security suite, which includes Azure AD premium, has196 million users, or roughly 60% of the Office 365 user base. With those numbers in mind, the requirement for premium licenses should not be an impediment to the adoption of Azure AD custom security attributes.

Microsoft’s announcement positions Azure AD custom security attributes as part of their roll-out of Attribute Based Access Control to give organizations the ability to control access to resources like Azure storage at a fine-grained level. Worthy as that effort is, I think many organizations will find practical use for Azure AD custom security attributes to replace Exchange custom mailbox attributes to store important or sensitive corporate information about users. This is one of the scenarios called out by Microsoft in their announcement and it’s the one I explore here.

Allowing Organizations to Define Their Own Attributes

The problem with standard software is that it’s standard. Being able to customize how software works means that different customers can make software more useful in terms of their operations.

Although an organization can store what they want in Exchange custom attributes, they can’t change the names of the attributes or their number. Things are very different with Azure AD. Custom security attributes are defined in attribute sets, managed collections of key-value pairs. Azure roles allow organizations to control who can define attribute sets and individual attributes and who can view the data stored in the attributes. Each Azure AD tenant can create up to 500 custom security attributes. You can scope an attribute set so that it is managed tenant-wide or managed by specific users. For instance, an Azure AD administrator located in Germany might control attributes specific to accounts belonging to that country.

Overall, the key differences between Exchange custom attributes and Azure AD custom security attributes are:

  • Organizations can decide how many custom security attributes they want and how to organize those attributes in attribute sets. They can assign their own names to the attributes.
  • Azure AD custom security attributes can be strings, integers, or Booleans, and accept single or multiple values. Fifteen of the Exchange custom attributes are single value (all treated as strings) while five are multi-value and can hold up to 1,300 values each.
  • Azure AD custom security attributes can be prepopulated and limited to a set of acceptable values.
  • Management of and access to attribute sets can be scoped to different users. By comparison, any global or Exchange administrator can manage and access the data held in mailbox attributes.
  • Exchange Online custom attributes are available for all mail-enabled objects, including Microsoft 365 group mailboxes. Azure AD custom attributes are available for user accounts (member and guests).
  • Adaptive scopes for user retention policies is an example of how Microsoft exploits values written into Exchange custom attributes. For Azure AD custom attributes, Microsoft’s focus is likely to be on security, with the first use being as conditions in conditional access policies (due soon).

Like the Exchange custom attributes, Azure AD custom security attributes are accessible programmatically using PowerShell and the Microsoft Graph (through the beta endpoint for the Users API). The PowerShell cmdlets and parameters show their Graph heritage and are not as easy to work with as the Exchange custom attributes are, but once you get used to what’s required, it’s reasonably plain sailing to set attributes. As explained later, retrieving values from Azure AD custom security attributes using PowerShell is a tad more complicated, but not if you use the Graph API.

Creating New Custom Security Attributes

The documentation for creating a new attribute set and populating it with attributes is clear and doesn’t need repeating. The big thing is to make sure that the account you sign into the Azure AD admin center holds the Attribute Definition Administrator role. Even if your account is a global administrator, it won’t have the role unless you go ahead and assign it. After assigning the role, wait a few minutes for the change to percolate through Azure AD and refresh the browser to pick up the change.

Before creating anything, it’s a good idea to write down the names and characteristics of the custom security attributes you plan to use. The basic structure of each attribute is:

  • Name (up to 32 characters but can’t contain spaces or special characters).
  • Description (up to 128 characters of your best prose).
  • Data type (string, integer, or Boolean). Given the widespread storage of dates (hire date, last promotion, last review) in personal data, it’s curious that Microsoft did not include a date type.
  • Allow multiple values to be assigned (yes/no).
  • Only allow predefined values to be assigned (yes/no). If you choose yes, you must edit the attribute after creation to add the predefined values.

Apart from predefined values, you can’t add validation or formatting instructions for data held in custom security attributes. For instance, you can’t say that an integer attribute must be within 1 and 1000. However, the lack of formatting and validation for Exchange custom attributes has not restricted their usefulness over the last fifteen years because, in most cases, code is written to validate and format data before updating an attribute.

When you create a new attribute set, you’re asked how many attributes will be in it. The default is 25, but you don’t have to create this many. It is a maximum, not a target to aim for.

I created a new attribute set called Employees to hold the kind of information often used by HR and then started on the attributes. Figure 1 shows the creation of an attribute called TaxIdentifier, intended to store information like U.S. social security numbers.

Creating a new Azure AD custom security attribute
Figure 1: Creating a new Azure AD custom security attribute

Figure 2 shows a custom security attribute called LegalEntity being edited to add predefined values. In addition, the settings for the attribute allow only values from the predefined set.

Adding predefined values for an Azure AD custom security attribute
Figure 2: Adding predefined values for an Azure AD custom security attribute

Note that you cannot delete an attribute. If you make a mistake, you can deactivate an attribute to remove it from the current set, but the old attribute remains in place until Microsoft provides a way to remove it.

Eventually, you build out all the custom security attributes for the set (Figure 3) and are ready to populate some data.

Attributes in an Azure AD custom security attribute set
Figure 3: Attributes in an Azure AD custom security attribute set

This is when you get the chance for a coffee break. When I set things up in two different tenants, it took several hours for Azure AD to recognize that a new set of custom security attributes is available to be populated. Microsoft says that new attributes should show up faster. It could be that the slowness I experienced is just a preview glitch.

In any case, you’ll know when things are ready when the Custom security attributes (preview) option in the Users blade of the Azure AD admin center is no longer greyed out. If the option stays greyed out after a couple of hours, it might be a chance to have a mild panic. Or just wait a bit longer and check the troubleshooting hints again.

Populating Azure AD Custom Security Attributes

Adding custom security attributes to Azure AD is nice; being able to store some user data in those attributes is even better. The basic approach is to edit user properties in the Azure AD admin center and choose Custom security attributes from the Manage menu. You can then select attributes to add from the available attribute sets (Figure 4).

Adding Azure AD custom security attributes for a user
Figure 4: Adding Azure AD custom security attributes for a user

The Azure AD admin center GUI for Azure AD custom attributes could never be considered user friendly. Then again, neither is the GUI available for custom attributes in the new Exchange Online admin center (Figure 5). Both are passable, but only because it’s likely that code will write data into both types of custom attributes most often.

Exchange custom attributes in the (new) Exchange Online admin center
Figure 5: Exchange custom attributes in the (new) Exchange Online admin center

Because Azure AD indexes custom security attributes, they can be used to filter user accounts. Add a filter in the normal manner and select custom security attribute as the filter, then the attribute set and attribute to use, the operator, and the value (Figure 6).

Filtering Azure AD users with custom security attributes
Figure 6: Filtering Azure AD users with custom security attributes

Using PowerShell to Transfer Custom Attributes from Exchange Online to Azure AD

Speaking of PowerShell, if we want to move data from Exchange Online to Azure AD, we need to write some code. The PowerShell code below requires the Exchange Online management module to read the mailbox information and version of the Azure AD preview module to update the Azure AD accounts. The code is very simple:

  • Find user mailboxes in the tenant.
  • If CustomAttribute8 holds a value, use it to update the JobCode custom security attribute for the Azure AD account.
  • If CustomAttribute12 holds a value, use it to update the LegalEntity custom security attribute for the Azure AD account.

No error checking or validation of the data held in the Exchange custom attributes occurs. I’ll leave those pieces to your imagination. Here’s the code:

[array]$Mbx = Get-ExoMailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited -Properties CustomAttribute8, CustomAttribute12
If (!($Mbx)) { Write-Host "No mailboxes found - exiting"; break}
ForEach ($M in $Mbx) {
  If (!([string]::IsNullOrWhiteSpace($M.CustomAttribute8))) {
  # Update the JobCode in Azure AD
  $JobCodeInfo = @{
    Employees = @{
        "@odata.type" = "#Microsoft.DirectoryServices.CustomSecurityAttributeValue"
        JobCode = "$($M.CustomAttribute8)"
   Write-Host ("Updating account {0} job title to {1}" -f $M.DisplayName, $M.CustomAttribute8)
   Set-AzureADMSUser -Id $M.ExternalDirectoryObjectId -CustomSecurityAttributes $JobCodeInfo
   }  # End if
   If (!([string]::IsNullOrWhiteSpace($M.CustomAttribute12))) {
       # Update Legal Entity in Azure AD
       $LegalEntityInfo =  @{
        Employees = @{
            "@odata.type" = "#Microsoft.DirectoryServices.CustomSecurityAttributeValue"
            LegalEntity = "$($M.CustomAttribute12)"
         Write-Host ("Updating account {0} legacy entity to {1}" -f $M.DisplayName, $M.CustomAttribute12)
         Set-AzureADMSUser -Id $M.ExternalDirectoryObjectId -CustomSecurityAttributes $LegalEntityInfo
   } # End if
} # End ForEach

To remove the sensitive user information from Exchange Online, you could use the Set-Mailbox cmdlet to overwrite the custom attributes. However, before you put all your custom attribute eggs in the Azure AD basket, read the notes about retrieving information below.

Further details of how to manage Azure AD custom security attributes with PowerShell or the Microsoft Graph are available here.

Searching and Retrieving Information

And now some bad news. Transferring information from Exchange Online to Azure AD using PowerShell is straightforward. Accessing it afterwards is more challenging. As described above, you can use the Azure AD admin center to filter objects based on custom security attributes, but it’s likely that you’ll also want to access the data in scripts.

For Exchange custom attributes, the task is straightforward because you can use a server-side filter. For example:

Get-Recipient -Filter {CustomAttribute12 -eq "United States"}

The matching objects are found by the server and returned to the workstation in an array ready to be processed in whatever way the scripter wishes.

The PowerShell implementation for fetching Azure AD custom security attributes is poor and requires too much effort to find and extract data. First, you can’t run Get-AzureADUser to filter against values in custom security attributes. Instead, you need to check accounts individually by running the Get-AzureADMSUser cmdlet:

$Attributes = Get-AzureADMSUser -Id Brian.Weakliam@Office365itpros.com -Select CustomSecurityAttributes

The returned object is a MsUser type (rather than standard PowerShell object). To see the actual values, we need to examine the CustomSecurityAttributes property, which is a JObject type, to see:


Type                       : Object
HasValues                  : True
First                      : {}
Last                       : {}
Count                      : 4
Parent                     : {"@odata.type": "#microsoft.graph.customSecurityAttributeValue" "JobCode": "OpsMgr" "LegalEntity": "RA Ireland" "EmployeeNumber": 150823}
Root                       : {Employees}
Next                       :
Previous                   :
Path                       : Employees
LineNumber                 : 0
LinePosition               : 0
IsReadOnly                 : False
AllowNew                   : True
AllowEdit                  : True
AllowRemove                : True
SupportsChangeNotification : True
SupportsSearching          : False
SupportsSorting            : False
IsSorted                   : False
SortProperty               :
SortDirection              : Ascending
IsFixedSize                : False
SyncRoot                   : System.Object
IsSynchronized             : False
Keys                       : {@odata.type, JobCode, LegalEntity, EmployeeNumber}

The information we need to access is there, but it’s hard (and slow) to get at it.

Microsoft’s answer is to use the Graph API. For instance, an example in their documentation shows how to fetch data by filtering users using an equal match against a custom security attribute. The query looks for objects with the value Canada in the custom attribute AppCountry in the Marketing attribute set:


Although it’s not hard to include Graph API queries in PowerShell scripts, extra code and effort is needed. I understand why Microsoft would concentrate on the Graph API for programmatic access to date, especially for preview releases, but it’s a pity that simple (and fast) PowerShell querying capability against Azure AD custom security attributes is unavailable.

Extensible Directories

Being able to extend the information held about user accounts is a nice feature to have. Microsoft has made a solid start in the preview of Azure AD custom security attributes, and the capability will become stronger when they add support for custom security attributes in conditional access policies. The lack of good PowerShell support might create an adoption barrier in some cases; in other circumstances, the Graph rules supreme and this isn’t an issue.

All in all, Azure AD custom security attributes are worth investigating to discover if they can solve business problems for your Microsoft 365 tenant.

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.


  1. Adam Atwell

    Hello, thanks for the article! I have two questions. 1. Can these new AAD Custom Security Attributes be mapped to a AAD Enterprise Application relationship for syncing? 2. Do you know if the Exchange Custom Attributes are visible to users at large or only sys admins in backend?

    1. Avatar photo
      Tony Redmond

      Custom security attributes are currently only assignable to Azure AD user objects and security principals.

      Exchange custom attributes are not exposed by any client that I know of.

  2. Mike

    Great article. How can the Custom Security Attributes be accessed for SAML claims or expressions? Are they part of the user object or are they part of another object? I created a Custom Security Attribute and assigned it to a user but it doesn’t appear in the drop down of available attributes within the user object (user.CustomSecurityAttribute)

  3. Shane

    I really appreciate this article. Microsoft’s help documentation on Powershell for Custom Security Attributes is lacking right now and the examples they provided for Powershell weren’t working for me. (There’s a line “Project@odata.type” = “#Collection(String)” which it didn’t seem to like.) I saw your code and it set me on the right path. Thanks!

    1. Avatar photo
      Tony Redmond

      Documentation often needs time to catch up with the active use of new technology in the wild…

  4. Derek

    Good article. How do these differ from Graph Schema Extensions and Graph Open Extensions? I feel like there’s no simple english or best practice examples for these….

    1. Avatar photo
      Tony Redmond

      The Azure AD security attributes are defined for use by any tenants. Any extensions are, by definition, organization specific.

Leave a Reply