Active Directory Directory foundations

Design a forward link and backlink

Create a linked pair, let AD maintain the reverse view and check the result from both objects.

Model the relationship before choosing attribute names

You want to record who’s responsible for a computer’s maintenance, then look up all the computers that refer to that person. A linked pair lets the application write the relationship on the computer account and lets AD work out the reverse view.

We’ll use exampleMaintainer as the multivalued forward link on computer accounts and exampleMaintainedDevice as its multivalued backlink. This records the maintenance contact. It doesn’t grant logon rights, group membership, ownership of an AD security descriptor or permission to administer the computer.

Computer LABPC01
    exampleMaintainer → Contact user Alice

Contact user Alice
    exampleMaintainedDevice → Computer LABPC01
    (derived from forward links)

If each computer should have exactly one contact, use a single-valued forward link. The backlink still needs to be multivalued because several computers can refer to the same contact. Linked-attribute rules.

Start with creating a custom attribute if you haven’t already. We’ll use its test forest, stable OIDs/schema GUIDs, staged import process and exampleDeviceInventory auxiliary class, which is statically associated with computer. The LDIF templates below change the forest schema; fill in your identifiers and check the DNs before importing them.

Use a DN attribute for an object reference

With DN syntax, AD knows which object a value refers to and can follow it through renames and moves. Putting CN=Alice,... in an ordinary string attribute won’t give you that behavior.

Object(DS-DN) uses these three syntax fields together:

Property Value
attributeSyntax 2.5.5.1
oMSyntax 127
oMObjectClass bytes 2B 0C 02 87 73 1C 00 85 4A
LDIF representation oMObjectClass:: KwwCh3McAIVK

The double colon encodes a binary value as base64. rangeUpper does not restrict the number of DN values or impose a target-class constraint. Check the protocol syntax table and attribute range rules. The application must enforce that a chosen target is an appropriate contact; the DN syntax does not mean “only user objects.”

Modern AD supports automatic linkID allocation during the LDAP Add of a new schema attribute. For the forward link, 1.2.840.113556.1.2.50 requests an unused even numeric ID. This allocator identifier is not the forward attribute’s attributeID; the attribute still needs its own allocated OID.

Create the forward definition and refresh the contacted DC’s schema cache before creating the backlink. For the backlink’s linkID, supply the existing forward attribute’s LDAP display name or attribute OID. AD resolves the pair and assigns forward ID plus one. The stored linkID is then numeric; it does not remain the name or allocator OID. Obtaining a link ID, protocol auto-generation.

The allocated numeric IDs can differ between forests. Use the stable OIDs/schema GUIDs to identify your definitions, then check the numeric pair each forest assigned. Since linkID is system-only, you can’t turn an ordinary unlinked attribute into a linked pair by editing that field later. That would need a new definition and a plan to migrate the values.

04-forward-link.ldf

Allocate fresh OIDs/GUIDs for both definitions; preserve them in the extension manifest. Replace every placeholder and the forest-root schema suffix. This stage adds the forward link and performs a local cache refresh:

dn: CN=Example-Maintainer,CN=Schema,CN=Configuration,DC=contoso,DC=com
changetype: add
objectClass: attributeSchema
cn: Example-Maintainer
adminDisplayName: Example maintainer
lDAPDisplayName: exampleMaintainer
attributeID: <FORWARD_ATTRIBUTE_OID>
schemaIDGUID:: <BASE64_FORWARD_GUID>
attributeSyntax: 2.5.5.1
oMSyntax: 127
oMObjectClass:: KwwCh3McAIVK
isSingleValued: FALSE
linkID: 1.2.840.113556.1.2.50
searchFlags: 0
isMemberOfPartialAttributeSet: FALSE

dn:
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-

05-backlink.ldf

Import only after the forward definition and cache refresh succeed. The backlink is calculated and system-maintained:

dn: CN=Example-Maintained-Device,CN=Schema,CN=Configuration,DC=contoso,DC=com
changetype: add
objectClass: attributeSchema
cn: Example-Maintained-Device
adminDisplayName: Example maintained device
lDAPDisplayName: exampleMaintainedDevice
attributeID: <BACK_ATTRIBUTE_OID>
schemaIDGUID:: <BASE64_BACK_GUID>
attributeSyntax: 2.5.5.1
oMSyntax: 127
oMObjectClass:: KwwCh3McAIVK
isSingleValued: FALSE
systemOnly: TRUE
linkID: exampleMaintainer
searchFlags: 0
isMemberOfPartialAttributeSet: FALSE

dn:
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-

The name in the backlink’s linkID is an instruction to the allocator when the definition is created. The field still stores a number. Keep any import error so you can investigate it; ldifde -k can skip errors you need to see.

Allow the attributes on the appropriate classes

Add the forward link to the optional auxiliary class from the first note. For the backlink, we’ll follow Microsoft’s convention of adding it to top, allowing objects of any class to show the reverse relationship. Review that forest-wide class change as part of the design. Allowing the attribute on a class doesn’t grant anyone permission to write the forward values.

