Solved

DHCP and DNS powershell / vbscript needed to change setting

Posted on 2013-10-23
8
1,507 Views
Last Modified: 2013-10-29
Is the a way to query all DHCP servers in ADS (authorized) for both root and child, and from those results, make a configuration change to the IPV4 DNS settings.

I have about 200-300 DCHP servers across the whole domain at various sites. etc.
including child domains too.

We had an issue where some random (BYOD) computer with the same name as one of our critical business servers (updated the A record in DNS. )
This some computer was neither a domain added PC, nor a priveldged user . etc.

It was assumed that the non-domain computer (random) BYOD, got an IP address from DHCP, and DHCP updated the A and PTR record in its behalf.

So looking at all the DHCP IPv4 setting / properties
We see that

Enable DNS dynamic updates according to the settings below
Always Dynamically update DNS A and PTR records
Discard A and PTR records when lease is deleted

and Finally
Dynamically update DNS A and PTR records for DHCP clients that do not request updates.


It has been said that the final option
Dynamically update DNS A and PTR rcords for DHCP clients that do not request updates.
needs unchecked to prevent this from happening...

So part (1)
is there a powershell, vbscript, or etc  that will query all authorized DHCP servers in Active directory for both root and child domain.

Then ping or check if the server is available
then check to see if it is running DHCP server service. (status)
then from the list of all running DHCP servers.
configure the IPV4 setting to uncheck the Dynamically update DNS A and PTR records for DHCP clients that do not request updates.

On completion of the script, I need it to write both success and failures to a log file.

Failures should include unreachable if no longer on the network, ( line item)
Failure should include "does not have DHCP server service running or status, if its reachable, but cant get to dhcp server service." separate line item.

and write its overall success and failure of updating the appropriate setting on the IPv4 DNS tab.

(2) second part.
Not sure if this can be in combination or coininisde with the first part.
But for failures, unreachable or etc. need a way to query ADS to see when its last time stamp was registered, and/or on the network, and etc. Need to verify if the list of Authorized DHCPs in ADS is inacurate and there are disabled, decommissioned, stale, or orphaned records. with last timestamp

(3) final part (cleanup)
for all the bad\orphaned\disabled\stale lingering objects,
Need script to remove from ADS computer accounts, and also from the Authorized Managed DHCP list, so it no longer shows up in the list anymore.

Not sure if this has been done, if there are Experts than can help.
Going through so many is very tedious, and allows for potential humnan error.

Thanks for your thoughts, suggestions, and help
0
Comment
Question by:Indyrb
  • 5
  • 3
8 Comments
 
LVL 70

Expert Comment

by:Chris Dent
ID: 39596665
Part 1: Returning the DHCP servers from the forest

Using Quest's AD CmdLets for convenience:
http://www.quest.com/powershell/activeroles-server.aspx

$ConfigNC = Get-QADRootDSE | Select-Object -ExpandProperty ConfigurationNamingContext
Get-QADObject -SearchRoot "CN=NetServices,CN=Services,$ConfigNC" -LdapFilter "(objectClass=dHCPClass)" |
  ForEach-Object {
    $Server = New-Object PsObject -Property @{
      Name              = $_.Name;
      PingResponds      = $false;
      DHCPServiceStatus = "NotPresent";
    }

    if (Test-Connection $Server.Name -Quiet -Count 2) {
      $Server.PingResponds = $true

      $DhcpService = Get-Service -ComputerName $Server.Name | Where-Object { $_.Name -eq 'DhcpServer' }
      if ($DhcpService) {
        $Server.DHCPServiceStatus = $DhcpService.Status
      }
    }
    
    $Server
  # The trailing } is required. Optional results export because this may take a while to complete.
  } | Export-Csv "DhcpServers.csv" -NoTypeInformation

Open in new window

Chris
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 39596670
I've split this out of part 1:

configure the IPV4 setting to uncheck the Dynamically update DNS A and PTR records for DHCP clients that do not request updates.

I'm a strongly believe you want the reporting script first, then an opportunity to do things based on that.  Reports need to be reviewed by people first, just in case it might do something you didn't expect.

