DNS Server Enforcement across an AD Forest
Support in Active Directory for centrally enforcing client DNS settings via Group Policy Objects is at best patchy. Many of the settings work only with specific (and often legacy) versions of Windows; the “DNS Server” is one such setting. It is supported only on Windows XP Professional meaning no support is available for Windows Server 2000, 2003, 2008, Windows Vista or Windows 7. In most environments workstations receive their DNS Server configuration settings automatically via DHCP. These settings can be changed by configuring either the DHCP server global or scope settings, (note: TCP/IP settings configured locally on a computer override the settings provided by DHCP). While commonly servers have their TCP/IP settings statically configured.
One possibility as to why Microsoft has not pursued widening the DNS Server GPO setting support for newer releases of Windows is that network configurations particularly on servers are often more complex, for example multiple network interface cards (NICs) or multiple VLANs trunked into a single NIC. In such scenarios it would be difficult to apply settings in a GPO to a specific targeted NIC on a server.
When new DNS servers are implemented with new IP addresses it is necessary to reconfigure computers that have static TCP/IP configurations. This article, although focusing on ongoing enforcement of DNS Server settings can be used as a basis to writing one off scripts to configure Domain member computers.
A way to enforce DNS Client Settings is to create a Computer Startup Script GPO. This is located in the GPO Editor under Computer Configuration\Policies\Windows Settings\Scripts\Startup.
Startup scripts only run when a computer boots and initialises, meaning if settings configured by the script are changed by an Administrator they will only be reset the next time the script runs which will be when the computer is next rebooted.
A consideration when configuring DNS Server settings is the computers location and identifying its local DNS servers, often these differ from AD Site to AD Site. A GPO containing the DNS Server configuration Startup script could be linked to an AD site but of course this would mean potentially one Startup script per AD site which in a large environment would quickly become an unmanageable mess! Most large environments strive for a unified Computer startup script which contains logic to ensure only the code that is intended to run for a specific computer, site or OU is run on the client computer.
Generally it is better to link the GPO containing the Computer Startup script to the base OU containing the Computer objects. If the GPO is linked to an OU whose directory tree contains computers with DHCP as well as statically configured NICS, code must be present in the script to ignore and not enforce DNS Server settings on any DHCP configured NICs (this is not covered in this article). To ensure the correct DNS server settings are enforced by the script, it must identify the AD site the computer belongs to. - The following vbScript code does this:
strSite = objADSysInfo.SiteName
Set objADSysInfo = Nothing
The vbScript variable strSite contains the AD Site name (as it appears in the AD Sites and Services snap-in) as a string. Next using a Select Case statement an array arrDNSServers can be populated with the correct DNS server settings for each site. A Case Else is implemented to ensure there is a catch-all for any site that is not specifically listed in the script .
Case “site1-intranet”
arrDNSServers = Array(“172.24.16.2″, “172.24.16.3″)
Case “site1-internet”
arrDNSServers = Array(“10.0.18.2″, “10.0.18.3″)
Case “site2″
arrDNSServers = Array(“172.24.17.2″, “172.24.17.3″, “172.24.16.2″)
Case Else
arrDNSServers = Array(“172.24.16.2″, “172.24.16.3″)
End Select
Now we have the configuration the correct NIC (logical or physical) must be identified and the settings applied. This is contained within a function, so first to call the function and pass the array populated in the previous step.
Knowing which adapter to configure is key and there is probably no ideal failsafe approach but here follows two possibilities, this first code block uses the following logic. It configures the DNS Servers for all NICs that have TCP/IP enabled and have a DNS Server List configured (DNSServerSearchOrder). The basis for this is on a multihomed system the bindings will determine which is the primary and which is the secondary, tertiary etc. By default TCP/IP sends packets to the primary NIC unless static routes determine they should pass through another NIC. Therefore the DNS Server List need only be configured on the primary NIC.
Dim objWMIService, colAdapters, objAdapter
Set objWMIService = GetObject(“winmgmts:{impersonationLevel=impersonate}//./root/cimv2″)
Set colAdapters = objWMIService.ExecQuery _
(“SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True”)
For Each objAdapter in colAdapters
If Not IsNull(objAdapter.DNSServerSearchOrder) Then
objAdapter.SetDNSServerSearchOrder(arrDNSServers)
End If
Next
Set colAdapters = Nothing
Set objWMIService = Nothing
wscript.echo “completed”
End Function
An alternate method using the Win32_PingStatus WMI object is to first ping the computer by it’s name, identify the IP Address that responds to the ping request and query Win32_NetworkAdapterConfiguration, from the collection of returned adapters identify the adapter with a matching configured IP Address and apply the DNS Servers list to it, something similar to this:
‘ examples to create site specific values
arrDNSServers = Array(“172.24..16.2″, “172.24.16.3″)
strComputer = getEnvVar(“PROCESS”, “ComputerName”)
strIPAddr = getPingAddress(strComputer)
SetDNSResolverList arrDNSServers, strIPAddr
Function getPingAddress(byRef strComputer)
err.Clear
Set oPingResults = GetObject(“winmgmts:{impersonationLevel=impersonate}//.” &_
”/root/cimv2″).ExecQuery(“SELECT * FROM Win32_PingStatus WHERE Address = ‘” &_
+ strComputer + “‘”)
For Each oPingResult In oPingResults
If oPingResult.StatusCode = 0 Then
getPingAddress = oPingResult.ProtocolAddress
Else
getPingAddress = “noResponse”
End If
Next
If Err.Number <> 0 Then
getPingAddress = “notReachable”
End If
Set oPingResults = Nothing
End Function
Function SetDNSResolverList(ByRef arrDNSServers, ByRef strIPAddr)
Dim objWMIService, colAdapters, objAdapter
Set objWMIService = GetObject(“winmgmts:{impersonationLevel=impersonate}//./root/cimv2″)
Set colAdapters = objWMIService.ExecQuery _
(“SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True”)
For Each objAdapter in colAdapters
For Each strIPAddress in objAdapter.IPAddress
If Not IsNull(strIPAddress = strIPAddr) Then
objAdapter.SetDNSServerSearchOrder(arrDNSServers)
End If
Next
Next
Set colAdapters = Nothing
Set objWMIService = Nothing
End Function
Function getEnvVar(byref strEnvType, byRef strEnvVar) ‘ strEnvType: (User|System|Process)
Dim objWSH, objSystemVars
Set objWSH = CreateObject(“WScript.Shell”)
Set objSystemVars = objWSH.Environment(“PROCESS”)
getEnvVar = objSystemVars(strEnvVar)
Set objWSH = Nothing
Set objSystemVars = Nothing
End Function
I am sure there are other approaches to achieving this, please detail in the comments if you have used alternative approaches.
LINKEDIN
RSS FEED
No comments yet.