A customer of an AD Bridge product ( https://github.com/BeyondTrust/pbis-open ) asked me:

What is the best practice around how to ensure the Users you want to “export” are available to define with PBIS settings in the named cell on the RESOURCE side. Essentially, what prerequisite needs to be met so from the RESOURCE side, we can see these users. Is it a universal group?

If it is a universal group, is the expectation that the admins of the USER domain would know when onboarding a user that requires linux access, to put them in that group on their side (the USER side) so they’re available for cell enabling on the RESOURCE side?

a Typical 1-way trust setup has users in the “USER” domain, and the computers joined to the “RESOURCE” domain.  We’ll use those names, but “RESOURCE” could be a DMZ zone, or a partner system, or anything else.  For this discussion, we’ll use the following 2 forests:


RESOURCE has a 1-way outbound trust to USER (RESOURCE trusts USER, but accounts in RESOURCE cannot access the USER or ROOT domains. ROOT users cannot log into RESOURCE either)

In Windows, there are 4 kinds of groups ,with different purposes and limitations.  These limitations change slightly depending on the AD forest functional level (nesting is much more restrictive in older Forest Functional levels).  This document describes the AD groups: https://technet.microsoft.com/en-us/library/dn579255(v=ws.11).aspx but to recap the AD group types are “Domain Local”, “Domain Global”, and “Universal”. The 4th is “Computer Local Group” which you manage in the “Local Users and Groups” plugin to the “Computer Management” snap-in in the Windows OS (not in AD).  On Linux, this last one equates somewhat to groups in /etc/group.

  • Universal Groups: can contain any: Domain Global group, Universal Group, or User/Computer account in the same AD forest as the Universal Group.  Universal Groups are stored in the Global Catalog, making updates to them slower than other group types.  You can use them to control rights on any resource anywhere in the forest.
  • Domain Global Groups: can contain any Domain Global group or User/Computer account from the same Domain as the Domain Global group. Domain Global groups can be used to control rights on any resource anywhere in the forest.
  • Domain Local Groups: can contain pretty much any Group from any trusted domain, including across 1-way trusts. Domain Local groups can ONLY go into Domain Local groups in the same domain, or Computer Local groups in Computers on that Domain.  Domain Local groups can only be used to control rights on a resource in the same domain as the local group.

Of note: Universal groups store (in the AD database) a DN reference, which is part of why they can only contain objects form the same domain.  Domain Local groups store a SID reference, which is why they work across one-way trusts. (Domain Local Group membership contains a “foreignKeyReference” as the members, whereas Universal Groups contain a link to the GC object in the DIT which is expanded to the DN of the object on retrieval (meaning that if you move the member, the Universal Group membership doesn’t need to be updated, because the UUID of the object referenced by the link didn’t change).

Think of it this way: Users go into Universal and Domain Global groups.  Domain Global groups go into Domain Local Groups.  Domain Local groups are used to control access to Local resources in the Domain.  What this means is that if USER\rob is in the Domain Local group USER\dlg1, and accesses a server file01.root.local: file01 doesn’t even see that USER\rob is in USER\dlg1, because USER\dlg1 isn’t in the ROOT domain that file01 is in.  AD doesn’t even bother returning any foreign Domain Local groups in the Kerberos Ticket PAC (in the TGS) to file01, since that group can’t be used to control resources outside of the USER domain.

For any other 1-way-enabled AD Bridge like PBIS or Samba, then, which groups can we provision into the cell / Computers in RESOURCE?  PBIS specifically is less restrictive than AD (samba is not), and will allow you to import the Domain Global and Universal, and even if you try hard enough, the Domain Local groups from USER into the cell in RESOURCE, and use LDAP calls to attempt to resolve the Universal and Domain Global groups and their membership, because everything I just stated above is pretty difficult to explain to a Unix admin on a tech support call. In other words: the BeyondTrust PBIS Product will export the USER Domain Local groups to the RESOURCE domain computers, so that the Unix admins don’t have to know anything in this post, but the Samba admins will need to grok all of this.

But, when I’m designing a PBIS Cell design for a customer (it allows assigning UID numbers, rather than generating per host like Samba or SSSD), I will try to design the customer to build Domain Local groups in the RESOURCE domain, and populate those groups into the Cell, with the membership coming from the USER domain.  This meets the AD design methodologies, means that the Unix team can be delegated rights to control the group membership in the RESOURCE domain themselves, but not have any rights to any user accounts in USER. This also means that any Active Directory auditing tools will pick up and audit the users properly, and when PBIS drops this “nice enablement”, the customers I have worked with won’t need to make changes to their environment.

The information in this post came primarily from: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd861330(v=ws.11)
When I originally wrote this in late 2017.

The UPS on the lab servers is near the end of its life, so we’ve changed the shutdown script in power outages to simply hard-power off some of the servers (using Rob’s fork of ESXIDown from https://github.com/docsmooth/esxidown ). Of course, the second DC had to be one of them, so that there would be enough battery left for the SQL server and FSMO / PDC to shut down cleanly. THis means that the second DC often fails to boot properly when the power comes back after our yearly ComEd outage.

So, how do you fix this without doing the research every time? Thankfully, modern versions of Windows can be configured to boot to recovery mode. If you log in and launch a command prompt, you can run the following commands to find and repair problems:

  1. Launch the command prompt.

    recovery mode cmd.exe window example

    Launching CMD.EXE in recovery window

  2. navigate to your drive with the NTDS.DIT file (on our lab server, it’s always d:\windows\ntds:
  3. Run an ESENTUTL checksum on the Active Directory database file ntds.dit:
    d:\windows\system32\esentutl.exe /k ntds.dit

    ESENTUTL.exe completed checksum

    ESENTUTL.exe completed checksum

  4. Even though that’s successful, you’ll probably fail an integrity check:
    d:\windows\system32\esentutl.exe /g edb
    On our server, that always generates the error:

    The database is not up-to-date. Integrity check may find that this database is corrupt because data from the log files has yet to be placed in the database. It is strongly recommended the database is brought up-to-date before continuing! Do you wish to abort the operation?

  5. If the checksum passed and you get this error, try rebooting into Directory Services Repair Mode – exit the command prompt and hit “Restart” and then pound on F8 to get the DSRM boot option.
  6. If DSRM bluescreens, then you need to go deeper into esentutl.exe to repair your DB. If this is NOT your only DC, you will have data loss, but it should replicate from other DCs back into this one, so it shouldn’t be a huge problem.
    If DSRM works, try an ntdsutil in cmd.exe:
    activate instance ntds
  7. If ntdsutil file recovery errors with

    Could not initialize the Jet engine: Jet Error -543.
    Failed to open DIT for AD DS/LDS instance NTDS. Error -21478418113

    then you need to do more work with esentutl, but can continue inside DSRM, rather than having to reboot.

    If you couldn’t boot into DSRM, continue as below, but from the recovery install CMD.exe. I’ll continue these commands from THAT pathing, since it turns out not bothering to jump into DSRM makes for a faster recovery, with ensured data loss. I don’t care abuot data loss in our lab though.

  8. Try to recover the database: d:\windows\system32\esenutl.exe /ml d:\windows\ntds\edb
  9. If that doesn’t work, delete the edb.log files, then try recovery again. You’ll get an error like

    Operation terminated with error -501 (JET_errLogFileCorrupt, Log file is corrupt) after 2.123 Seconds.

    So backup your logs to a new location or delete them outright:
    mkdir log-backup
    move edb*.log log-backup
    move edb.chk log-backup

  10. Recreate the log files with a hard recovery of the database:
    d:\windows\system32\esentutl.exe /p d:\windows\ntds\ntds.dit
    You’ll get an error saying you should only run this on damaged or corrupt databases. The checks before this have proven that that is the case in this situation, so click “OK”.
  11. This should restore the database and complete successfully. Reboot and test it. If it doesn’t work, or doesn’t boot, try again in all offline mode without jumping to DSRM.
  12. If that still doesn’t work:
  13. Recheck the database integrity:
    cd \windows\ntds
    esentutl /g: ntds.dit
  14. Do a database repair again:d:\windows\system32\esentutl.exe /p ntds.dit
  15. And reboot when that completes successfully. You *should* now boot properly, and the edb.chk and edb.log files should get rebuilt.

Sometimes it’s nice to know what’s happening under the hood, so let’s talk about how Group Policy is built, by tearing down how to access a particular policy. First, Group Policy is implemented in 2 parts, an LDAP part and a file part, delivered via SMB (CIFS if you’re oldschool) via DFS (Distributed FIle SYstem). Because the DFS part is replicated completely differently than the AD part, there’s a version number for each Group Policy object that’s stored in both places to keep them in sync. Most GPO engines remember the last version they applied by remembering the lowest of the 2 numbers (the LDAP version and the file version in the GPT.INI), if they don’t match.

Let’s talk about the “Default Domain Policy” which everyone will have one of. To find where that policy lives, you have to ask AD. The policy doesn’t actually live in the OU or Domain where it’s linked, so we have to back out the link:
ldap_search_s(ld, "dc=company,dc=com", 2, "(objectClass=organizationalUnit)", gpLink, base, &msg)
We’ll get back something like:

gPLink: [LDAP://CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=company,Dc=com;0]

Now, this is a multi-valued array, because multiple GPOs can be linked, in order, to a single OU or Domain or Site. But we only care about this one, so let’s see what’s in it:

ldap_search_s(ld, "CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=company,DC=com", 2, "(objectClass=*)", gPCMachineExtensionNames;gPCFileSysPath;displayName;versionNumber, 0, &msg)

That’ll get us the Client Side Extensions (where the work actually happens), and what the file path to the files in the estension are stored, as well as the pretty name of the Group Policy Object:

displayName: Default Domain Policy;
gPCFileSysPath: \\child1.lwtest.corp\sysvol\child1.lwtest.corp\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9};
gPCMachineExtensionNames: [{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{53D6AB1B-2488-11D1-A28C-00C04FB94F17}{53D6AB1D-2488-11D1-A28C-00C04FB94F17}{D02B1F72-3407-48AE-BA88-E8213C6761F1}][{827D319E-6EAC-11D2-A4EA-00C04F79F83A}{803E14A0-B4FB-11D0-A0D0-00A0C90F574B}][{B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A}{53D6AB1B-2488-11D1-A28C-00C04FB94F17}];
versionNumber: 15;

So we have the Default Domain Policy, as desired, but there are a bunch of client side extensions here. It’d be nice to know what they all do generically, without having to inspect each one.
And TechNet delivers on that desire: a list of all Client Side Extensions (in 2010) by GUID for easy reference. Now, I’m writing this, because someone asked where the Password Policy for the domain was stored. Well, that appears to be in: {827D319E-6EAC-11D2-A4EA-00C04F79F83A} Security, which our Default Domain policy applies. So, let’s go find the data!

One of the attributes in the list we last requested was gPCFileSysPath which returned a normal SMB share. If you browse to that share, you’ll see 3 objects:

  • A folder named “MACHINE”
  • A folder named “USER”
  • a file named “GPT.INI”

The GPT.INI will only have 2 lines:


That’s the version number, that you can compare to the “versionNumber” property from the object. If they’re the same, you’re good. If not, your AD isn’t in sync.

In the “MACHINE” Folder are all the Computer Policy settings, and in the “User” folder are all the User Policy settings. Since we were talking about the Password Policy, which is affected on the SAM on the server, it’s a MACHINE setting. If you were to poke through, eventually you’d find this file:

\\domain\sysvol\domain\\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf

with this data:

[Registry Settings]

And there’s your password policy, via LDAP and SMB only.

For a bit of additional background, when a computer processes this data, in this order, it will actually only apply CSEs from the gPCMachineExtensionNames that the computer recognizes and has DLLs (or whatever code, if it’s non-Microsoft vendor CSE) that can apply the CSE. This makes it technically safe to put multiple GPOs for multiple Operating sytsems on the same OU structure, knowing that the client computer won’t even bother downloading the files for un-recognized CSEs.

Now, that’s a lot of stuff to type into ldp.exe, how can we make a report on this a bit easier? Well, PowerShell could do it, but one of the products I work on is PowerBroker Open https://github.com/BeyondTrust/pbis-open and https://www.beyondtrust.com/products/powerbroker-identity-services-open/ which includes a CLI for browing ldap called “adtool”. With a bit of bash, we can list out all the group policy objects by name attached to a single OU:

$ cat report-gpos-by-ou.sh
GP=`adtool -a lookup-object --dn "$@" --attr gPLink`;
GPO=`echo $GP | sed -e 's/\[LDAP:\/\///g' -e 's/;[[:digit:]]\]/ /g'`
if [ -n "$GPO" ]; then
echo "";
echo "$OU";
for P in $GPO; do
G=`adtool -a lookup-object --dn "$P" --attr displayName`;
grep -q "$G" /tmp/gpos.txt;
if [ $? -ne 0 ]; then
echo $G >> /tmp/gpos.txt;
echo "$G";
$ ./report-gpos-by-ou.sh "OU=Company,DC=domain,DC=com"
PBUL Basics

Joe and Jorge posted these back in 2005 and 2006, but they’re impossible for me to find in Google lately, possibly because of age:


In order to move an object in DS, you need the following three permissions:
1) DELETE_CHILD on the source container or DELETE on the object being moved
2) WRITE_PROP on the object being moved for two properties: RDN (name) and
CN (or whatever happens to be the rdn attribute for this class, i.e. ou for
org units).
3) CREATE_CHILD on the destination container.

Dmitri Gavrilov
SDE, Active Directory Core
Use of included script samples are subject to the terms specified at

But, what, specifically does that mean?

  1. To provide these rights, after delegating control for the Creation and Deletion of the object (Computer/User/etc.), open ADSIEDIT.MSC and navigate to the OU in question.
  2. Right-click the OU and choose “Properties”
  3. Click on the “Security” tab.
  4. Click the “Advanced” button.
  5. Click the “Add” button to add a new security right.
  6. Enter the group you want to delegate the control to and click “OK”
  7. Choose the “Properties” tab.
  8. In the pulldown, choose “Descendent Computer Objects”
  9. Grant:
  1. Read and Write canonicalName
  2. Read and Write name
  3. Read and Write Name

Many are the times we’ve run into DNS configuration problems with Microsoft AD.  After being asked for advice a few more times than normal this year, I’ve pulled together several emails for this list of “Troubleshooting Microsoft AD-integrated DNS” highlights below.  We’ll first cover the generic topics of checking the configuration of your server configuration,  then the configuration of the zones themselves. For each topic, we’ll do a checklist followed by an explanation.

Server configuration:


  1. Is the server (Windows 2003 or higher) pointing to itself for primary DNS in the network configuration?
  2. If a standalone DC: Does the server have *no* secondary DNS in the network configuration?
  3. If there are multiple DCs: Does the server list only other DCs in the secondary DNS server list in the advanced network configuration?
  4. Does the server have proper forwarders in the DNS server configuration (to the parent domain or to the ISP, but not both)?
  5. In a command prompt, run the following:
    ipconfig /registerdns
    net stop netlogon
    net start netlogon
  6. Read DNS and System logs to make sure there are no issues being reported.
  7. wait 20 minutes


One of the major problems we run into is that customers will put the ISP DNS servers in the network configuration on the DC, not in the DNS Forwarders list in the DNS Server configuration.  The DC *is* a DNS server.  It needs to talk to itself, so that it can register crucial DNS settings in its own database.  If its own database can’t find the information requested (such as www.google.com), then the DNS Server service is responsible for looking that data up, and then caching it so that it’s readily available for other clients, too.  This misconfiguration also has the problem of generating DDNS update requests back to the ISP DNS servers, which are ignored at best, and a security leak at worst (like for military/government installations).

I like to tell my Unix customers “the first rule of administering Active Directory is to go get another cup of coffee.” This forces them to take their hands off the keyboard and wait for cross-site replication (hopefully) before making another change.  It’s a good reminder for the seasoned Windows admins, as well.

Zone Configuration

Reverse Lookup Zones

We’ll cover reverse lookup zones before forward lookup zones, for two reasons: 1) customers screw up reverse lookup configuration much more often than forward lookup configuration ; 2) no SRV records in Reverse zones (normally).


