Domain join using a Read-Only Domain Controller

2 minute read

Joining computers to a domain using only a read-only domain controller is a bit of a complicated process. This usually comes up because you have a server in a DMZ or behind a perimter firewall with no access to a RWDC (read-write domain controller).

If you just follow the instructions that exist in Microsoft documentation you are probably going to run into weird issues down the road. After many failed attempts over the years I have finally found a process that lets you properly join a domain without ever having network connectivity to a writeable domain controller. Here it is!

Updated 2022-01-18: Changes for Server 2019 compatibility. Thanks to Markus Hampe for pointing out the issue and helping troubleshoot.

Pre-populating

The first step is pretty obvious. We’re going to have to create a computer account in our domain with a known password that we can provide to the computer to join with.

$ComputerPassword = 'Password!'

New-ADComputer -Name 'NewComputer' -AccountPassword ($ComputerPassword | ConvertTo-SecureString -AsPlainText -Force)

Once that’s done we’ll want to add it to the security group that allows its account to be replicated to our Read-Only Domain Controllers. Best practice is to create a security group for each physical site or RODC and add those, but for this example I’m just going to use the default group.

$ComputerName = 'NewComputer'

Get-ADGroup "Allowed RODC Password Replication Group" | Add-ADGroupMember -Members (Get-ADComputer $ComputerName)

This next part is fairly critical and not super obvious. If your computer only has access to a Read-Only Domain Controller it won’t be able to update its Service Principal Names after joining. Without these in place Kerberos is going to fail and you’re going to run into a lot of weird issues. To fix these problems you can prepopulate the required SPN entries manually.

$ComputerName = 'NewComputer'
$Domain = 'example.net'

$SPN = @{
    Replace = @(
        "TERMSRV/$ComputerName.$Domain",
        "WSMAN/$ComputerName.$Domain",
        "RestrictedKrbHost/$ComputerName.$Domain",
        "HOST/$ComputerName.$Domain",
        "TERMSRV/$ComputerName",
        "WSMAN/$ComputerName",
        "RestrictedKrbHost/$ComputerName",
        "HOST/$ComputerName"
    )
}

Get-ADComputer $ComputerName | Set-ADComputer -ServicePrincipalNames $SPN

Likewise your computer is probably not going to be able to register its own DNS records without access to a writeable Domain Controller so we’ll create that record manually.

$ComputerName = 'NewComputer'
$Domain = 'example.net'
$ComputerIP = '192.168.100.200'

Add-DnsServerResourceRecord -ZoneName $Domain -A -CreatePtr -IPv4Address $ComputerIP -Name $ComputerName

Joining the domain

The final step is to actually run the join on the computer. In my experience trying to join to a RODC only works if the computer already has the appropriate name before starting the join. Before we do anything we’ll need to rename the computer and restart.

Rename-Computer -NewName 'NewComputer' -Restart

Once that’s done run the PowerShell commands to join to the specific RODC using a pre-populated password.

$Domain = 'example.net'
$Rodc = 'rodc01.example.net'

$ComputerPassword = 'Password!'
$ComputerCredentials = New-Object pscredential -ArgumentList ([PSCustomObject]@{
    UserName = $null
    Password = ($ComputerPassword | ConvertTo-SecureString -AsPlainText -Force)[0]
})

$Options = 'UnsecuredJoin,PasswordPass,JoinReadOnly'

Add-Computer -Domain $Domain -Options $Options -Credential $ComputerCredentials -Server $Rodc -Restart

Voila! If everything went well you should now be able to log in to this computer using domain credentials and access domain resources. In my experience it may take one or two reboots before Group Policies start applying properly.

Future Concerns

  • You’ll probably want some way of automating computer password rotation since the computer can no longer do it automatically.