Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

527 lines
19 KiB

  1. @rem = '
  2. @goto endofperl
  3. ';
  4. $USAGE = "
  5. Usage: $0 InputFiles
  6. MKDSX makes NTDS-Connection objects. An input file specifies where the
  7. connection is to be created, updated or deleted. Create and update commands
  8. take additional parameters specifying whether the connection is enabled and
  9. a schedule parameter. Since connection names are often GUIDs a specific
  10. connection among a list of alternate connections is located by the value of
  11. the connection's From-Sever attribute.
  12. MKDSX Parameters set via enviroment vars.
  13. MKDSX_REDO_FILE Output file of failed mkdsx commands (default: MKDSX.REDO)
  14. MKDSX_DCNAME computer name of DC to bind to.
  15. Input command file entries consist of one record per connection operation.
  16. The following commands are supported.
  17. Host Server From Server Enabled Schedule option
  18. create site\\server site\\server on|off s-ii-cc-pp [/dc dcname] # comment
  19. update site\\server site\\server on|off s-ii-cc-pp [/dc dcname] # comment
  20. del site\\server site\\server|* [/dc dcname] # comment
  21. dump site\\server site\\server|* [/dc dcname] # comment
  22. /dc <default computer name of DC on which to create the connection objects>
  23. /auto_cleanup
  24. /debug processes the file but prevents mkdsxe.exe from actually modifying the DC.
  25. /verbose enables verbose output.
  26. /schedmask <file with 7x24 string of ascii hex digit pairs to turn off the schedule>
  27. /schedoverride <file with 7x24 string of ascii hex digit pairs to turn on the schedule>
  28. No embedded blanks are allowed within parameters.
  29. The /dc option can be used in two ways:
  30. 1. On a command line by itself to specify the global default DC on which
  31. to create/update the connection object for subsequent connection operation
  32. commands. The default can be changed multiple times in the input file.
  33. 2. The /dc option can also be used at the end of the create, update, del
  34. and dump commands to override the current global default for this
  35. single command. This is useful if you need to create a connection object
  36. on a remote DC that currently has no connection objects and so is not
  37. replicating but the global default is sufficient for all the other commands.
  38. The /auto_cleanup option is used to automatically delete ALL old connections
  39. under a given host site\\server before the first new connection is created.
  40. This is done only once before the first create operation on the host is processed.
  41. If the first operation on a given host is an update command then it is assumed
  42. that no cleanup should be done on this host. The del and dump commands do not
  43. trigger an auto cleanup.
  44. Create: Create a connection under the host server in the specified site.
  45. The DN for the From-Server attribute is built using the specified site
  46. and server name. The Enabled-Connection attribute is set based on the
  47. on|off parameter. The Schedule attribute is constructed using the
  48. schedule paramter. Create behaves like update if the specified connection
  49. already exists.
  50. Update: Update a connection under the host server in the specified site.
  51. Parameters are the same as for create. The specific connection is found
  52. by searching for a connection under the host site\\server with a matching
  53. From-Server attribute. Update returns an error if the specified connection
  54. is not found.
  55. Update reads the schedule and enabled attributes and performs the
  56. update only if there is a change. This means that the same connection
  57. data file can be run repeatedly trying to create connections and only
  58. perform creates or updates as needed.
  59. Del : Delete the connection under the host server in the specified site.
  60. The specific connection is found as described in the update command.
  61. If there are duplicate connection objects with the same From Server
  62. attribute then all are deleted.
  63. In addition, if '*' is specified for the From Server parameter then
  64. all NTDS-Connection objects under the host site\\server are deleted.
  65. Dump: Dump out the attribute information for the specified connections.
  66. Automatically building a hub-spoke topology -
  67. An associated script called mkhubbchtop takes a list of hub servers and a list
  68. of branch servers and builds a connection data file for a hub-branch topology
  69. that can be used by this script. mkhubbchtop balances the branch servers
  70. across the list of hub servers with a staggered schedule so all branches are
  71. not hitting the hub server at the same time. See the help info in mkhubbchtop
  72. Schedule parameter and load sharing -
  73. The schedule parameter provides a means for setting a repeating replication schedule.
  74. Connection schedules are an attribute associated with each NTDS-Connection object
  75. in the DC. They contain a 7x24 array of bytes, one byte for each hour in a
  76. 7 day week (UTC time zone). You can use the schedule paramter to spread the
  77. replication load among multiple inbound source servers.
  78. The paramter is of the form s-iii-ccc-ppp where the i, c and p fields are decimal
  79. numbers. The i field describes the desired interval (in hours) between inbound
  80. replication events on the host server. The c field describes the number of
  81. connections objects present that will import data to this host server. Or, put
  82. another way, it is the number of other servers that will be providing data to
  83. this server. The p field is offset parameter that ranges from 0 to c-1. It
  84. is used to stagger the schedule relative to the schedules on the other connection
  85. objects.
  86. For example, lets assume you have two connection objects that refer to two servers
  87. SA and SB which will supply replication updates to the host server. We would
  88. like to arrange the schedules of these two connection objects so that our host
  89. server is updated every 4 hours. To do this, the schedule parameter for the
  90. connection object referring to server SA would be 's-4-2-0' and the parameter
  91. for the connection to server SB is 's-4-2-1'.
  92. Source H o u r
  93. Server 0 4 8 12 16 20
  94. SA s-4-2-0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...
  95. SB s-4-2-1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 ...
  96. Repl Events ^ ^ ^ ^ ^ ^
  97. With these two connection objects the net interval between replication events
  98. will be every 4 hours. The schedule for server B is offset by 4 hours as a result
  99. of the p field being 1. Both of the above schedule patterns continue to repeat
  100. over the course of the 7x24 array comprising the schedule attribute.
  101. As a second example, assume you want to replicate every 2 hours and you establish
  102. connections with three other servers to provide the data. The schedule paramter
  103. values and the schedule array are then:
  104. Source H o u r
  105. Server 0 4 8 12 16 20
  106. SA s-2-3-0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 ...
  107. SB s-2-3-1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 ...
  108. SC s-2-3-2 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 ...
  109. Repl Events ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
  110. Schedmask and Schedoverride parameters -
  111. Schedmask and schedoverride data are formatted as a pair of ascii hex digits
  112. for each byte in the 7x24 schedule array with byte 0 corresponding to day 1 hour 0.
  113. For each connection the 7x24 result schedule is formed using the schedule parameter (see
  114. below) and then the schedule mask is applied (each bit set in the schedule mask
  115. clears the corresponding bit in the result schedule). Finally the schedule override
  116. is applied with a logical OR of the override schedule to the result schedule.
  117. Schedmask and schedoverride can have embedded whitespace chars (including cr/lf)
  118. which are deleted or be a single string of 336 (7*24*2) hex digits. For example:
  119. FF0000000000 000000000000 000000000000 000000000000
  120. FF0000000000 FFFFFFFFFF00 000000000000 000000000000
  121. FF0000000000 FFFFFFFFFF00 000000000000 000000000000
  122. FF0000000000 FFFFFFFFFF00 000000000000 000000000000
  123. FF0000000000 FFFFFFFFFF00 000000000000 000000000000
  124. FF0000000000 000000000000 000000000000 000000000000
  125. FF0000000000 000000000000 000000000000 000000000000
  126. Sample Input File -
  127. #A sample input file might look as follows:
  128. #
  129. /dc ntdev-dc-01
  130. /clean
  131. #
  132. # Host Server From Server Enabled Schedule
  133. #
  134. create Red-Bldg40\\ntdev-dc-01 Red-bldg40\\ntdsdc9 on s-4-2-0 # update every 8 hours beg at hr 0
  135. create Red-Bldg40\\ntdev-dc-01 Red-bldg40\\ntdsdc8 on s-4-2-1 # update every 8 hours beg at hr 4
  136. # update every 2 hours beg at hr 0
  137. update Red-Bldg40\\ntdev-dc-01 Red-bldg40\\ntdsdc90 on s-2-1-0
  138. #End of file
  139. Error handling -
  140. Any command line that returns an error is written to the ReDo file.
  141. An error message is written to standard out.
  142. Note: The redo file is deleted when the script starts so if no redo file exists
  143. after completion of the script then all commands were processed without errors.
  144. ";
  145. die $USAGE unless @ARGV;
  146. ## $mkdsx = "mkdsxe.exe /v ";
  147. $mkdsx = "mkdsxe.exe ";
  148. $time = scalar localtime;
  149. printf DAT ("Running mkdsx on: %s\n", $time);
  150. printf("\n\n");
  151. $redo = $ENV{'MKDSX_REDO_FILE'}; printf("MKDSX_REDO_FILE: %s\n", $redo);
  152. $dcname = $ENV{'MKDSX_DCNAME'}; printf("MKDSX_DCNAME: %s\n", $dcname);
  153. $verbose = $ENV{'MKDSX_VERBOSE'}; printf("MKDSX_VERBOSE: %s\n", $verbose);
  154. if ($redo eq "") {$redo = "mkdsx.redo";}
  155. if ($dcname ne "") {$dcname = "/dc $dcname";}
  156. if ($verbose ne "") {$verbosemode = "/v";}
  157. printf("\n\n");
  158. print $0 @argv;
  159. printf("Redo File: %s\n", $redo) if ($redo ne "");
  160. #
  161. # mkdsx.exe error return codes
  162. #
  163. $ErrMsg[0] = "Success.";
  164. $ErrMsg[1 ] = "Invalid Arguments.";
  165. $ErrMsg[2 ] = "Could not bind to the DC.";
  166. $ErrMsg[3 ] = "Could not find 'NTDS Settings' object. Check the host site\\server parameter.";
  167. $ErrMsg[4 ] = "Could not find 'NTDS Settings' object. Check the from site\\server parameter.";
  168. $ErrMsg[5 ] = "Error creating connection.";
  169. $ErrMsg[6 ] = "Connection already exists.";
  170. $ErrMsg[7 ] = "Error updating connection.";
  171. $ErrMsg[8 ] = "Error updating connection; connection not found.";
  172. $ErrMsg[9 ] = "Error updating connection; duplicate connections found.";
  173. $ErrMsg[10] = "Error deleting connection.";
  174. $ErrMsg[11] = "Error deleting connection; connection not found.";
  175. $ErrMsg[12] = "Deleting multiple connection.";
  176. $ErrMsg[13] = "Error dumping connection.";
  177. $ErrMsg[14] = "Error dumping; connection not found.";
  178. $ErrMsg[15] = "Dumping duplicate connections.";
  179. #
  180. # Valid commands with number of required params.
  181. #
  182. $cmdtab{"/dc"} = 1;
  183. $cmdtab{"/schedmask"} = 1;
  184. $cmdtab{"/schedoverride"} = 1;
  185. $cmdtab{"/debug"} = 0;
  186. $cmdtab{"/verbose"} = 0;
  187. $cmdtab{"/auto_cleanup"} = 0;
  188. $cmdtab{"create"} = 4;
  189. $cmdtab{"update"} = 4;
  190. $cmdtab{"del"} = 2;
  191. $cmdtab{"dump"} = 2;
  192. $linenumber = 0;
  193. $InFile = "";
  194. unlink $redo;
  195. $redo_cnt = 0;
  196. $cleanup = 0;
  197. while (<>) {
  198. if ($InFile ne $ARGV) {
  199. $InFile = $ARGV;
  200. printf("Processing file %s \n\n", $InFile);
  201. $linenumber = 0;
  202. }
  203. $linenumber++;
  204. $cleancmd = "";
  205. chop;
  206. ($func, @a) = split;
  207. if (($func eq "") || ($func =~ m/^#/)) {next;}
  208. #
  209. # check for valid command and for missing or extraneous parameters.
  210. #
  211. $func = lc($func);
  212. if (!exists($cmdtab{$func})) {
  213. printf("Line %d: Error: %s unrecognized command.\n%s\n\n", $linenumber, $func, $_);
  214. goto ERROR;
  215. }
  216. $numargs = $cmdtab{$func};
  217. #
  218. # Are there any optional params present?
  219. #
  220. $option = ""; $optionarg = "";
  221. if ($a[$numargs] =~ m/\/dc/i) {
  222. $option = $a[$numargs]; $optionarg = $a[$numargs+1];
  223. $numargs += 2;
  224. }
  225. if (($a[$numargs] ne "") && !($a[$numargs] =~ m/^#/)) {
  226. printf("Line %d: Error: %s has extraneous or missing parameters - skipping\n%s\n\n", $linenumber, $func, $_);
  227. goto ERROR;
  228. }
  229. $i = $numargs;
  230. while ($i-- > 0) {
  231. if (($a[i] eq "") || ($a[$i] =~ m/^#/)) {
  232. printf("Line %d: Error: %s missing parameters - skipping\n%s\n\n", $linenumber, $func, $_);
  233. goto ERROR;
  234. }
  235. }
  236. #
  237. # func a0 a1 a2 a3 a4
  238. # Host Server From Server Enabled Schedule option
  239. # create site\\server site\\server on|off s-ii-cc-pp [/dc dcname] # comment
  240. # update site\\server site\\server on|off s-ii-cc-pp [/dc dcname] # comment
  241. #
  242. # /dc <default computer name of DC on which to create the connection objects>
  243. # /auto_cleanup
  244. # /debug
  245. # /schedmask <file>
  246. # /schedoverride <file>
  247. if ($func =~ m/\/dc/i) {
  248. $dcname = "/dc $a[0]";
  249. printf("Default DC name change: %s\n", $a[0]);
  250. next;
  251. }
  252. if ($func =~ m/\/schedmask/i) {
  253. $schedmask = "/schedmask $a[0]";
  254. printf("schedmask change: %s\n", $a[0]);
  255. next;
  256. }
  257. if ($func =~ m/\/schedoverride/i) {
  258. $schedoverride = "/schedoverride $a[0]";
  259. printf("schedoverride change: %s\n", $a[0]);
  260. next;
  261. }
  262. if ($func =~ m/\/auto_cleanup/i) {
  263. printf("Automatic cleanup (i.e. delete) of old connections under each site\server is enabled.\n");
  264. $cleanup = 1;
  265. next;
  266. }
  267. if ($func =~ m/\/debug/i) {
  268. printf("Debug mode enabled. DC modifications supressed.\n");
  269. $debugmode = "/debug";
  270. next;
  271. }
  272. if ($func =~ m/\/verbose/i) {
  273. printf("Verbose mode enabled.\n");
  274. $verbosemode = "/v";
  275. next;
  276. }
  277. $host = $a[0]; $fromsrv = $a[1]; $enable = $a[2]; $sched = $a[3];
  278. ($host_site, $host_srv) = split(/\\/, $host);
  279. ($from_site, $from_srv) = split(/\\/, $fromsrv);
  280. #
  281. # check for correct number of parameters.
  282. #
  283. if (($host_site eq "") || ($host_srv eq "")) {
  284. printf("Line %d: Error: Host Site or Server is null - skipping\n%s\n\n", $linenumber, $_);
  285. goto ERROR;
  286. }
  287. if (($from_site eq "") || (($from_srv eq "") && ($from_site ne "*"))) {
  288. printf("Line %d: Error: Host Site or Server is null - skipping\n%s\n\n", $linenumber, $_);
  289. goto ERROR;
  290. }
  291. #
  292. # check for DC override option.
  293. #
  294. $binddc = $dcname;
  295. if ($option =~ m/\/dc/i) {
  296. $binddc = "/dc $optionarg";
  297. }
  298. #
  299. # build function call for create / update commands.
  300. #
  301. if ($func =~ m/create|update/i) {
  302. if ($from_site eq "*") {
  303. printf("Line %d: From site of \"*\" not allowed for %s command - skipping\n%s\n\n",
  304. $linenumber, $func, $_);
  305. goto ERROR;
  306. }
  307. if (!($enable =~ m/on|off/i)) {
  308. printf("Line %d: Third parameter of %s command must be 'on' or 'off' - skipping\n%s\n\n",
  309. $linenumber, $func, $_);
  310. goto ERROR;
  311. }
  312. $enable_arg = ($enable =~ m/on/i) ? "/enable" : "/disable";
  313. if (!($sched =~ m/s\-[0-9]+\-[0-9]+\-[0-9]+/i)) {
  314. printf("Line %d: Fourth parameter of %s command must be s-iii-ccc-ppp - skipping\n%s\n\n",
  315. $linenumber, $func, $_);
  316. goto ERROR;
  317. }
  318. ($junk, $iii, $ccc, $ppp) = split(/-/, $sched);
  319. if ($ppp >= $ccc) {
  320. printf("Line %d: Fourth parameter of %s command s-iii-ccc-ppp, ppp must be less than ccc - skipping\n%s\n\n",
  321. $linenumber, $func, $_);
  322. goto ERROR;
  323. }
  324. #
  325. # Make up a delete command if we are auto cleaning old connections.
  326. #
  327. if ($cleanup && ($func =~ m/create/i) && !$hostcleaned{$host}) {
  328. $cleancmd = "$mkdsx $binddc $debugmode $verbosemode \
  329. /del /tosite $host_site /toserver $host_srv /all";
  330. }
  331. #
  332. # Remember that we have done either a create or update against this
  333. # host site\server so it is done only once. In particular if we
  334. # see an update command for a host before the first create for the host
  335. # we will NOT do a cleanup on that host if we see a create for it later.
  336. #
  337. $hostcleaned{$host} += 1;
  338. #
  339. # Make a cxtion name if a create.
  340. #
  341. $name_arg = ($func =~ m/create/i) ? "/name From-$from_site-$from_srv" : "";
  342. $mcmd = "$mkdsx $binddc $debugmode $verbosemode /$func $name_arg $enable_arg \
  343. /tosite $host_site /toserver $host_srv \
  344. /fromsite $from_site /fromserver $from_srv \
  345. /schedule $iii $ccc $ppp $schedmask $schedoverride";
  346. }
  347. #
  348. # build function calls for del / dump commands.
  349. #
  350. # func a0 a1 a2 a3
  351. # del site\\server site\\server|* [/dc dcname] # comment
  352. # dump site\\server site\\server|* [/dc dcname] # comment
  353. #
  354. if ($func =~ m/del|dump/i) {
  355. $fromarg = ($from_site eq "*") ? "/all" : "/fromsite $from_site /fromserver $from_srv";
  356. $mcmd = "$mkdsx $binddc $debugmode $verbosemode /$func \
  357. /tosite $host_site /toserver $host_srv $fromarg ";
  358. }
  359. #
  360. # Do the operation on the connection.
  361. #
  362. if ($verbosemode ne "" ) {printf("\n");}
  363. printf("%s\n", $_);
  364. if ($cleancmd ne "") {
  365. #
  366. # Do the cleanup command first to delete old connections on this site\server.
  367. #
  368. if ($verbosemode ne "") {printf("\nRunning autoclean:\n%s\n", $cleancmd)};
  369. $rc = system ($cleancmd) / 256;
  370. if ($rc != 0) {
  371. printf("Line %d: Status return from mkdsx.exe (%d) - %s - for auto cleanup command. Continuing.\n",
  372. $linenumber, $rc, $ErrMsg[$rc]);
  373. }
  374. }
  375. if ($verbosemode ne "" ) {printf("\nRunning:\n%s\n", $mcmd)};
  376. $rc = system ($mcmd) / 256;
  377. if ($rc != 0) {
  378. printf("Line %d: Error from mkdsx.exe (%d) - %s - skipping\n%s\n\n",
  379. $linenumber, $rc, $ErrMsg[$rc], $_);
  380. ++$redo_cnt;
  381. goto REDO_CMD;
  382. }
  383. next;
  384. ERROR:
  385. #
  386. # append command record to redo file.
  387. #
  388. $errorcount += 1;
  389. REDO_CMD:
  390. open(REDO, ">>$redo");
  391. #
  392. # put options out first.
  393. #
  394. if ($redo_cnt == 1) {
  395. $time = scalar localtime;
  396. printf REDO ("#Time generated: %s\n", $time);
  397. print REDO "$dcname \n";
  398. print REDO "/auto_cleanup \n" if ($cleanup == 1);
  399. print REDO "/debug \n" if ($debugmode ne "");
  400. print REDO "/verbose \n" if ($verbosemode ne "");
  401. print REDO "$schedmask\n" if ($schedmask ne "");
  402. print REDO "$schedoverride\n" if ($schedoverride ne "");
  403. print REDO "# \n";
  404. }
  405. print REDO "$_\n";
  406. close(REDO);
  407. } # end while()
  408. printf("WARNING: %d command(s) were invalid and not performed. They were written to the Redo File: %s\n",
  409. $errorcount, $redo) if ($errorcount > 0);
  410. printf("WARNING: %d command(s) failed their connection operation. They were written to the Redo File: %s\n",
  411. $redo_cnt, $redo) if ($redo_cnt > 0);
  412. __END__
  413. :endofperl
  414. @perl %~dpn0.cmd %*