{"id":1308,"date":"2025-10-19T02:14:03","date_gmt":"2025-10-19T00:14:03","guid":{"rendered":"https:\/\/blog.chrisse.se\/?p=1308"},"modified":"2025-10-19T11:35:20","modified_gmt":"2025-10-19T09:35:20","slug":"active-directory-32k-pages-dit-and-the-jet_bitsetuniquemultivalues-issue-the-real-exchange-schema-issue","status":"publish","type":"post","link":"https:\/\/blog.chrisse.se\/?p=1308","title":{"rendered":"Active Directory &#8211; 32k pages DIT and the JET_bitSetUniqueMultiValues issue (The real Exchange Schema Issue)"},"content":{"rendered":"\n<p>So after HIPConf 25 and meeting some people from the AD team &#8211; having good discussions, I thought it would be nice to deep dive into what I love the most &#8211; Active Directory and it&#8217;s internal workings, I decided to dig into this issue that has been posted a lot to me and people has asked what I think about it: <a href=\"https:\/\/techcommunity.microsoft.com\/blog\/exchange\/active-directory-schema-extension-issue-if-you-use-a-windows-server-2025-schema-\/4460459\">Active Directory schema extension issue if you use a Windows Server 2025 schema master role | Microsoft Community Hub<\/a><\/p>\n\n\n\n<p>So what is going on here &#8211; a bad exchange schema upgrade that would cause replication to fail? At first you can think that would be the case &#8211; it&#8217;s NOT according to me, but I would hold on that the exchange schema upgrade do something bad [1] &#8211; let&#8217;s get back to that later.<\/p>\n\n\n\n<p>So when can this disaster strike &#8211; if you&#8217;re running Exchange adprep to extend your Active Directory schema for the first time, aka the forest had no previous versions of Exchange schema extensions &#8211; nope nothing happens regardless of the versions of your DCs, Including the Schema FSMO &#8211; running Windows Server 2025.<br><br>If you run adprep and ALREADY have extended your schema for Exchange previously and the Schema FSMO would be running Windows Server 2025 &#8211; then you would run into issues &#8211; But what really happens?<br><br>Attributes with the syntax 2.5.5.2 aka String(Object-Identifier) suddenly takes duplicates &#8211; here it&#8217;s time to tell what exchange is doing bad [1] &#8211; Exchange adprep never check if a value is already present in those attributes, instead on each update (CU\/Release) it&#8217;s trying to add the same value again, relaying that AD throw&#8217;s them out with ATT_OR_VALUE_EXISTS &#8211; below we can see how that works when the Schema &#8211; FSMO is held by a Windows Server 2008 R2<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"417\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-6-1024x417.png\" alt=\"\" class=\"wp-image-1311\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-6-1024x417.png 1024w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-6-300x122.png 300w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-6-768x313.png 768w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-6.png 1033w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>But this will be allowed on Windows Server 2025?<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"411\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-7-1024x411.png\" alt=\"\" class=\"wp-image-1312\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-7-1024x411.png 1024w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-7-300x120.png 300w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-7-768x308.png 768w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-7.png 1453w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>That is not good &#8211; and it will break Active Directory replication on the receiving end if it&#8217;s a down-level DC (e.g. not Windows Server 2025 [2]) the update will only apply one of the duplicate e.g. the duplicate detection will work, so if we&#8217;re looking up our example class here &#8216;Address-Book-Container&#8217; between the schema FSMO and another DC.<br><br>Why will it not break replication to other Windows Server 2025 DCs? Well they suffer from the same duplication bug &#8211; or do they really? [2]<\/p>\n\n\n\n<p>This is how it would look like on a down-level DC (e.g. not Windows Server 2025)<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1008\" height=\"348\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-9.png\" alt=\"\" class=\"wp-image-1315\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-9.png 1008w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-9-300x104.png 300w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-9-768x265.png 768w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1012\" height=\"283\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-10.png\" alt=\"\" class=\"wp-image-1316\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-10.png 1012w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-10-300x84.png 300w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-10-768x215.png 768w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>And of course it&#8217;s a schema mismatch when the definition of a class is different between two replocas, one with two values for the attribute auxiliaryClass (2) country;country while the other only has auxiliaryClass (1) country;<br><br>Well let&#8217;s go a step beyond this and leave Exchange for a while, let&#8217;s add our own attr <strong>(chDsObjid)<\/strong> with the syntax 2.5.5.2 aka String(Object-Identifier) <br><\/p>\n\n\n\n<p>Windows Server 2025 DC<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"693\" height=\"174\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-8.png\" alt=\"\" class=\"wp-image-1314\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-8.png 693w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-8-300x75.png 300w\" sizes=\"auto, (max-width: 693px) 100vw, 693px\" \/><\/figure>\n\n\n\n<p>Windows Server 2022 DC<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"693\" height=\"132\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-11.png\" alt=\"\" class=\"wp-image-1317\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-11.png 693w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-11-300x57.png 300w\" sizes=\"auto, (max-width: 693px) 100vw, 693px\" \/><\/figure>\n\n\n\n<p>So the same behavior &#8211; however this will not cause a schema mismatch and break replication, only bring inconsistency. <br><br>So what is wrong here, something most be wrong with Active Directory&#8217;s duplication logic on Windows Server 2025 [2] or?<br><br>Let&#8217;s again look at how it should work &#8211; we should be thrown out if where trying to add a value that already exists on a attribute with syntax 2.5.5.2 aka String(Object-Identifier) <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"888\" height=\"169\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-12.png\" alt=\"\" class=\"wp-image-1318\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-12.png 888w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-12-300x57.png 300w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-12-768x146.png 768w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>We are and it works as expected on down-level DC (e.g. not Windows Server 2025) &#8211; We get a DSID &#8211; that can give us a pointer to where this is blocked in the ds source. I happen to know that AD has it&#8217;s own detection for duplicates values for certain syntaxes, but not for 2.5.5.2 aka String(Object-Identifier) &#8211; here Active Directory solidly relays on Extensible Storage Engine &#8211; ESENT \/ Jet for value duplication detection.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"384\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-13-1024x384.png\" alt=\"\" class=\"wp-image-1320\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-13-1024x384.png 1024w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-13-300x112.png 300w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-13-768x288.png 768w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-13.png 1147w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/extensible-storage-engine\/jetsetcolumn-function\"><strong>JetSetColumn <\/strong><\/a>is called with grbit <strong>JET_bitSetUniqueMultiValues<\/strong> = 0x00000080 &#8211; this seems to fail on Windows Server 2025? [2]<\/p>\n\n\n\n<p>I felt I had to try out this my self on the Extensible Storage Engine &#8211; ESE level so what the heck how hard can it be to modify ESEDump to do writes to the DIT:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"507\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-14-1024x507.png\" alt=\"\" class=\"wp-image-1322\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-14-1024x507.png 1024w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-14-300x148.png 300w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-14-768x380.png 768w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-14.png 1263w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>So let&#8217;s try this and see if we&#8217;re thrown out by ESE &#8211; if we first try with a Windows Server 2022 DIT (8k)<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"191\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/Skarmbild-2025-10-18-194404-1024x191.png\" alt=\"\" class=\"wp-image-1323\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/Skarmbild-2025-10-18-194404-1024x191.png 1024w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/Skarmbild-2025-10-18-194404-300x56.png 300w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/Skarmbild-2025-10-18-194404-768x143.png 768w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/Skarmbild-2025-10-18-194404.png 1333w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>Yes that works as expected, let&#8217;s try the very same code now on a Windows Server 2025 DIT (32k)<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"184\" src=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-15-1024x184.png\" alt=\"\" class=\"wp-image-1324\" srcset=\"https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-15-1024x184.png 1024w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-15-300x54.png 300w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-15-768x138.png 768w, https:\/\/blog.chrisse.se\/wp-content\/uploads\/2025\/10\/image-15.png 1438w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>Ops &#8211; Something must be wrong within Extensible Storage Engine -ESE (ESENT.dll) &#8211; we&#8217;re getting through here even if we&#8217;re calling <strong><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/extensible-storage-engine\/jetsetcolumn-function\" data-type=\"link\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/extensible-storage-engine\/jetsetcolumn-function\">JetSetColumn <\/a><\/strong>with grbit <strong>JET_bitSetUniqueMultiValues <\/strong>and a value that is already present in the column.<\/p>\n\n\n\n<p>But let&#8217;s try a DIT from Windows Server 2022 (8k) on Windows Server 2025 \ud83d\ude42 We&#8217;re thrown out with ESENT error: A duplicate value was detected on a unique multi-valued column. <br><br>But wait wasn&#8217;t Windows Server 2025 broken or had some defect in ESENT.dll? <br><br>My understanding is that this has to do with the page size of the NTDS.dit database and that <strong>JET_bitSetUniqueMultiValues <\/strong>don&#8217;t work correctly on 32k pages DBs and has never done, no matter of the underlaying operating system, it just happen to be that on Windows Server 2025 all NTDS.dit databases are 32k pages.<br><br>But wait shouldn&#8217;t the database be 32k pages first when the &#8220;Database 32k pages optional feature&#8221; has been enabled? No, again all NTDS.dit&#8217;s on Windows Server 2025 is 32k page by default, the &#8220;Database 32k pages optional feature&#8221; only let go of restrictions enforced to be able to co-exist with downl-level replicas (e.g. none Windows Server 2025 DCs)<\/p>\n\n\n\n<p>[2] The issue has nothing to do with Active Directory &#8211; it seems to be a bug in Extensible Storage Engine &#8211; ESENT (ESENT.dll)<\/p>\n\n\n\n<p><strong>Summary<\/strong><\/p>\n\n\n\n<p>It took me a day to figure out and test this, including writing a version of ESEDump that could prove this. Exchange should look for the values they are trying to add and not relay on Active Directory throwing an error that the value already exists.<br><br>How can you find effected attributes, run the following AD query against your Schema NC:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">PowerShell<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292eff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>Get-ADObject -SearchBase (Get-ADRootDSE).schemaNamingContext -LDAPFilter \"(&amp;(attributeSyntax=2.5.5.2)(isSingleValued=FALSE))\"<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki min-light\" style=\"background-color: #ffffff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6F42C1\">Get-ADObject<\/span><span style=\"color: #24292EFF\"> <\/span><span style=\"color: #D32F2F\">-<\/span><span style=\"color: #24292EFF\">SearchBase (<\/span><span style=\"color: #6F42C1\">Get-ADRootDSE<\/span><span style=\"color: #24292EFF\">).schemaNamingContext <\/span><span style=\"color: #D32F2F\">-<\/span><span style=\"color: #24292EFF\">LDAPFilter <\/span><span style=\"color: #22863A\">&quot;(&amp;(attributeSyntax=2.5.5.2)(isSingleValued=FALSE))&quot;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>It is possible to fix this if you run into it &#8211; without during a forest recovery. Please contact Microsoft Support and they will help you to get back in a supported manner, I know how to get out of this as well &#8211; but I&#8217;m not Microsoft nor do I work for Microsoft, I&#8217;m just a Active Directory geek that like to figure out how things work, or not work.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So after HIPConf 25 and meeting some people from the AD team &#8211; having good discussions, I thought it would be nice to deep dive into what I love the most &#8211; Active Directory and it&#8217;s internal workings, I decided to dig into this issue that has been posted a lot to me and people &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/blog.chrisse.se\/?p=1308\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Active Directory &#8211; 32k pages DIT and the JET_bitSetUniqueMultiValues issue (The real Exchange Schema Issue)&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[41],"tags":[6,16],"class_list":["post-1308","post","type-post","status-publish","format-standard","hentry","category-active-directory","tag-active-directory","tag-ntds-dit"],"_links":{"self":[{"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/posts\/1308","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1308"}],"version-history":[{"count":14,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/posts\/1308\/revisions"}],"predecessor-version":[{"id":1334,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/posts\/1308\/revisions\/1334"}],"wp:attachment":[{"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1308"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1308"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1308"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}