Search This Blog

Wednesday 14 July 2010

Microsoft DNS update script - dnscmd

We recently made the decision to use AD DNS internally rather than the mish mash of AD & BIND.  One of the downsides was the inability for bulk load changes.  The DNSCMD command line app is limited.

This is my attempt to fix that with a script.  It deals with creating A & CNAME forward records and cleans up and creates PTR from an input file bulk_load.txt

DNSCMD doesn't deal with existing A records.  The majority of the script deals with finding those and deleting the FWD and REV records.

Feel free to copy, currently its still in test so use with care.

Amendments/suggestions, all welcome .. there are a few hacks in it which I'm sure can be cleaned up.  

And yes it could probably be done on 5 lines in something else.  I just don't know something else.
@ECHO OFF
::        // Paul Regan - 14/7/2010/7/14/2010
::        // This script will take input from dns_bulk.txt, which must be forward zone A or CNAME records.
::        // First check if the entries already exist.  If they do it will prompt to continue.
::        // It will then delete the forward and reverse entries and create the new from the file.
::        // Through-out this script there are a number of hacks due to DNSCMD's inability to produce decent return codes. I rely on
::        // piping STNDOUT through FIND & FC to check FOR response and generate the correct errorlevel
::        // Check the help (/?) for bulk_dns.txt format

IF "%1" == "" GOTO ERROR
IF "%1" == "/?" GOTO HELP
IF "%1" == "?" GOTO HELP

::        // A quick check that bulk_dns.txt EXISTs and confirm its the file to be used
IF EXIST bulk_dns.txt (
    GOTO BULK_EXISTS
) ELSE (
    CLS
    ECHO.
    ECHO.      ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR
    ECHO.
    ECHO       bulk_dns.txt is missing !
    GOTO END
)

:BULK_EXISTS
CLS
ECHO.
ECHO     This is the bulk_txt I found ...
ECHO.
TYPE bulk_dns.txt
ECHO.
ECHO.
ECHO.
CHOICE /C YN /M "continue and use this file ? Press Y for Yes, N for No
IF %ERRORLEVEL%==1 GOTO BEGIN
IF %ERRORLEVEL%==2 GOTO END

:BEGIN
::        // Sets the DNS Server to be used from the STNDIN
SET DNS-SERVER=%1

::        // Clean up any old working files
IF EXIST revip.txt DEL /f /q revip.txt >NUL
IF EXIST recorddeleted.txt DEL /f /q recorddeleted.txt >NUL
IF EXIST recordsexist.txt DEL /f /q recordsexist.txt >NUL
IF EXIST rev-recordsexist.txt DEL /f /q rev-recordsexist.txt >NUL
IF EXIST recordcreated.txt DEL /f /q recordcreated.txt >NUL
IF EXIST summary.txt DEL /f /q summary.txt >NUL
IF EXIST doesntexist.txt DEL /f /q doesntexist.txt >NUL

::        // Reset the variable and then extract the zone from bulk_dns.txt & SET.  We do this as the zone will be common to all commands
SET ZONEFILE=
FOR /f "tokens=2 delims=," %%1 IN (bulk_dns.txt) DO SET ZONEFILE=%%1

::        // loop to determin if any records already exist as we need to first delete them. -->
::        // In theory DNSCMD should return :
::        //  0 = host found
::        //  9714 = host not found
::        // in practice it didnt, possibly to do with the FOR loop.  A hack is to pipe the STDNOUT through find.  A DNS hit response includes @
::        // SetLocal / EndLocal deals with variables being used in a FOR loop, allows the FOR loop to return the correct ERRORLEVELs per loop
CLS
ECHO.
ECHO Checking for existing records ............
ECHO.
SETLOCAL EnableDelayedExpansion
FOR /f "tokens=1-4 delims=," %%1 IN (bulk_dns.txt) DO (
        DNSCMD %DNS-SERVER% /EnumRecords %%2 %%1  | FIND "@"
    IF !ERRORLEVEL! == 0 (
        ECHO %%1.%%2,%%3,%%4 >> recordsexist.txt
    ) ELSE (
        ECHO %%1.%%2 Doesn't Exist >>doesntexist.txt
    )
)
ENDLOCAL
::        // Check to see if recordsexist has been created, and action, o/wise jump to create
IF NOT EXIST recordsexist.txt GOTO :CREATE
::        // Display existing host entries and give an opt out prompt using the file generated from the /EnumRecords loop
CLS
ECHO.
ECHO ******  The following host entries already EXIST *******
ECHO.
TYPE recordsexist.txt
ECHO.
ECHO.
ECHO.
CHOICE /C YN /M "continue ? this will delete and then re-create from bulk_dns.txt Press Y for Yes, N for No
IF %ERRORLEVEL%==1 GOTO DELETE
IF %ERRORLEVEL%==2 GOTO BOMBOUT
GOTO END

:BOMBOUT
GOTO END

