Bare Minimum Required to Promote a Domain Controller Into a Domain


This is something I meant to blog about months ago, but for some reason I let it slip my mind. It just came up again in a conversation I had yesterday, and I couldn't believe I forgot to post it here. (It also may or may not be similar to a test question that someone might encounter if he or she were taking some Microsoft-centric certification tests.)

It started when someone on ServerFault asked the question, "Do you need a GC online to DCPROMO?"

Well the short answer to that question is that no, you don't need a global catalog online (or reachable) from the computer you are trying to simply promote into a domain controller. But that got me thinking, I'd like to go a step farther and see for myself what the bare minimum requirements for promoting a computer to a domain controller in an existing domain, especially concerning the accessibility of certain FSMO roles from the new DC. I don't care about anything else right now (such as how useful this DC might be after it's promoted) except for just successfully completing the DCPromo process.

On one hand, this might seem like just a silly theoretical exercise, but on the other hand, you just might want to have this knowledge if you ever work in a large enterprise environment where your network is not fully routed, and all DCs are not fully meshed. You might need to create a domain controller in a segment of the network where it has network connectivity to some other DCs, but not all of them.

Well I have a fine lab handy, so let's get this show on the road.

  1. Create three computers.
  2. Make two of them DCs for the same single-domain forest (of the 2008+ variety.)
  3. Make only one of them a global catalog.
  4. Leave all FSMOs on the first domain controller, for now.

So when you promote a writable domain controller, you need two things: another writable domain controller online from which to replicate the directory, and your first RID pool allocation directly from the RID pool FSMO role holder. When you promote an RODC, you don't even need the RIDs, since RODCs don't create objects or outbound replicate.  If the computer cannot reach the RID pool master, as in direct RPC connectivity, DCPROMO will give you this message:

You will not be able to install a writable replica domain controller at this time because the RID master is offline.

But you can still create an RODC, as long as the domain controller with whom you can communicate is not also an RODC - it has to be a RWDC.

So the final steps to prove this theory are:

  1. Transfer only the RID master to the second domain controller.
  2. Power down the first domain controller.

At this point, only the RID pool master is online, and no global catalog is online. Now run DCPromo on your third computer. Can you successfully promote the new domain controller as a RWDC?

Yes you can.

Now, you'll encounter some other problems down the road, such as the new DC not being able to process password changes because it cannot contact the PDCe, but you've successfully added a new domain controller to the domain nonetheless.

Locating Active Directory Site Options with Powershell

So as you may know, I hang out on ServerFault a lot.  And last night, one of my favorite ServerFault members, Mark Marra, asked an interesting question there that sent me on a long journey of research in order to answer it.

