Active Directory Directory foundations

Schema attributes and linked values

Read class definitions, inspect indexes and the partial attribute set, and map forward links to their backlinks.

Read the definition before interpreting a value

If you’re adding an attribute, start with creating a custom attribute and designing a forward link and backlink. This page covers reading the definitions and working out what they mean.

The schema defines classes and attributes. A class’s required and optional attributes, inheritance and auxiliary classes affect which values an object may hold. lDAPDisplayName is the name used by LDAP clients; OIDs identify schema definitions; schemaIDGUID appears in object-specific access control entries.

$dc = 'dc1.contoso.com'
$schema = (Get-ADRootDSE -Server $dc).schemaNamingContext
Get-ADObject -Server $dc -SearchBase $schema -SearchScope OneLevel `
    -LDAPFilter '(lDAPDisplayName=member)' `
    -Properties attributeID,attributeSyntax,oMSyntax,isSingleValued,linkID,
        searchFlags,isMemberOfPartialAttributeSet,schemaIDGUID |
    Format-List *

For a class, check subClassOf, mustContain, mayContain, systemMustContain, systemMayContain and its auxiliary classes. Looking at mayContain alone will miss attributes inherited from other classes.

member is the forward link on a group. memberOf is the corresponding backlink on a member. Change the forward link; the directory maintains the backlink. A forward link has a positive, even linkID; its paired backlink has the next odd value. Create a new forward definition before its backlink. Microsoft’s linked attribute reference describes the relationship and constraints.

This small schema report indexes the definitions once rather than searching the entire list for each pair:

$attributes = @(Get-ADObject -Server $dc -SearchBase $schema `
    -SearchScope OneLevel `
    -LDAPFilter '(&(objectClass=attributeSchema)(linkID=*))' `
    -Properties linkID,lDAPDisplayName)

$byId = @{}
foreach ($attribute in $attributes) {
    $byId[[long]$attribute.linkID] = $attribute
}

$attributes | Where-Object { $_.linkID -gt 0 -and $_.linkID % 2 -eq 0 } |
    ForEach-Object {
        $backlink = $byId[([long]$_.linkID + 1)]
        [pscustomobject]@{
            ForwardLink = $_.lDAPDisplayName
            ForwardID   = $_.linkID
            BackLink    = $backlink.lDAPDisplayName
            BackID      = $backlink.linkID
        }
    } | Sort-Object ForwardID

Linked value replication gives each forward-link value its own replication metadata. A membership edit can then replicate as a change to that value instead of a replacement of the whole member list. See replication internals.

Index flags are a bit field

Useful searchFlags bits include ordinary indexing (0x1), container indexing (0x2), ANR participation (0x4), preservation on deletion (0x8), tuple indexing (0x20), confidential treatment (0x80) and the RODC filtered attribute set (0x200). They have different purposes and additional constraints. The schema reference defines them.

Get-ADObject -Server $dc -SearchBase $schema -SearchScope OneLevel `
    -LDAPFilter '(&(objectClass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))' `
    -Properties lDAPDisplayName,searchFlags |
    Select-Object lDAPDisplayName,searchFlags

An index is built and used locally on each replica. The schema change replicates, while the physical index pages do not. Indexes consume disk and maintenance work; a high-churn attribute can make that cost noticeable. Collect query evidence before changing forest-wide schema settings.

Confidential is an access check

The confidential bit adds a control-access requirement to the normal read-property checks. You’ll still need suitable ACLs, and the value isn’t encrypted. Filtering an attribute from an RODC doesn’t make it confidential on writable DCs either.

ANR participation requires ordinary indexing too. Confidential treatment is ignored for base-schema attributes as described in the search-flags reference; it is not a way to retrofit secrecy onto any built-in attribute. Preserve unrelated bits when planning a flag change: setting an integer to 128 can clear indexing or deletion-preservation flags that were already present.

Inspect the global catalog attribute set

Get-ADObject -Server $dc -SearchBase $schema -SearchScope OneLevel `
    -LDAPFilter '(&(objectClass=attributeSchema)(|(isMemberOfPartialAttributeSet=TRUE)(systemFlags:1.2.840.113556.1.4.803:=2)))' `
    -Properties lDAPDisplayName,isMemberOfPartialAttributeSet,systemFlags |
    Select-Object lDAPDisplayName,isMemberOfPartialAttributeSet,systemFlags |
    Sort-Object lDAPDisplayName

An attribute can be required in the partial set by systemFlags bit 0x2, as well as selected through isMemberOfPartialAttributeSet. The MS-ADTS system-flags definition distinguishes that bit from the similarly numbered bits of searchFlags. Moving data into the GC affects every GC replica; validate expected replication and storage costs before extending the set.

Resolve the GUID in an object-specific ACE

An ACE’s ObjectType can identify a class or attribute by schemaIDGUID, or an extended right/property set by rightsGuid. InheritedObjectType can restrict the class of descendant objects to which the ACE applies. A property set groups attributes through their attributeSecurityGUID; it is not the same identifier as an individual attribute’s schema GUID.

$root = Get-ADRootDSE -Server $dc
$guidMap = @{}
Get-ADObject -Server $dc -SearchBase $root.schemaNamingContext `
    -LDAPFilter '(schemaIDGUID=*)' -Properties schemaIDGUID,lDAPDisplayName |
    ForEach-Object {
        $key = ([guid]$_.schemaIDGUID).Guid
        $guidMap[$key] = $_.lDAPDisplayName
    }
$rightsBase = "CN=Extended-Rights,$($root.configurationNamingContext)"
Get-ADObject -Server $dc -SearchBase $rightsBase -SearchScope OneLevel `
    -LDAPFilter '(rightsGuid=*)' -Properties rightsGuid,displayName |
    ForEach-Object { $guidMap[([guid]$_.rightsGuid).Guid] = $_.displayName }

# Replace with the ObjectType or InheritedObjectType GUID from the actual ACE.
$guidMap['bf967aba-0de6-11d0-a285-00aa003049e2']

Once you’ve resolved the GUID, read the rest of the ACE: ActiveDirectoryRights, allow/deny, inheritance and the principal. You’ll need those to work out effective access. Microsoft’s object-specific access model and directory ACE example explain the class/property-set/attribute levels.

A missing attribute can have several causes

Before changing the schema, distinguish an unset value, an unrequested property, a confidential value the caller cannot read, a constructed attribute requiring a suitable search, and an attribute absent from a GC’s partial replica. Query the same GUID on a writable DC in its owning domain with the intended credentials and an explicit property list.

After a schema change, check replication, the local schema cache and any index build separately. The write on the schema master can succeed before another DC is ready to use the definition. Try the application’s operation on the DCs it uses rather than relying on a fixed wait.

RootDSE’s schemaUpdateNow operational attribute requests a local schema-cache refresh. It is an active operation, not a query, and cannot supply a schema change that has not reached that DC. Microsoft’s schema-cache procedure describes its purpose. When one application server can use a new attribute and another cannot, compare the actual DCs, replicated definition and requested operation before repeatedly reapplying a forest schema extension.

Schema edits outlive an application install

Making an attribute mandatory can prevent object creation when management tools do not supply it. OID ownership, syntax, ranges, defaults, permissions, indexes and rollback limitations all belong in the design review. Removing a product does not necessarily undo its schema extension. Test with the actual object-creation and synchronization clients before introducing the change to a forest.

← All Active Directory topics