If you have non-Microsoft DNS servers or multiple AD domains in your environment

  1. Does the server have reverse DNS zones defined?
  2. Does any *other* server (in the DNS Forwarders configuration list) have the same reverse DNS zone defined?
  3. Do the defined reverse zones allow “unsecured dynamic updates”?
  4. Are all IP subnets in your network defined as reverse DNS zones on the primary DNS servers (the last forwarders in the network before the ISP)?
  5. Do you have aging and scavenging turned on in the server settings?  If so (you should), do you have all clients automatically renewing their records (Windows clients will by default)?

If you only have a single AD domain, or no non-Microsoft DNS servers

  1. Does the server have reverse DNS zones defined for all IP subnets (including IPv6) in your network?
  2. Do those reverse DNS zones allow dynamic updates?
  3. Is aging of old records enabled with sane no-refresh and refresh values  in the reverse zones?


Each DNS Zone is a database.  There can only be one authoritative owner of the database, defined by the SOA record on the Zone.  Any other DNS servers get their information from this SOA, either by normal queries, or by zone transfer (AD replication does a kind of zone transfer).  If two servers are set up with the same zone (create 0.168.192.in-addr.arpa reverse DNS zone in dns1.contoso.com and ns1.worldwidetoys.com, for example), then there is no mechanism to transfer the information between those two servers.