Anyway, I'm half-sure we can modify those check boxes using netsh. I'll be right back.

Chris
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 39596697
Update to Part 1. It reports on all required values now.
$RootDSE = Get-QADRootDSE
$RootNC = $RootDSE.rootDomainNamingContext
$ConfigNC =  $RootDSE.ConfigurationNamingContext
Get-QADObject -SearchRoot "CN=NetServices,CN=Services,$ConfigNC" -LdapFilter "(objectClass=dHCPClass)" |
  ForEach-Object {
    $Server = New-Object PsObject -Property @{
      Name                       = $_.Name;
      PingResponds               = $false;
      DHCPServiceStatus          = "NotPresent";
      DnsUpdateDNS               = "Unknown";
      DnsDiscardForwardLookups   = "Unknown";
      DnsUpdateNonDynamicClients = "Unknown";
      ServerPasswordLastSet      = $null;
      ServerLastLogin            = $null;
    }

    if (Test-Connection $Server.Name -Quiet -Count 2) {
      $Server.PingResponds = $true
      
      $ComputerObject = Get-QADComputer -DnsName $Server.Name -SearchRoot $RootNC -GC -IncludedProperties PwdLastSet, LastLogonTimeStamp
      $Server.ServerPasswordLastSet = $ComputerObject.PwdLastSet
      $Server.ServerLastLogin = $ComputerObject.LastLogonTimeStamp
      
      $DhcpService = Get-Service -ComputerName $Server.Name | Where-Object { $_.Name -eq 'DhcpServer' }
      if ($DhcpService) {
        $Server.DHCPServiceStatus = $DhcpService.Status
        
        $DnsConfig = Invoke-Expression "netsh dhcp server \\$($Server.Name) show dnsconfig"
        if ($DnsConfig) {
          switch -RegEx ($DnsConfig) {
            '^Dynamic update[^:]+: (\w+)\.?'  { $Server.DnsUpdateDns = $Matches[1] }
            '^Discard forward[^:]+: (\w+)\.?' { $Server.DnsDiscardForwardLookups = $Matches[1] }
            '^Do update[^:]+: (\w+)\.?'       { $Server.DnsUpdateNonDynamicClients = $Matches[1] }
          }
        }
      }
    }
    $Server
  # The trailing } is required. Optional results export because this may take a while to complete.
  } | Export-Csv "DhcpServers.csv" -NoTypeInformation

Open in new window

Chris
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 39596774
All done. Please see below.

Minor updates to everything above and I believe I've captured all the requirements. Not bad since I only got the neglected question alert 1 hour 15 minutes ago :)

Notes

Error handling when it comes to actually changing things is vague. I have no test system to try this one.

And since it's not tested, you should before you let it lose on your Forest.

Prerequisites

Scripts require Quest AD CmdLets: http://www.quest.com/powershell/activeroles-server.aspx

Part 1


