With the advent of Read Only Domain Controllers (RODC) remote offices no longer have to present a risk for your Active Directory (AD) enterprise secrets. RODC's by default do not cache ANY user or computer passwords. This can present a problem if there is a loss of connectivity between the remote site's RODC and a Read Write Domain Controller (RWDC), since without caching since neither a user or computer will be able to authenticate. You can however specifiy that their passwords be cached either by including a group or specific user in the Password Replication Policy on the RODC at the remote site. Access to this policy is gained by opening up the RODC computer object and selecting the "Password Replication Policy" tab.
It is realtively simple to add and remove user and computer objects, simply click on the "Add" or "Remove" button and modify the membership. Problem is this can be very dynamic, users and computers are consisting coming and going and management of this can become extremely tedious. Even if you are using group membership, this still has to be maintained.
I have found the use of Powershell was the piece I needed to resolve the problem. It was important though that I am able to determine where a user or computer exists. There is no software out there that can determine where an object exists without some clear definition. Fortunately for me I have a nightly syncronization program between HR and AD that keeps all my users objects address accurate. Now I just need a way to determine my machine object location.
After doing some thinking I quickly realized that I already know which machines reside at any one site by the subnet definitions within AD Sites and Services.
Now that I had things clear in my process, I had to find a way to gather all the information. I decided that Powershell would be the best path to go, since I had two defined process.
Script 1
- Determine the ip subnets within the site I wanted to build my group for
- Query for all DNS records within the doman the RODC belongs to
- Query AD to determine which of the DNS hosts are members of the AD domain
- Update the computer objects location with a value that defines this sites lcoation
Script 2
- Since the users and computers move around so much clear out the current group membership
- Read all computer and user objects and those that have the specific location defined add to the Site Group
I have posted both scripts below, you will note that the users "City" attribute is not touched since this should be a managed attribute by your HR department. Both scripts can be run on within a single task, just make sure that the Dynamic Security group sub-task is run second.
Note: Script 2 will generate churn for DC replication. This rebuilds the group everytime it is run, so it will cause the group and its membership to be rereplicated wether or not there were any changes. Not a big deal for small to midsized shops without expensive links or significant numbers of DC's, but if you have 100,000's of objects or 100's of dc's this is not efficient. I hope to rewrite this to manage delta's only.
Script 1
import-module activeDirectory # # Script - UpdateSiteLocation.ps1 # Author - Paul Bergson # Date Written - 09/22/2010 # Description - Script will populate the location field of all computer accounts that reside in a specific site # When used in association with the Powershell script to dynamically populate the members # of a security group of all computer and user accounts with the same location. This group can # be part of the Password Replication Policy (PRP) for an RODC in the defined site. $ErrorActionPreference = "SilentlyContinue" # Get the subnets associated with Boswell and place them in the array $ipSubNetAry $ipSubNetAry = @() # Create an empty array $UpdateSite = "Site-Timbuktu" # Define the site that you want to build the array for $locationName = "Timbuktu" # Define the value you want populated in the object's "Location" attribute $forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest() $sites = $forest.Sites Foreach ($site in $sites) { $MPSubNets = $site.Subnets ForEach($MPSubNet in $MPSubNets) { If($MPSubNet.site.name -eq $UpdateSite) { $ipSubNetAry = $ipSubNetAry + $MPSubNet.Name.Substring(0,($MPSubNet.Name.Length-5)) } } } # Go get the host records from the sites in the array of the subnets $dnsRecords = gwmi -computername computer.domain.com -namespace root\microsoftDNS -Query ('select OwnerName, IPAddress from MicrosoftDNS_AType where DomainName = "domain.com"') # Now that all host records have been captured look for matching subnet's and see if they reside in Active Directory ForEach ($hostRecord in $dnsRecords) {$ServerIpAddress = $HostRecord.IpAddress ForEach($ipSubNet in $ipSubNetAry) { $FoundMatch = $ServerIpAddress.StartsWith($IpSubNet) if ($FoundMatch) { $FQDN = $hostRecord.OwnerName $Sam = $FQDN.Split(".") # Get the AD computer object to see if it needs to be updated # Sam[0] holds the host name from the fqdn when the array is formed $ComputerObj = $Null # Clear prior to call otherwise old value stays in object variable $ComputerObj = get-adcomputer -identity $Sam[0] -properties Location if ($error[0]) # Don't process if host not available { ForEach($NewComputer in $ComputerObj) { if ($NewComputer.Location -ne $locationName) {write-output $NewComputer.samAccountName # Not really needed other than if run locally write-output $FoundIpAddress # it will provide feedback on the machines updated # Next line does the actual update. It should be commented out during any testing Set-ADComputer $NewComputer.samAccountName -Location $locationName } } } } } }
Script 2
# Program buildDynamicSecurityGroup # Author Paul Bergson # Date Written September 20, 2010 # Description This will recreate the membership list of the AD security group "DynamicSecurityGroup". This group is used to manage # whose passwords are cached on the RODC in Timbuktu # By using the attribute City on USers and Location on Computers this is a Dynamic Security Group # This script is run nightly # Get the ad cmdlets imported import-module ActiveDirectory $siteName = "Timbuktu" # Clear all current members get-adgroupmember DynamicSecurityGroup | %{remove-adgroupmember DynamicSecurityGroup $_.SamAccountName -Confirm:$false} # Add all users and computers to the $SiteName global security group get-aduser -filter{city -like $siteName} | %{Add-ADGroupMember DynamicSecurityGroup $_.SamAccountName} get-adcomputer -filter{location -like $siteName} | %{Add-ADGroupMember DynamicSecurityGroup $_.SamAccountName}