For example: any individual client will only talk to the DNS server it’s configured to talk to (client1.contoso.com gets its DNS info from dns1.contoso.com and winxp1.worldwidetoys.com gets its information from ns1.worldwidetoys.com). Each client will also send updates only to its own DNS server.  This means that client1.contoso.com will register its IP with dns1.contoso.com, and winxp1.worldwidetoys.com will register its IP with ns1.worldwidetoys.com.  These two records will never be synched between dns1.contoso.com and ns1.worldwidetoys.com.  Therefore, when winxp1.worldwidetoys.com asks ns1.worldwidetoys.com “who has”, ns1.worldwidetoys.com will answer “nobody!”.

The DNS admin must fix this problem by manually registering all of the records from ns1.worldwidetoys.com in the zone stored in dns1.contoso.com, deleting the 0.168.192.in-addr.arpa zone from ns1.worldwidetoys.com, and then setting up a forwarder or conditional forwarder to dns1.contoso.com.  Now, that same query results in ns1.worldwidetoys.com looking in its own database, finding no answer, and reaching out to its forwarders to ask, “who has”.  Similarly, when winxp1.worldwidetoys.com goes to register, it is directed, via the SOA record, to send that registration to dns1.contoso.com.  This is why reverse zones often need to allow unsecured dynamic updates.

Forward Lookup Zones

I have a customer who needs this much data now – I’ll follow up with the Forward Lookup zones in a separate post later this week.

Next Page »