Reporting DHCP server settings and server status. The user is assumed to understand the values returned.
$RootDSE = Get-QADRootDSE
$RootNC = $RootDSE.rootDomainNamingContext
$ConfigNC =  $RootDSE.ConfigurationNamingContext
Get-QADObject -SearchRoot "CN=NetServices,CN=Services,$ConfigNC" -LdapFilter "(objectClass=dHCPClass)" |
  ForEach-Object {
    # The use of [Ordered] here requires PowerShell 3. Makes the output format nicer.
    $Server = New-Object PsObject -Property ([Ordered]@{
      Name                       = $_.Name;
      AuthDN                     = $DN;
      PingResponds               = $false;
      DHCPServiceStatus          = "NotPresent";
      DnsUpdateEnabled           = "Unknown";
      DnsUpdateSetting           = "Unknown";
      DnsDiscardForwardLookups   = "Unknown";
      DnsUpdateNonDynamicClients = "Unknown";
      ServerPasswordLastSet      = $null;
      ServerLastLogin            = $null;
    })

    if (Test-Connection $Server.Name -Quiet -Count 2) {
      $Server.PingResponds = $true
      
      $ComputerObject = Get-QADComputer -DnsName $Server.Name -SearchRoot $RootNC -GC -IncludedProperties PwdLastSet, LastLogonTimeStamp
      $Server.ServerPasswordLastSet = $ComputerObject.PwdLastSet
      $Server.ServerLastLogin = $ComputerObject.LastLogonTimeStamp
      
      $DhcpService = Get-Service -ComputerName $Server.Name | Where-Object { $_.Name -eq 'DhcpServer' }
      if ($DhcpService) {
        $Server.DHCPServiceStatus = $DhcpService.Status
        
        $DnsConfig = Invoke-Expression "netsh dhcp server \\$($Server.Name) show dnsconfig"
        if ($DnsConfig) {
          switch -RegEx ($DnsConfig) {
            '^Dynamic update[^:]+: (\w+)\.?'  { $Server.DnsUpdateEnabled = $Matches[1] }
            '^client acquires[^:]+: (.+)$'    { $Server.DnsUpdateSetting = $Matches[1] }
            '^Discard forward[^:]+: (\w+)\.?' { $Server.DnsDiscardForwardLookups = $Matches[1] }
            '^Do update[^:]+: (\w+)\.?'       { $Server.DnsUpdateNonDynamicClients = $Matches[1] }
          }
        }
      }
    }
    $Server
  # The trailing } is required. Optional results export because this may take a while to complete.
  } | Export-Csv "DhcpServers.csv" -NoTypeInformation

Open in new window


Part 1.5


Modifying the existing setting. Consumes the CSV generated in part 1.
Import-Csv DhcpServers.csv |
  Where-Object { $_.DHCPServiceStatus -eq "Running" -and $_.DnsUpdateNonDynamicClients  -eq "Enabled" } |
  ForEach-Object {
    # netsh dhcp server \\server set dnsconfig <Enable(0|1> [Update(0|1)] [Lookup(0|1)] [NonDyn(0|1)]
    $Enable = 0; $Update = 0; $Lookup = 0; $NonDyn = 0
    if ($_.DnsUpdateEnabled -eq 'Enabled')         { $Enable = 1 }
    if ($_.DnsUpdateSetting -match '^Always')      { $Update = 1 }
    if ($_.DnsDiscardForwardLookups -eq 'Enabled') { $Lookup = 1 }
    # NonDyn is left as 0, the setting we wish to put in place.
    $Command = "netsh dhcp server \\$($_.Name) set dnsconfig $Enable $Update $Lookup $NonDyn"
    Invoke-Expression $Command
    # Error handling here is a bit vague. I have no test system.
    if ($?) {
      $_ | Select-Object *, @{n='ChangeStatus';e={ "Success" }}
    } else {
      $_ | Select-Object *, @{n='ChangeStatus';e={ "Failure" }}
    }
  } | Export-Csv DhcpServerChangeReport.csv -NoTypeInformation

Open in new window


Part 2


Merged into part 1. PwdLastSet and LastLogonTimeStamp are pulled from the Global Catalog. Provided, of course, the server can be located in the first place.

Part 3


You can delete the object from AD that makes it an authorised DHCP server. For example, we might decide everything which doesn't have DHCP running should be deauthorised:
Import-Csv DhcpServers.csv | Where-Object { $_.DHCPServiceStatus -ne 'Running' } | ForEach-Object { Remove-QADObject $_.AuthDN }

Open in new window

Cheers!

Chris
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:Indyrb
ID: 39598906
Awesome job... I look forward to the test... I have a question, First your last post is the final code for all combined parts correct, I don't need to pull from post or example one, then a little on two. its the complete list...

More specifically I am looking at part one...

Part one if I understand is just a collection of DHCP servers, validate they are reachable, report their service, then collect the settings... I wasn't sure if it was using netsh to update any values, I was slightly confused on last part.


HAve you ran part 1, just to report on your own domain, without making any changes, just report?

I see your comment about powershell version 3?  Is version 3 native to windows 2008  (not R2) can it be downloaded and installed and compatiable on 2K8 (not R2)

