TL;DR: Point the server at the DC for DNS, make sure the clock isn't more than 5 minutes off, then run one command:
Add-Computer -DomainName corp.local -Credential corp\domainadmin -OUPath "OU=Servers,DC=corp,DC=local" -Restart
That's the whole post if you already know what you're doing. Below is the stuff that actually goes wrong.
Prereqs (the part everyone skips)
Domain-join fails for three reasons, in this order: DNS, time, and network. Fix those first or you'll waste an hour reading event logs.
DNS
The server must use the domain controller as its primary DNS server. Not Google DNS. Not Cloudflare. The DC. If you can't resolve corp.local or the DC's FQDN from the server, you can't join.
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses 10.0.0.10
Resolve-DnsName corp.local
nslookup -type=SRV _ldap._tcp.corp.local
If _ldap._tcp.corp.local doesn't return SRV records pointing at your DC, nothing else matters. Fix DNS first.
Time
Kerberos refuses tickets if the clock skew is over 5 minutes. Fresh VMs often boot with garbage time.
w32tm /query /status
w32tm /resync
If the server is a VM, double-check that hypervisor time sync is actually working. I've been bitten by VMs reporting the host time as UTC when the host was in local time.
Network
The server needs to reach the DC on a handful of ports: 53 (DNS), 88 (Kerberos), 389 (LDAP), 445 (SMB), 464 (kpasswd), plus the high RPC range. Quick test:
Test-NetConnection dc01.corp.local -Port 389
Test-NetConnection dc01.corp.local -Port 445
The join command
With prereqs green, the join is one line. Use -Credential so you get prompted for the password instead of putting it on disk:
Add-Computer -DomainName corp.local -Credential corp\domainadmin -OUPath "OU=Servers,DC=corp,DC=local" -NewName "web05" -Restart
Flags that matter:
-DomainName— the domain name, not the DC hostname-Credential— a user with the "Add workstations to domain" right, or Domain Admin-OUPath— full distinguished name. Skip this and the computer object lands inCN=Computers, which nobody wants-NewName— rename during join, saves a reboot-Restart— required to activate the join, and you can't use the box until you reboot anyway
If the command returns without an error, you're joined. The reboot finishes the work.
Verify it worked
After the reboot, log in with a domain account and run:
systeminfo | findstr /B "Domain"
(Get-WmiObject Win32_ComputerSystem).PartOfDomain
gpresult /r /scope:computer
klist
systeminfo should print your domain, not WORKGROUP. gpresult shows applied GPOs — if it prints nothing, either the OU has no GPOs linked or AD replication hasn't caught up. klist lists Kerberos tickets and proves the machine account is authenticating properly.
Leave the domain
Same flow in reverse. Don't just delete the computer object in AD and wonder why things break.
Remove-Computer -UnjoinDomainCredential corp\domainadmin -PassThru -Verbose -Restart
This cleans both sides: the local secure channel and the AD computer object. If the server can't reach AD anymore (typical decommissioning scenario), add -Force for a local-only unjoin, then remove the stale AD object by hand.
Gotchas I've actually hit
Duplicate computer object
Joining a server with the same name as a pre-existing AD object fails with a cryptic access-denied error. Delete the old object, or pick a different -NewName.
Broken secure channel
If a server sits off the network for months, its machine password desyncs. Symptom: domain users can't log in even though the server is still "joined". Fix:
Test-ComputerSecureChannel -Verbose
Test-ComputerSecureChannel -Repair -Credential corp\domainadmin
Wrong OU after join
Forgot -OUPath? The object is sitting in CN=Computers. Move it in ADUC or via PowerShell:
Get-ADComputer web05 | Move-ADObject -TargetPath "OU=Servers,DC=corp,DC=local"
Then gpupdate /force on the server to pull GPOs from the new OU.
DNS registration didn't happen
Forward record works, reverse doesn't, or vice versa. Force it:
ipconfig /registerdns
If the DNS zone doesn't allow dynamic updates you'll need to create the record by hand on the DNS server.
Name longer than 15 characters
NetBIOS still matters. Names over 15 characters get truncated and cause duplicate-name conflicts. Just pick shorter names — your future self will thank you.
Next steps
Once the server is on the domain, the rest of the setup is standard. If you haven't done baseline hardening yet, do that first: Windows Server initial setup checklist. And if you want RDP from a domain account instead of local admin, see Enable RDP on Windows Server.
Domain-join is the kind of task that's one command when everything's right and a half-day debugging session when something's wrong. Fix DNS, fix time, then run the command.