:DELETE
::        // Start loops to delete existing A, CNAME & PTR DNS entries
::        // DNSCMD returns a 0 FOR /RecordDelete and exactly the same output regardless IF a delete fails or even IF you attempt
::        // to delete a host that doesnt EXIST.
::        // So its pointless doing any errorlevel checks.  We'll assume that we got this far and they EXIST and we'll be able to delete them
CLS
ECHO.
ECHO Deleting forward zone records ............
ECHO.
FOR /f "tokens=1-9 delims=.," %%1 IN (recordsexist.txt) DO DNSCMD %DNS-SERVER% /RecordDelete %ZONEFILE% %%1 %%9 /f
::        // We now need to clean up the reverse records & will create a rev dns working file from the records in recordsEXIST.txt
::        // Parse the txt file and extract the 'A' records to a new txt file.
CLS
ECHO.
ECHO Fordward records deleted, now the rev zone........if no rev zone exists you will see errors during this process.
ECHO.
TYPE recordsEXIST.txt | find "A" >> rev-recordsexist.txt
::        // Parse that txt file and create a another file with the reverse ip host names
FOR /f "tokens=5-8 delims=,." %%a IN (rev-recordsexist.txt) DO ECHO %%d.%%c.%%b.%%a.in-addr.arpa >>revip.txt
::        // Phew, now we can delete the in-addr.net records using this text file
::        // DNSCMD returns a 0 FOR /RecordDelete regardless so its pointless doing any errorlevel checks
FOR /f "tokens=1-6 delims=." %%a IN (revip.txt) DO DNSCMD %DNS-SERVER% /RecordDelete %%b.%%c.%%d.%%e.%%f %%a PTR /f

:CREATE
CLS
ECHO.
ECHO Create foward and rev records.......if rev zones dont exist you may see errors.
ECHO.
::        // And now, finally, create the host entries
FOR /f "tokens=1-4 delims=," %%1 IN (bulk_dns.txt) do DNSCMD %DNS-SERVER% /RecordAdd %ZONEFILE% %%1 /CreatePTR %%4 %%3
::        // Run a quick /EnumRecords check to confirm records where created and then produce a comparison file of that output to bulk_dns.txt
::        // The | find "@" just removes a bunch of white space from STDOUT
FOR /f "tokens=1-4 delims=," %%1 IN (bulk_dns.txt) do DNSCMD %DNS-SERVER% /EnumRecords %%2 %%1 | FIND "@" >> RECORDCREATED.txt
FC recordcreated.txt bulk_dns.txt | FIND /V "Command" | FIND /V "records" >> summary.txt
CLS
TYPE summary.txt | MORE
ECHO.
ECHO You can review the comparison afterwards with summary.txt
ECHO.
PAUSE
GOTO CLEANUP

:HELP
CLS
ECHO.
ECHO.
ECHO      This script takes input from bulk_dns.txt, checks FOR EXISTing records and then deletes and creates A or CNAME records.
ECHO      It will automatically deal with PTR records, there is no need to put them in bulk_dns.
ECHO.
ECHO      ***** "ONLY USE THIS ON ONE ZONE NA OR EU [eu|na].rtdom.net at a time, NOT A MIX .. !" *****
ECHO.
ECHO      bulk_dns.txt FORmat
ECHO      ",,,"
ECHO.
ECHO      eg A Record
ECHO      server,eu.rtdom.net,A,10.2.66.66
ECHO.
ECHO      eg CNAME Record
ECHO      server,eu.rtdom.net,CNAME,lo-inf-999.eu.rtdom.net
ECHO.
ECHO      The FORmat of the script command is dnscmd ""
ECHO.
ECHO      I have generated an example_bulk_dns.txt FOR reference.
IF EXIST example_bulk_dns.txt DEL example_bulk_dns.txt /f > NUL
ECHO anArecord,eu.rtdom.net,10.2.65.13,A >> example_bulk_dns.txt
ECHO aCNAMErecord,eu.rtdom.net,anArecord.eu.rtdom.net,cname  >> example_bulk_dns.txt
GOTO END

:ERROR
CLS
ECHO      *********** FAIL **************
ECHO.
ECHO script /? For help
GOTO END

:CLEANUP
IF EXIST revip.txt DEL /f /q revip.txt >NUL
IF EXIST recorddeleted.txt DEL /f /q recorddeleted.txt >NUL
::        // Removed this so the user can review the hosts that existed and where over written
REM IF EXIST recordsexist.txt DEL /f /q recordsexist.txt >NUL
REM IF EXIST doesntexist.txt DEL /f /q doesntexist.txt >NUL
IF EXIST rev-recordsexist.txt DEL /f /q rev-recordsexist.txt >NUL
IF EXIST recordcreated.txt DEL /f /q recordcreated.txt >NUL


:END

4 comments:

  1. Proper old skool ;)

    Powershell is the new way to go for this kind of thing isn't it?

    ReplyDelete
  2. I'm an old skool kind-a-guy :)

    agreed, and perl aswell. neither of which I have made the effort to learn.

    I should ..

    ReplyDelete
  3. A useful tool is useful in any language... looks good!

    ReplyDelete
  4. Just knocked something together which I was going to post here but couldnt fit it.....

    http://thescadman.blogspot.com/2010/08/dns-config.html

    ReplyDelete