(Mark's got his own IT blog by the way which you should totally check out. He's a world class Active Directory guy, the kind of guy that doesn't usually ask easy questions, so I'm proud of myself whenever I'm able to answer one of his questions.)

The link to the actual question and answer on ServerFault is here, most of which I am about to repeat in this post, but I'll see if I can embellish a little here on this blog.


How can I use PowerShell to find AD site options like +IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED in PowerShell? I've been playing around with the following command, but can't get it to spit out anything useful.

Get-ADObject -Filter 'objectClass -eq "site"' `
-Searchbase (Get-ADRootDSE).ConfigurationNamingContext `
-Properties options


The above command is very close, but off by just a hair. The short and simple answer is that the above command is searching for the options attribute of the Site object itself, when we actually need to be looking at the NTDS Site Settings object belonging to that site. And furthermore, there is no Powershell-Friendly way of getting this data as of yet, i.e., there is no simple Get-ADSiteOptions Cmdlet... but we may just have the cure for that if you can get through the rest of this blog post. We just need to figure out where exactly to find the data, and then we can use Powershell to grab it, wherever it may be hiding.

Take the following two commands: 

repadmin commands

Repadmin /options <DC> gives us the DSA options that are specific to the domain controller being queried, such as whether the domain controller is a global catalog or not, and the Repadmin /siteoptions <DC> command gives us the options applied to the Active Directory Site to which the domain controller being queried belongs (or you can specify that you want to know the settings for another site with the /site:California parameter. Full repadmin syntax here, or just use the /experthelp parameter.)

Note that these settings are relatively advanced settings in AD, so you may not work with them on a regular basis. Sites by default have no options defined, so if you find yourself working with these options, chances are you have a more complex AD replication structure on your hands than the average Joe. If all you have are a few sites that are fully bridged/meshed, all with plenty of bandwidth, then you probably have no need to modify these settings. More importantly, if you modify any of these settings, it's very important that you document your changes, so that future administrators will know what you've done to the domain.

So where does repadmin.exe get this information?

The settings for individual domain controllers come from here: 

ADSI Edit 1

That is, the options attribute of the NTDS Settings object for each domain controller.

The site options come from the NTDS Site Settings object for each site. (Not the site object itself: ) 

Site Options

Here is the basic MSDN documentation on the Options attribute:

A bitfield, where the meaning of the bits varies from objectClass to objectClass. Can occur on Inter-Site-Transport, NTDS-Connection, NTDS-DSA, NTDS-Site-Settings, and Site-Link objects.

Now we know exactly which bits repadmin.exe works on when we issue a command such as repadmin /options DC01 +IS_GC or repadmin /siteoptions DC01 /site:Arlington +IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED. Fortunately, repadmin.exe as well as the ADSI Edit MMC snap-in both have bitmask translators in their code, so that they can show us the friendly names of the value of the options attribute, instead of just a 32-bit hexadecimal code.

If we want to roll our own Get-ADSiteOptions Cmdlet, we'll have to build our own bitmask translator too.

Fortunately the bitfields for both the DC settings and the Site settings are documented, here and here. Here is an excerpt for the Site options bitmask: 

Site Options Bitmask

So now we have enough information to start working on our Get-ADSiteOptions Cmdlet. Let's start with this basic snippet of Powershell:

ForEach($Site In (Get-ADObject -Filter 'objectClass -eq "site"' -Searchbase (Get-ADRootDSE).ConfigurationNamingContext)) 
    Get-ADObject "CN=NTDS Site Settings,$($Site.DistinguishedName)" -Properties Options 

What that does is get the DistinguishedName of every Site in the forest, iterate through them and get the attributes of each Site's NTDS Site Settings object. If the options attribute has not been set for a Site (which remember, is the default,) then it will not be shown. Only Sites with modified options will show as having an options attribute at all. Furthermore, in Powershell, it will come out looking like this:

Powershell site options

It's in decimal. 16 in decimal is 0x10 in hex, which we now know means IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED.

So, without further ado, let's see if we can build our own Get-ADSiteOptions Cmdlet:

#Require -Version 3
#Require -Module ActiveDirectory
Function Get-ADSiteOptions
    This Cmdlet gets Active Directory Site Options.
    This Cmdlet gets Active Directory Site Options.
    We can fill out the rest of this comment-based help later.
    Written by Ryan Ries, October 2013.
        Set-StrictMode -Version Latest

        # This enum comes from NtDsAPI.h in the Windows SDK.
        # Also thanks to Jason Scott for pointing it out to me.
        Add-Type -TypeDefinition @" 
                                   public enum nTDSSiteSettingsFlags {
                                   NTDSSETTINGS_OPT_IS_AUTO_TOPOLOGY_DISABLED            = 0x00000001,
                                   NTDSSETTINGS_OPT_IS_TOPL_CLEANUP_DISABLED             = 0x00000002,
                                   NTDSSETTINGS_OPT_IS_TOPL_MIN_HOPS_DISABLED            = 0x00000004,
                                   NTDSSETTINGS_OPT_IS_TOPL_DETECT_STALE_DISABLED        = 0x00000008,
                                   NTDSSETTINGS_OPT_IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED = 0x00000010,
                                   NTDSSETTINGS_OPT_IS_GROUP_CACHING_ENABLED             = 0x00000020,
                                   NTDSSETTINGS_OPT_FORCE_KCC_WHISTLER_BEHAVIOR          = 0x00000040,
                                   NTDSSETTINGS_OPT_FORCE_KCC_W2K_ELECTION               = 0x00000080,
                                   NTDSSETTINGS_OPT_IS_RAND_BH_SELECTION_DISABLED        = 0x00000100,
                                   NTDSSETTINGS_OPT_IS_SCHEDULE_HASHING_ENABLED          = 0x00000200,
                                   NTDSSETTINGS_OPT_IS_REDUNDANT_SERVER_TOPOLOGY_ENABLED = 0x00000400  }
        ForEach($Site In (Get-ADObject -Filter 'objectClass -eq "site"' -Searchbase (Get-ADRootDSE).ConfigurationNamingContext)) 
            $SiteSettings = Get-ADObject "CN=NTDS Site Settings,$($Site.DistinguishedName)" -Properties Options
            If(!$SiteSettings.PSObject.Properties.Match('Options').Count -OR $SiteSettings.Options -EQ 0)
                # I went with '(none)' here to give it a more classic repadmin.exe feel.
                # You could also go with $Null, or omit the property altogether for a more modern, Powershell feel.
                [PSCustomObject]@{SiteName=$Site.Name; DistinguishedName=$Site.DistinguishedName; SiteOptions='(none)'} 
                [PSCustomObject]@{SiteName=$Site.Name; DistinguishedName=$Site.DistinguishedName; SiteOptions=[Enum]::Parse('nTDSSiteSettingsFlags', $SiteSettings.Options)}

And finally, a screenshot of the fruits of our labor - what we set out to do, which was to view AD Site options in Powershell:

SRV Record for NTP? In *MY* Active Directory?

Howdy fellow IT goons. I am probably not going to talk about Powershell today... but no promises.

Good ole' RFC 2782, the great fireside reading that it is, spells out the concept behind DNS SRV records and using them to locate services within a domain. The Microsoft article "How DNS Support for Active Directory Works", which is also more than just a heart-warming story but is also required reading if you're a Windows admin, mentions that Active Directory is pretty much, more or less, compliant with the aforementioned RFC:

"When a domain controller is added to a forest, a DNS zone hosted on a DNS server is updated with the Locator DNS resource records for that domain controller. For this reason, the DNS zone must allow dynamic updates (RFC 2136), and the DNS server hosting that zone must support the SRV resource records (RFC 2782) to advertise the Active Directory directory service."

It goes _<service>._<protocol>, so if I wanted to locate LDAP services in a domain I'd issue a DNS query for, or if I wanted to find Kerberos service I'd do

But no one ever said that Active Directory uses every type of SRV there is by default. Not even close. Take NTP, Network Time Protocol, as an example.  Given the above logic I might issue a DNS query for, searching for NTP time service in that domain. Assuming I'm in a Microsoft Active Directory domain, odds are that I will not find it.

An SRV record is not created by default for the NTP service.  This is because Windows clients connecting to an AD domain already know to use domain controllers for time service in an AD domain, and the domain controllers already have their own SRV records, so separate NTP records would be redundant and unnecessary.

In fact, the only Microsoft-centric scenario I know of where the SRV record comes in to play is smart phones and devices using Microsoft Office Communicator or Lync - and even then it's optional since they'll fail back to if the SRV record is not found. You can find those examples here and here. If you know of any other situations where Windows-based applications use such an SRV record, please let me know.

But maybe you have a heterogeneous IT environment and you may want to add these records for yourself in order to support Unix/Linux clients and their applications that are making such DNS queries.  It's very easy:

  • Open the DNS Manager console/MMC snap-in.
  • Drill down into your Forward Lookup Zones.
  • Locate the _udp subdomain, since the NTP service operates over the UDP protocol.
  • You should see a list of _kerberos and _kpasswd SRV records there already, that represent the domain controllers currently in your domain.
  • Right-click in that white space and choose "Other New Records..."
  • Select "Service Location (SRV)" from the list.
  • Configure your new record like this screenshot:

SRV record

Mind the underscores, and notice the trailing period at the end of your domain name. You will probably want to add one of these for each domain controller you have, and you can play around with the weights and priorities however you like. NTP uses port 123 of course. There will be some options in the drop down list that they give you as examples. Don't confuse it with _nntp, unless you host the News Network Transfer service in your domain too.

Tell Me Which Active Directory Security Groups Are Not Applying Inheritable Permissions

I encounter many Active Directory forests that were built and maintained for years by other organizations, and then through mergers or acquisitions or business reorgs, I need to help bring them into the fold with the rest of my portfolio of AD forests.

AD permissions can be a deep rabbit hole, especially when sitting down to a new directory sight unseen. Administrators make subtle changes to AD objects over the years and a lot of entropy happens.  Entropy that's not always easy to see or keep track of.

In this particular instance, we had an issue where a delegation of control was not working correctly and/or consistently.  It was the common IT task of delegating the ability to reset passwords and unlock accounts (but nothing else) to a special "help desk" sort of security group. It was allowing members of the "help desk" group to reset the passwords of certain users, but not others.  None of them were administrative users, or members of the Domain Admins group, the Account Operators group, etc. etc.

Turns out, the problem was that some security groups were not including inheritable permissions from the domain root object, so users who were members of these certain groups were immune to the effects of the delegation. 

Advanced Permissions

At first I actually thought to go and click on every single security group in the domain, checking on whether they were applying inheritable permissions or not.  Then a few seconds I realized, "Don't be an idiot Ryan. The GUI is not your friend! Don't succumb to its siren song!"

After glancing at this excellent SDDL reference here for about 5 minutes, I whipped this up:

Foreach($_ In Get-ADGroup -Filter *)
	[bool]$Inherits = $($(Get-ADGroup $_ -Properties *).nTSecurityDescriptor.Sddl.Contains('OI'))
	If($Inherits -EQ $False)

 And presto - a list of all security groups in the domain that are not applying inheritable permission from their parents.

PS - I admit, I still have to use a cheat sheet when reading SDDL.  :P

Finding Locked Out Domain Accounts, Or At Least, How Not To

I hadn't posted in a little while, so I thought I'd do a two-fer today.

You might see some advice on the internet about using the userAccountControl attribute to identify locked out domain accounts.  More specifically, the following LDAP filter:


The =16 part should mean "locked out", per the attribute's documentation, keeping in mind that 0x10 in hex is 16 in decimal.

DON'T USE IT.  It doesn't work. I don't think it has ever worked. Apparently it was just an idea that some person on the AD design team had that never got implemented. If anyone has any history on this bit, and if it has ever worked in the past, I would love to hear about it. All I know is that it does not work now.

You can easily verify for yourself that it doesn't work with Powershell:

Get-ADUser -LDAPFilter "(&(objectCategory=User)(userAccountControl:1.2.840.113556.1.4.803:=16))"

You'll probably get 0, or some other very inaccurate value. (Other userAccountControl flags however do definitely work and can be used reliably. Just not this one.)

Here is another LDAP filter you will often see on the web for finding locked out accounts:


DON'T USE THAT EITHER. That will return too many results.  The reason why is that lockoutTime is not reset until the next time that person successfully logs in. So if an account is locked out, then their lockoutTime attribute gets set, then if the domain lockout duration expires, the account is no longer technically locked out, but lockoutTime remains populated until the next time that user logs in. Now if you're thinking that we should filter this list by only the users who have a lockoutTime that is less than [domain lockout duration] minutes in the past, then you're on the right track. Those would be the users who are still really locked out.

When I type  Search-ADAccount -LockedOut , however, I am given what seems to be an accurate number of users that are currently locked out. I should point out that if working in a large AD environment, I think it's best to point directly to your PDC-emulator whenever possible, because your PDC-emulator will always have the most up-to-date information about account lockouts. From a Microsoft article about urgent replication:

... account lockout is urgently replicated to the primary domain controller (PDC) emulator role owner and is then urgently replicated to the following:

• Domain controllers in the same domain that are located in the same site as the PDC emulator.

• Domain controllers in the same domain that are located in the same site as the domain controller that handled the account lockout.

• Domain controllers in the same domain that are located in sites that have been configured to allow change notification between sites (and, therefore, urgent replication) with the site that contains the PDC emulator or with the site where the account lockout was handled. These sites include any site that is included in the same site link as the site that contains the PDC emulator or in the same site link as the site that contains the domain controller that handled the account lockout.

In addition, when authentication fails at a domain controller other than the PDC emulator, the authentication is retried at the PDC emulator. For this reason, the PDC emulator locks the account before the domain controller that handled the failed-password attempt if the bad-password-attempt threshold is reached.

If you follow my earlier instructions on how to peek inside the Search-ADAccount cmdlet itself, you'll see that Microsoft themselves is keying on the Account Lockout Time to perform this search:

Finally, I can reproduce the same behavior of  Search-ADAccount -LockedOut  with the following bit of Powershell, given that I know my domain's account lockout duration:

Get-ADUser -LDAPFilter "(&(objectCategory=Person)(objectClass=User)(lockoutTime>=1))" -Properties LockoutTime | 
Select Name, @{n="LockoutTime";e={[DateTime]::FromFileTime($_.LockoutTime)}} | 
Sort LockoutTime -Descending | ? { $_.LockoutTime -gt (Get-Date).AddMinutes($AccountLockoutDuration * -1) }

That gives the exact same results as  Search-ADAccount -LockedOut .