Also we have mixed mode servers, some 2K8, some 2K3... and perhaps a stupid slight chance of 2K....

If the powershell script is ran locally on an OS that supports powershell version 3, and run with proper credentials, will it remotely pull all the information of all the servers, even if they are legacy Oses?

I was going to copy/paste the code and in bold ask various questions about what it is doing, and why a value of null or some understanding of its function and code.. (For learning and education)

But I was hoping that you could just put in little notes or comments on each line, (group) of what the code is doing, as the more I looked through it , the more I was curious and had questions....

I thank you for ytour expertise and the quick turn around...
We will start off with just a report to give to management with accurate details of value, pingable, unreachable, failed service, dhcp settings, timestamp in ads, and etc..
I like the export to cvs/excel.

Yes ultimate goal is the whole execution.. and I appreciate all the samples.. Can you kindly just teach or learn me on the code, properties, and commands. I am newbie --

Thanks Chris....
0
 
LVL 70

Accepted Solution

by:
Chris Dent earned 500 total points
ID: 39599789
Good morning,

This post will also contain everything you need to run the script, comments are verbose. The previous did as well, but I never stop tweaking things.

These are the changes between this post and the last.

Part 1 - The previous version only checked lastLogonTimeStamp / PwdLastSet if the computer responded to Ping. This version addresses that and checks for those values regardless.
Part 1.5 - Added a second NetSh call to show the new values for dnsConfig.

Requirements to execute the scripts

Quest AD CmdLets: Those would need to be downloaded, we make three calls using those. If necessary they can be replaced with native things, but that adds a fair bit of extra complexity.

PowerShell 3: It's native to Windows 8 / 2012. It can be downloaded for Windows 7 and 2008 R2.

http://www.microsoft.com/en-gb/download/details.aspx?id=34595

PowerShell 3 is only required on the system running the script, the version on the remote system does not matter.

Supported operating systems

In theory it should work on down-level servers. Part 1 is harmless either way.

However, I have only tested part 1 against Windows 2008 R2. I have nothing else I can poke here I'm afraid.

Where to run the scripts

Nothing needs to be local to each server. All commands are remote.

If I worked for you, I'd run all of these scripts from my own workstation, or a nominated / dedicated workstation (or server) for executing scripts like this.

The remote nature of the script is the only reason I consider it acceptable to inject a little flexibility in the software requirements (PS 3 / Quest CmdLets).

Part 1

Part 1 is reporting only, it changes nothing. Looks around, doesn't change. It does need administrative rights, but only to execute this command:

netsh dhcp server \\someserver show dnsconfig