dn: CN=Example-Device-Inventory,CN=Schema,CN=Configuration,DC=contoso,DC=com
changetype: modify
add: mayContain
mayContain: exampleMaintainer
-

dn: CN=Top,CN=Schema,CN=Configuration,DC=contoso,DC=com
changetype: modify
add: mayContain
mayContain: exampleMaintainedDevice
-

dn:
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-

Save this as stage 06 and import it through the schema master, checking the result as you did for the earlier stages. You can allow the backlink on a narrower class instead. Watch the inheritance, though: computer derives from user, so adding a property to user also makes it available to its subclasses. That won’t restrict the forward link’s targets to human users. Computer class hierarchy.

The dependency chain is now: forward definition → cache refresh → backlink definition → cache refresh → class applicability → cache refresh → object writes. The refresh is blocking and local; another DC must receive the definitions and become ready independently. Cache operation.

Verify the definitions before populating data

This reads the definitions from one explicit writable DC:

$dc = 'dc1.contoso.com'
$schema = (Get-ADRootDSE -Server $dc).schemaNamingContext
Get-ADObject -Server $dc -SearchBase $schema -SearchScope OneLevel `
    -LDAPFilter '(|(lDAPDisplayName=exampleMaintainer)(lDAPDisplayName=exampleMaintainedDevice))' `
    -Properties attributeID,schemaIDGUID,attributeSyntax,oMSyntax,
        oMObjectClass,linkID,isSingleValued,systemOnly |
    Select-Object Name,attributeID,
        @{Name='SchemaGuid';Expression={([guid]$_.schemaIDGUID).Guid}},
        attributeSyntax,oMSyntax,
        @{Name='OmObjectClassBase64';Expression={
            if ($null -ne $_.oMObjectClass) {
                [Convert]::ToBase64String([byte[]]$_.oMObjectClass)
            }
        }},linkID,isSingleValued,systemOnly |
    Format-List

Check that the forward ID is positive and even, the backlink ID is one higher, and both definitions have the OIDs/GUIDs, DN syntax and cardinalities you planned. OmObjectClassBase64 should be KwwCh3McAIVK. Then check exampleDeviceInventory.mayContain, computer.auxiliaryClass and top.mayContain so you know the attributes are allowed on the right classes too.

Write the forward side and inspect both objects

Using pre-existing test accounts in the same domain, the following adds one forward relationship:

$dc = 'dc1.contoso.com'
$contact = Get-ADUser -Server $dc -Identity 'LabContact01'
Set-ADComputer -Server $dc -Identity 'LABPC01' `
    -Add @{exampleMaintainer = $contact.DistinguishedName} -Confirm
Get-ADComputer -Server $dc -Identity 'LABPC01' -Properties exampleMaintainer |
    Select-Object ObjectGUID,exampleMaintainer
Get-ADUser -Server $dc -Identity $contact.ObjectGUID `
    -Properties exampleMaintainedDevice |
    Select-Object ObjectGUID,exampleMaintainedDevice

Use -Add to add one contact. -Replace would replace the whole value set and could remove the other contacts. If you’re retrying a command, check whether the value is already present; adding it again can return an error. AD maintains the backlink, so the application only needs to write the forward side.

Linked-value replication tracks each forward-link value. A replica calculates the backlink from the forward relationships it can see. If two replicas disagree, look at that forward-link state and its linked-value metadata.

Test identity, visibility and deletion behavior

Test What it establishes
Add/remove a forward value on a lab computer Both views reflect the same relationship without a client write to the backlink
Refer to one contact from two computers A backlink has two values even if a different design uses a single-valued forward link
Rename/move the contact within its domain The relationship follows the object; callers do not need to edit text DNs everywhere
Read as the application identity Effective access and requested attributes produce the intended view
Read on a second writable replica Relevant definitions and forward-link state are present before interpreting its reverse view
Delete and, where supported, restore a lab endpoint The application tolerates link removal and validates actual restoration behavior

Keep the object GUIDs and replica names with your results. Recreating a deleted object with the same name won’t restore its identity or automatically give it the old relationships. Link restoration depends on the recovery method and conditions; see object recovery for Recycle Bin and authoritative recovery.

For cross-domain relationships, examine where the forward objects live and what data the queried DC or GC actually holds. This example leaves the attributes outside the PAS, so it does not promise a complete forest-wide reverse query through a GC. Test the intended endpoint, class association, ACL, range retrieval and application behavior rather than treating every empty backlink as a lost link. GC view and returned attributes, large multivalue retrieval.

Check who can write the forward attribute, who can read the relationship and what the application does with it. Declaring the pair or adding the backlink to top doesn’t set those permissions for you. If the application uses this data to grant access, test that an unauthorized writer can’t change the relationship and gain that access.

← All Active Directory topics