views:

272

answers:

1

I am trying to automate DNS zone creation by using a batch file fired through one of Plesk's events.

Using the dnscmd command, the batch checks to see if the zone exists. If the zone does not exist, the script adds it according to specs. If it does exist, and it is a secondary zone, the script deletes and recreates it according to specs. If it exists, and it is a primary zone, the script leaves it alone. That part is all working.

Since we have some custom configurations, I also wanted to verify that if the zone is a secondary zone, it was also using the target server as the master. If it is using a different master, leave it alone. While I was able to retrieve the list of master servers, I was unable to match the text because of an odd problem with the output. Windows uses 0x0d,0x0a as the end-of-line marker, and the batch environment recognizes this. On this particular line of output, however, the end-of-line includes an additional 0x0d; the EOL is marked as 0x0d,0x0d,0x0a.

The problem section is after the :check3 label. I was receiving some weird feedback from the FOR /F loop, and added the echo commands to help debug. I eventually loaded the output of dnscmd directly into a hex editor to have a look. Using the algorithm shown in the script below, my test variables %%A and %%B retain the additional 0x0d, thus messing up my comparisons. The other lines I check from dnscmd do not show this issue - it is only with the output related to the MasterServers information. How can I resolve this?

The requirements: batch functionality only...we know we can recode this as VBScript and instantly resolve the issue, but that is not our goal here. The solution must not involve any other applications to parse the output from dnscmd.

@echo off
rem 1.2.3.4 = target server holding Plesk domains
rem 5.6.7.8 = our public nameservers

rem *** USER CONFIGURED VARIABLES
set dnsupdlog=test.log
set dnsupdip=1.2.3.4

rem *** other script variables (DO NOT MODIFY)
rem the next line is "set tab=<tab>%"
set tab=        %
set nozone=%1

rem *** make sure a domain was provided
if "%1"=="" set nozone=**NO ZONE PROVIDED**
for /F "delims=" %%A IN ('date /T') DO SET dnsupdtime=%%A
echo --------%dnsupdtime% begin zone %nozone% > %dnsupdlog%
if "%nozone%"=="**NO ZONE PROVIDED**" (
  echo You must provide a domain name, e.g., test.bat mydomain.com >> %dnsupdlog%
  goto :endit
)

rem *** does domain exist yet?  if not, just add the domain
"%plesk_bin%\dnscmd.exe" 5.6.7.8 /zoneinfo %1 | find "query failed" > NUL
if ERRORLEVEL 1 (
  echo Zone exists ... continue checking >> %dnsupdlog%
  goto :check2
)
echo Zone does not exist ... add domains >> %dnsupdlog%
goto :add_domains

:check2
rem *** domain already exists.  Is it primary?  if yes, skip
for /F "tokens=1-2 skip=1 delims=%tab%: " %%A IN ('"%plesk_bin%\dnscmd.exe" 5.6.7.8 /zoneinfo %1 Type') DO (
  if "%%A"=="Dword" (if "%%B"=="1" (
    echo Domain is a primary zone.  No work to be done. >> %dnsupdlog%
    goto :endit
    )
    echo Not a primary zone ... continue checking >> %dnsupdlog%
    goto :check3
  )
)
echo ***ERROR*** Could not determine zone type!! >> %dnsupdlog%
goto :endit

:check3
rem *** secondary domain exists.  Is it using this as master?  if not, skip
set isfound=no
for /F "skip=1 tokens=2-3 delims=%tab%=> " %%A IN ('"%plesk_bin%\dnscmd.exe" 5.6.7.8 /zoneinfo %1 MasterServers') DO (
  echo %%A
  echo %%B
  echo %%A,
  echo %%B,
  if /i "%%A"=="count" (if /i "%%B" NEQ "1" (
    echo Received unexpected master server count %%B!! >> %dnsupdlog%
    goto :endit
    )
  )
  if /i "%%A"=="Addr[0]" (
    if /i "%%B" NEQ "%dnsupdip%" (
      echo Different master server %%B.  No work to be done. >> %dnsupdlog%
      goto :endit
      )
    set isfound=yes
  )
)
if /i "%isfound%" NEQ "yes" (
  echo Did not find expected IP %dnsupdip% as master server.  No work to be done. >> %dnsupdlog%
  goto :endit
)

:del_domains
rem *** delete domains here
echo del >> %dnsupdlog%

:add_domains
rem *** add domains here
echo add >> %dnsupdlog%

:endit
echo --------%dnsupdtime% end zone %nozone% >> %dnsupdlog%
set isfound=
set nozone=
set dnsupdtime=
set dnsupdlog=
set dnsupdip=
A: 

I was able to get a script to ignore extra CR (0x0D) characters by using a combination of the FOR "call :subroutine" and SET substring capabilities.

First I created a test file with extra CRs on a few lines, in the CR CR LF arrangement that you were getting from DNSCMD. I was actually just trying to figure out the SET substring capability to strip off the extra CR, when I realized that the variables in the body of a multiline FOR statement (lines between parentheses) all get expanded at once, so SET substring manipulation doesn't work. Instead these commands needed to be executed line by line, which led me to the "call :subroutine" capability.

To get the remainder of the line passed to the ":show" subroutine", I had to put the third variable in quotes. This itself seems to strip the extra CR on lines that have it, neatly avoiding further conditional logic to skip lines that don't have an extra CR. Then I used substring manipulation in the subroutine to remove the quotes.

@echo off
for /F "tokens=1,2* delims= " %%A in (testfile.txt) do (call :show %%A %%B "%%C")
goto :eof

:show
  echo A=[%1]
  echo B=[%2]
  echo C=[%3]
  set l=%3
  : the param needs to be copied to another var for expansion to work
  set t=%l:~1,-1%
  echo T=[%t%]

  echo ---
  goto :eof

Batch programming has certainly come a long way from the old DOS days, but even so it just seems to be a pile of work-arounds to deal with the side effects of other work-arounds!

Anyway, you should be able to utilize something like this to get your script to work. In your case, if you just pass your %%A and %%B params to a subroutine you may be all set and not have to worry about adding and removing quotes. I don't know enough about DNSCMD so I can't replicate your output, otherwise I would give a more specific solution.

Todd
Essentially the same someone else provided to me on another site. Their example merely removed the final character of the string as opposed to adding others in first. In addition, they use "setlocal enabledelayedexpansion" to allow expanding the variables within the loop. Their snippet that did the work: set A=%%A set B=%%B set A=!A:~0,-1! set B=!B:~0,-1!
SBink