The code below has been annotated to better describe it's operation.
$RootDSE = Get-QADRootDSE
# This will be used as the search root when searching Active Directory for a computer account
$RootNC = $RootDSE.rootDomainNamingContext
# The connfiguration portion of Active Directory
$ConfigNC =  $RootDSE.ConfigurationNamingContext
# Get-QADObject is used here, but we can write around it if installation is impossible.
Get-QADObject -SearchRoot "CN=NetServices,CN=Services,$ConfigNC" -LdapFilter "(objectClass=dHCPClass)" |
  ForEach-Object {
    # We're looping through the results of the search now.
  
    # The use of [Ordered] here requires PowerShell 3. Makes the output format nicer.
    # This is the information we're returning, this will be written to a CSV file.
    # Information we know (such as Name) is added, information we don't know yet is set to 
    # a default value until we know better.
    $Server = New-Object PsObject -Property ([Ordered]@{
      Name                       = $_.Name;
      AuthDN                     = $DN;
      PingResponds               = $false;
      DHCPServiceStatus          = "NotPresent";
      DnsUpdateEnabled           = "Unknown";
      DnsUpdateSetting           = "Unknown";
      DnsDiscardForwardLookups   = "Unknown";
      DnsUpdateNonDynamicClients = "Unknown";
      ServerPasswordLastSet      = $null;
      ServerLastLogin            = $null;
    })

    # This section has moved, in the previous version it was under the "if (Test-Connection $Server.Name -Quiet -Count 2) {" statement.
    # 
    # Attempt to find the computer account. This will slow the script down, repeated searches like this aren't all
    # that efficient. The search targets the Global Catalog to account for all domains within a Forest (a single tree is assumed).
    $ComputerObject = Get-QADComputer -DnsName $Server.Name -SearchRoot $RootNC -GC -IncludedProperties PwdLastSet, LastLogonTimeStamp
    # Pull the PasswordLastSet field for this computer account from AD. Computers accounts reset this every 30 days (regardless of password policy).
    $Server.ServerPasswordLastSet = $ComputerObject.PwdLastSet
    # Pull the lastLogonTimeStamp. It may be up to 14 days out, but it's replicated and published into the GC so it's a great field for this.
    $Server.ServerLastLogin = $ComputerObject.LastLogonTimeStamp

    # Test-Connection is Ping. Sending 2 ICMP requests and hoping for a reply.
    if (Test-Connection $Server.Name -Quiet -Count 2) {
      # If it did reply, set that value on the Server object used to generate the report.
      $Server.PingResponds = $true

      # Pull a list of all services on the server and filter the list to see if the DhcpServer service is listed.
      # This is faster than running "Get-Service DhcpServer -ComputerName $Server.Name" as we don't have to timeout
      # the call if the service does not exist.      
      $DhcpService = Get-Service -ComputerName $Server.Name | Where-Object { $_.Name -eq 'DhcpServer' }
      
      # If the service does exist.
      if ($DhcpService) {
        # Pull the service status so we can write it to the report. This way we don't have to
        # test for lots of different values, if we find it we show the status as it is.
        $Server.DHCPServiceStatus = $DhcpService.Status
        
        # Use NetSh to grab the DnsConfig from the DHCP service. Tested on Windows 2008 R2, but claims to be valid from 2000 and above.        
        $DnsConfig = Invoke-Expression "netsh dhcp server \\$($Server.Name) show dnsconfig"
        
        # If we have a value for DnsConfig
        if ($DnsConfig) {
          # Use a set of regular expressions to parse it, pulling out the state of each element.
          # Write these values to the report.
          switch -RegEx ($DnsConfig) {
            '^Dynamic update[^:]+: (\w+)\.?'  { $Server.DnsUpdateEnabled = $Matches[1] }
            '^client acquires[^:]+: (.+)$'    { $Server.DnsUpdateSetting = $Matches[1] }
            '^Discard forward[^:]+: (\w+)\.?' { $Server.DnsDiscardForwardLookups = $Matches[1] }
            '^Do update[^:]+: (\w+)\.?'       { $Server.DnsUpdateNonDynamicClients = $Matches[1] }
          }
        }
      }
    }
    # The object we created for the report is now complete. Leave it as output so Export-Csv can pick it up below.
    $Server
  # The trailing } is required (it completes the ForEach-Object loop).
  # Results are exported to this CSV file name under the current path.
  } | Export-Csv "DhcpServers.csv" -NoTypeInformation

Open in new window


Part 1.5


This should make the change, netsh describes the required syntax. However, it is very important to note that I have not tested this part. Nothing to test on near work and home is always busy.

