You're in the middle of a routine user update—maybe you're changing lastLogonTimestamp or trying to set canonicalName via a PowerShell script—and boom, the operation fails with ERROR_DS_CONSTRUCTED_ATT_MOD (0X0000211B). The error message says "Modification of a constructed attribute is not allowed." This usually happens when a junior admin (or a poorly written script) tries to write to an attribute that Active Directory calculates on the fly. I've seen it most often with msDS-PrincipalName or objectSid, but it can bite you with any constructed attribute.
What's Actually Going On?
Active Directory has a few hundred attributes. Most are regular—you can read them and write to them. But a small set are constructed. That means the directory service computes their value from other data. For example, canonicalName is built from the distinguished name plus the domain structure. msDS-PrincipalName is derived from the sAMAccountName and domain. You can read these all day long, but writing to them would break the directory's internal consistency.
Think of it like a spreadsheet where a column has a formula. You can't type a value into that cell—Excel will scream at you. Same idea here. Windows NT 4.0 had a few of these, but Active Directory expanded the list. Microsoft documents them in the schema, but they're easy to miss if you're just poking around in ADSI Edit.
What Triggers It?
The most common trigger is a script or tool that does a bulk update—like setting every user's msDS-PrincipalName or trying to force a lastLogonTimestamp change. I also see it when someone copies an attribute from one object to another using PowerShell and forgets to filter out the constructed ones. Another classic: trying to set objectGUID because you want to sync it to some external system. Don't.
The Fix (It's Not What You Think)
Here's the blunt truth: you can't fix this by modifying the attribute. The only real fix is to change what you're trying to do. Let me walk you through the steps.
- Identify the attribute that's causing the issue. Look at your script or the error message. If the message doesn't name it, put a breakpoint or add a log line that prints the attribute being set. In PowerShell, wrap your
Set-ADUserin a try/catch and$_ | Format-List *to see the property. - Check if the attribute is constructed. Open ADSI Edit or use
Get-ADObjectto inspect the schema. The quick way is to run this against your domain:
Get-ADObject -SearchBase (Get-ADRootDSE).SchemaNamingContext -LDAPFilter "(attributeID=*)" -Properties name,attributeID | Where-Object { $_.name -eq 'msDS-PrincipalName' } | Format-List
But honestly, you can just search the web for "constructed attributes AD"—Microsoft has a list. Memorize the common ones: canonicalName, distinguishedName, objectGUID, objectSid, sAMAccountType. There are others like msDS-AdditionalSamAccountName.
- Stop writing to that attribute. Remove it from your script or tool. If you need the value for some downstream process, read it first, then pass it along—don't try to store it.
- If you're trying to modify something like
lastLogonTimestampfor testing, use the real attribute that supports writes. For logon tracking, that'slastLogon(though it doesn't replicate well). For a display name, usedisplayName—that's a regular attribute. - For scripts that do bulk updates, add a filter to exclude constructed attributes. Here's a quick PowerShell check:
$schema = Get-ADObject -SearchBase (Get-ADRootDSE).SchemaNamingContext -LDAPFilter "(objectClass=attributeSchema)" -Properties name,attributeID,systemFlags
$constructed = $schema | Where-Object { ($_.systemFlags -band 4) -ne 0 } | Select-Object -ExpandProperty name
# Then in your update loop, skip if the property is in $constructed
The systemFlags bit 4 marks an attribute as constructed. That's the official way to check.
If It Still Fails
So you removed the constructed attribute, but you're still getting the error? Then check your script for other hidden writes. Some cmdlets like Set-ADUser will try to update cn if you're changing the name—and cn is not constructed, but it's linked to the distinguished name. The error might be a side effect. Also, if you're using ADSI directly, remember that binding to an object and setting PutEx on any constructed attribute will throw this. Double-check every line.
Another gotcha: third-party tools like ADManager Plus or custom .NET code sometimes try to set instanceType or objectCategory—both of those are constructed too. If you're still stuck, run repadmin /showattr to see what's really on the object and compare it to what your operation is trying to change.
And one last thing—if you're positive you're not touching a constructed attribute and it still fails, check the schema version. I once spent an hour on this because a domain controller hadn't replicated the schema update that added a new attribute. The error was a red herring; the real issue was a replication lag. So repadmin /replsum is your friend.