# Use the file generated by the previous script. Filter the results to capture servers 
# with a Running DHCPServer service and with updates enabled for clients which don't 
# request the update.
Import-Csv DhcpServers.csv |
  Where-Object { $_.DHCPServiceStatus -eq "Running" -and $_.DnsUpdateNonDynamicClients  -eq "Enabled" } |
  ForEach-Object {
  
    # Create a return value as a copy of the original (*) with a few extra fields.
    $Server = $_ | Select-Object *, NewDnsUpdateEnabled, NewDnsUpdateSetting, NewDnsDiscardForwardLookups, NewDnsUpdateNonDynamicClients
  
    # NetSh tells us the syntax for changing the dnsconfig settings:
    #    
    # netsh dhcp server \\server set dnsconfig <Enable(0|1> [Update(0|1)] [Lookup(0|1)] [NonDyn(0|1)]
    #
    # It is not clear whether or not all values are mandatory. Therefore this script treats them as if they are.
    #
    # These are the default values for each of the settings (disabled)
    $Enable = 0; $Update = 0; $Lookup = 0; $NonDyn = 0
    
    # Look at the report file, and change the default value set above to match
    # This way we should change nothing except the one value we're targetting.
    if ($Server.DnsUpdateEnabled -eq 'Enabled')         { $Enable = 1 }
    if ($Server.DnsUpdateSetting -match '^Always')      { $Update = 1 }
    if ($Server.DnsDiscardForwardLookups -eq 'Enabled') { $Lookup = 1 }
        
    # NonDyn is left as 0, the setting we wish to put in place. The filter we have at the top
    # means we're only doing this to servers which have it enabled anyway.
    
    # Build and execute the command according to the example NetSh provides.
    # See: netsh dhcp server \\server set dnsconfig ?
    Invoke-Expression "netsh dhcp server \\$($Server.Name) set dnsconfig $Enable $Update $Lookup $NonDyn"

    # This is the new reporting block. The existing values will be preserved in the spreadsheet,
    # new values will be shown alongside. If nothing changed the command didn't work.
    $DnsConfig = Invoke-Expression "netsh dhcp server \\$($Server.Name) show dnsconfig"
        
    # If we have a value for DnsConfig
    if ($DnsConfig) {
      # Use a set of regular expressions to parse it, pulling out the state of each element.
      # Write these values to the report.
      switch -RegEx ($DnsConfig) {
        '^Dynamic update[^:]+: (\w+)\.?'  { $Server.NewDnsUpdateEnabled = $Matches[1] }
        '^client acquires[^:]+: (.+)$'    { $Server.NewDnsUpdateSetting = $Matches[1] }
        '^Discard forward[^:]+: (\w+)\.?' { $Server.NewDnsDiscardForwardLookups = $Matches[1] }
        '^Do update[^:]+: (\w+)\.?'       { $Server.NewDnsUpdateNonDynamicClients = $Matches[1] }
      }
    }
    
  # Write the modified report to a new CSV file.
  } | Export-Csv DhcpServerChangeReport.csv -NoTypeInformation

Open in new window


Part 2


As discussed before, merged into part 1, the tweak in this post makes it better account for things that no longer exist.

Part 3


This removes the object which denotes an authorised DHCP server in AD.

Again, this has not been tested. I've added -WhatIf to the command so if you were to run it, it would only show you what it would like to do.
Import-Csv DhcpServers.csv | Where-Object { $_.DHCPServiceStatus -ne 'Running' } | ForEach-Object { Remove-QADObject $_.AuthDN -WhatIf }

Open in new window

I have not addressed removal of the computer account, doing so seems rather risky. I strongly recommend you divorce that process from this one. This script does nothing to account for what else a server may be set-up to do, and what else it may have lingering in AD.

Chris
0
 

Author Comment

by:Indyrb
ID: 39610124
I appreciate your time and effort, and will go ahead and close this request and award points -- thanks

I haven't tested the script, but if I have questions or issues, I will hit you up..

Thank you Chris
0
 

Author Closing Comment

by:Indyrb
ID: 39610126
I appreciate your time and effort, and will go ahead and close this request and award points -- thanks

I haven't tested the script, but if I have questions or issues, I will hit you up..

Thank you Chris
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Sometimes drives fill up and we don't know why.  If you don't understand the best way to use the tools available, you may end up being stumped as to why your drive says it's not full when you have no space left!  Here's how you can find out...
OfficeMate Freezes on login or does not load after login credentials are input.
This tutorial will show how to push an installation of Backup Exec to an additional server in both 2012 and 2014 versions of the software. Click on the Backup Exec button in the upper left corner. From here, select Installation and Licensing, then I…
This tutorial will show how to configure a new Backup Exec 2012 server and move an existing database to that server with the use of the BEUtility. Install Backup Exec 2012 on the new server and apply all of the latest hotfixes and service packs. The…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now