Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.
On Netware servers, a CONFIG.NLM program can be run to produce a concise comprehensive server configuration report file CONFIG.TXT, which is useful for server documentation, disaster recovery, etc.
This program collects such files from servers specified in an internal list (the CONFIG.NLM is being run by someone/something else on a regular basis, so all this program needs to do is collect the resulting files) and consolidates them into a single compressed (.zip) file.
Additional code exists in the program, but is commented out, for:
- querying NDS for a list of server names (would need to add exemption/filter logic to protect against trying to access problematic/virtual/etc. servers) - remotely executing the CONFIG.NLM program on those servers (so as to assure up to the minutes results in the files being collected)Offered as is. Be sure to review thoroughly and adapt and test to your own situation. Use at your own risk. Not responsible for damage, loss of business, etc
;============================================================================================= ; program: NDS Servers Configurations ; ; language: WinBatch ; extenders: NetwareX WWNWX34I.DLL ; Zip Extender WWZIP34I.DLL ; ; author: Michael Harris ; created: 6/24/2003 last updated: 7/07/2003 ; ; description: ; Can be run interactively or batch. (Note: Batch mode has not been tested) ; Ultimately, could query NDS for all server objects (code exists below but is commented out) ; (if did, would need an exemption/filtering mechanism to exempt problematic, non-Netware, ; virtual, etc. servers) ; (but for now will work from hard coded list of server names, for testing and safety sake) ; Could load/run Novell's CONFIG.NLM on each server in the list (code for this exists below ; but is commented out) but aren't, as CONFIG.NLM appears to be being run at least weekly ; on our Netware 5/6 servers (by what?) ; So, what this program currently does is.... ; collect and combine all the server configuration report files (CONFIG.TXT, plain text) ; (both the NLM and TXT file are in each server's SYS:SYSTEM volume/directory) ; and combine/save them out as a single compressed (zip format) file ; to facilitate storage/e-mail off-site for routine server analysis/documentation ; and disaster recovery. ; ; output file location/name: ; Currently, location is specified in FilePathDefaultValue ; and file name is ; "NDS Servers Configurations %CurrentTimeYmdHmsWithBlanks%.zip" ;============================================================================================= ;================================ SET DEFAULT VALUES HERE ==================================== ; Default Values ;NDSTree = '\\ACME_TREE\' ;UNC = '.ACME' ; command line argument #1 (param1) LocalTempDirectory = "c:\winnt\temp" ; for incrementally building the zip file ;FilePathDefaultValue = 'F:\Winbatch\' ; for testing FilePathDefaultValue = '\\R999_server\V999\groups\Isd_techservices\WinBatch\Reports\' DialogTitle = 'NDS Servers Configurations' ;SpreadsheetDelimiter = @TAB MappedDrive = 'L:' ; Manually built server list (for testing and safety purposes, until/unless get comfortable ; with letting this program loose on all servers.... ; if were to loose on all servers, would need an exclusion table for specific servers ; to be excluded (example: CD-ROM server that is not really a Netware server), ; plus generic/wildcard exclusions for virtual servers associated ; with cluster(?) and/or storage array network(SAN)(?)) ; (note: all of the ServerList = StrCat.... lines should have @TAB delimiter at their end, ; except for the last one.... (it servers as the list delimiter character)) ServerList = "" ServerList = StrCat(ServerList, ".XYZISD3.Email.ACME", @TAB) ServerList = StrCat(ServerList, ".S_XYZ_00.ISD.ADM.ACME", @TAB) ServerList = StrCat(ServerList, ".S_FLD_01.FLD.REG.ACME") ; remember, no @TAB on end of last server name above ;DiagnosticLine = StrCat("ServerList = ", ServerList) ;Message(DialogTitle, DiagnosticLine) ;============================================================================================= ;===================================== HOUSEKEEPING ========================================= ; tolerate errors.... necessary for NDS processing? ; (could turn this on and off more selectively, as needed.....) ErrorMode(@OFF) ; load WinBatch's NetwareX extension AddExtender('WWNWX34I.DLL') ; load WinBatch's Zip Extender extension AddExtender("WWZIP34I.DLL") ; tell NetwareX to return typeless names from NDS nwSetOptions(1, @TRUE) ; make user defined functions (UDFs below) defined/known to WinBatch interpreter ; (otherwise, must place them here, above/ahead of the code that calls/invokes them) Gosub DefineUDFs ; interpreter scans UDFs then returns here ; ; so that UDFs can be placed below main code ;============================================================================================= ;============================== MAIN PROGRAM LOGIC STARTS HERE =============================== ; open message box and report program start MessageLine = "Running..." BoxOpen(DialogTitle, MessageLine) ; assure valid number of command line arguments (0 for interactive, 1 for batch/command line) If ((param0 < 0) || (param0 > 1)) ; invalid number, report and wait for user acknowledgement and terminate the program MessageLine = StrCat("ERROR: Invalid number of command line arguments = ", param0) Pause(DialogTitle, MessageLine) Exit Endif ; get valid base object specification for NDS search filter from user or command line ; (NDS tree plus UNC (.context or .server.context)) ;BaseObjectSpec = udfGetValidUNC(NDSTree, UNC, DialogTitle, param0) ; NOTE: at this point BaseObjectSpec has the tree name prefixed on it ; get list of server(s) within/that satisfy base object specification ; use what was entered as base object specification for search of NDS for servers ; (which may return zero, one or more servers) ; (server object name(s) in list will be typless, distinguished, tab delimited, unsorted) ; get the list of servers ;ServerList = udfGetServerList(BaseObjectSpec) ; (note that server names in list do not have NDS tree name prefix.... ; as are not returned by nwSearchObjects...... ; we'll re-prefix later when mapping drives) ; diagnostic, if needed ; INSTEAD, for testing and safety sake, until sure we want to turn this loose on all servers, ; let's employ a manually built a list of servers (see top of program) ; NOTE: Do not concatenate @TAB on end of last server name. ; remove servers from the list that should not be processed (i.e. virtual servers, etc.) ; ............ ; sort the server list ServerList = ItemSort(ServerList, @TAB) ;DiagnosticLine = StrCat("sorted ServerList = ", ServerList) ;Message(DialogTitle, DiagnosticLine) ; generate output zip (compressed) file name CurrentTimeYmdHmsWithBlanks = StrReplace(TimeYmdHms(), ":", " ") OutputZipFileName = StrCat(DialogTitle, " On ", CurrentTimeYmdHmsWithBlanks, ".zip") ; capture and display server list processing start time ServerListStartTimeYmdHms = TimeYmdHms() MessageLine = StrCat(MessageLine, @CR, "Server List Processing Start Time ", ServerListStartTimeYmdHms) BoxText(MessageLine) ; get count of servers in the list ServerCount = ItemCount(ServerList, @TAB) MessageLine = StrCat(MessageLine, @CR, "Number Of Servers To Be Processed ", ServerCount) ; process servers in the list (note: list starts at 1 (not at 0 like arrays do)) For ServerIndex = 1 to ServerCount by 1 ;ServerStartTimeYmdHms = TimeYmdHms() ServerName = ItemExtract(ServerIndex, ServerList, @TAB) ProgressLine = StrCat(MessageLine, @CR, "Processing server ", ServerIndex, " of ", ServerCount, " ", ServerName) BoxText(ProgressLine) ;DiagnosticLine = StrCat("ServerList[", ServerIndex, "] = ", ServerName) ;Message(DialogTitle, DiagnosticLine) ;ServerSpec = StrCat(NDSTree, ServerName) ;NLMName = "CONFIG.NLM" ; NOTE: FOLLOWING "RUN CONFIG.NLM" CODE COMMENTED OUT, AS IT IS ALREADY BEING RUN ; BY ?????? ON OUR NETWARE 5/6 SERVERS AT LEAST WEEKLY ; run CONFIG.NLM (unless is already running, in which (unlikely) case we don't need to) ;If (nwGetNLMInfo(ServerSpec, 17, NLMName) == "") ; ; CONFIG.NLM is not already running (otherwise, would have returned an integer NLM ID) ; ; so go ahead and load it ; NLMStartTimeYmdHms = TimeYmdHms() ; Result = nwSrvNLMMgr(ServerSpec, 1, NLMName) ; ;ResultCode = LastError() ; ;If ((Result != @TRUE) || (ResultCode != 0)) ; If (Result != @TRUE) ; ; NLM failed to load ; DiagnosticLine = StrCat("CONFIG.NLM load failed for ", ServerName) ; DiagnosticLine = StrCat(DiagnosticLine, " Result = ", Result) ; DiagnosticLine = StrCat(DiagnosticLine, " ResultCode = ", ResultCode) ; Message(DialogTitle, DiagnosticLine) ; ; give up on this server and go back to top of for loop and process the next server ; Continue ; Else ; ; NLM loaded ; ; wait for it to finish, using a loop and delays measured in seconds ; TimeDelay(5) ; NLMIDNumber = nwGetNLMInfo(ServerSpec, 17, NLMName) ; ;DiagnosticLine = StrCat("NLMIDNumber = ", NLMIDNumber, " for ", NLMName, " on ", ServerSpec) ; ;Message(DialogTitle, DiagnosticLine) ; ;While (IsNumber(nwGetNLMInfo(ServerSpec, 17, NLMName)) ; While (IsNumber(NLMIDNumber)) ; TimeDelay(5) ; NLMIDNumber = nwGetNLMInfo(ServerSpec, 17, NLMName) ; ;DiagnosticLine = StrCat("NLMIDNumber = ", NLMIDNumber, " for ", NLMName, " on ", ServerSpec) ; ;Message(DialogTitle, DiagnosticLine) ; EndWhile ; append this server's SYS:\SYSTEM\CONFIG.TXT file into the output zip file by ; generating \\servername\vol\path\ to server's SYS:SYSTEM\ location of the CONFIG.TXT file ServerSysSystemFilenameUNC = StrCat("\\", ItemExtract(2,ServerName,"."), "\sys\system\") ; and map rooting a drive letter to that location (for use by FileCopy command) nwMap(ServerSysSystemFilenameUNC, MappedDrive, 0) ; diagnostic line to verify getting to server's sys:system ;dir1=AskDirectory(MappedDrive, "L:", "","",0) ; and generating a full drive:filename sourcename for use by the FileCopy SourceDriveFileName = StrCat(MappedDrive, "config.txt") ; and generating a full drive:path\filename targetname for use by the FileCopy TargetDrivePathFileName = StrCat(LocalTempDirectory, "\", ItemExtract(2,ServerName,"."), ".txt") ; and simple filename targetname for use by the zZipFiles TargetFileName = StrCat(ItemExtract(2,ServerName,"."), ".txt") ; and copying it a local location, with a unique file name) FileCopy(SourceDriveFileName, TargetDrivePathFileName, @FALSE) ; should error check the filecopy? ; append the copied file into output zip file (which will be created for first server) origdir = DirGet() DirChange(LocalTempDirectory) ;ZippedFilesList = zZipFiles("j", OutputZipFileName, TargetFileName, "") zZipFiles("j", OutputZipFileName, TargetFileName, "") ; delete the temporary local copy of the server config file, now that it is in the zip file FileDelete(TargetFileName) DirChange(origdir) ; should error check the zZipFiles? ; NOTE: FOLLOWING NLMENDTIME COMMENTED OUT AS ARE NOT RUNNING CONFIG.NLM ;NLMEndTimeYmdHms = TimeYmdHms() ;NLMElapsedTimeMinutes = TimeDiffSecs(NLMEndTimeYmdHms, NLMStartTimeYmdHms) / 60 ;DiagnosticLine = StrCat("NLMElapsedTimeMinutes for ", ServerName, " = ", NLMElapsedTimeMinutes) ;Message(DialogTitle, DiagnosticLine) ;Endif ; commented out as not running/checking CONFIG.NLM on servers (see above) ;Endif ; commented out as not running/checking CONFIG.NLM on servers (see above) ;ServerEndTimeYmdHms = TimeYmdHms() ;ServerElapsedTimeMinutes = TimeDiffSecs(ServerEndTimeYmdHms, ServerStartTimeYmdHms) / 60 ;DiagnosticLine = StrCat("ServerElapsedTimeMinutes for ", ServerName, " = ", ServerElapsedTimeMinutes) ;Message(DialogTitle, DiagnosticLine) Next ; all servers' config files are now consolidated in the zip file ; copy the zip file from c:\winnt\temp to located specified in FilePathDefaultValue origdir = DirGet() DirChange(LocalTempDirectory) FileCopy(OutputZipFileName, FilePathDefaultValue, @FALSE) FileDelete(OutputZipFileName) DirChange(origdir) ; capture server list processing end time ServerListEndTimeYmdHms = TimeYmdHms() MessageLine = StrCat(MessageLine, @CR, "Server List Processing End Time ", ServerListStartTimeYmdHms) ; determine elapsed server list processing time ServerListElapsedTimeMinutes = Int((TimeDiffSecs(ServerListEndTimeYmdHms, ServerListStartTimeYmdHms) / 60) + 1.0) MessageLine = StrCat(MessageLine, @CR, "Server List Processing Elapsed Time Of ", ServerListElapsedTimeMinutes, " Minutes") ;DiagnosticLine = StrCat("ServerListElapsedTimeMinutes = ", ServerListElapsedTimeMinutes) ;Message(DialogTitle, DiagnosticLine) ; close the message box BoxShut() ; report the results, via message requiring user acknowledgement If (param0 == 0) MessageLine = StrCat("DONE.", @CR) MessageLine = StrCat(MessageLine, "Processed ", ServerCount, " servers", @CR) MessageLine = StrCat(MessageLine, "Elapsed time in minutes ", ServerListElapsedTimeMinutes, @CR) MessageLine = StrCat(MessageLine, "Output file is ", FilePathDefaultValue, OutputZipFileName) Message(DialogTitle, MessageLine) Endif ; end the program Exit ;=============================== MAIN PROGRAM LOGIC ENDS HERE ================================ ;============================ DEFINE USER DEFINED FUNCTIONS (UDFs) ================================= :DefineUDFs ; label for interpreter's gosub fallthru of UDFs ; ; so that UDFs can be placed below main code ; ; (interpreter must apparently scan user defined ; ; functions before they can be called..... doing this ; ; would not be necessary if user defined functions ; ; were placed ahead of/above main program logic ; ; as interpreter would then do a fall-thru scan ; ; before hitting and executing the main logic ;=================================================================================================== ; note: Function variables are local, subroutine variables are global. ; The user array allocated at the top of the program is global (address is passed, not contents) ; (must explicitely pass it, but don't have to return it.... contents persist across functions). ; ;--------------------------------------------------------------------------------------------------- ; #DefineFunction udfGetValidUNC(NDSTree, UNC, DialogTitle, param0) ; get valid base object specification for NDS search filter ; (NDS tree plus user supplied UNC (.context or .server.context)) ; being run interactively or batch/command line ? If (param0 == 0) ; interactively (no command line arguments were supplied) UNCEntered = "" NDSTreeUNCEntered = "" ResultCode = 1 ; loop till get valid base object specification from user While ((ResultCode != 0) || (IsNumber(UNCEntered)) || (StrSub(UNCEntered, 1, 1) != ".")) MessageLine = "NDS .context or .server.context " MessageLine = StrCat(MessageLine, "within ", NDSTree, " ?") ;MessageLine = StrCat(MessageLine, @CR, "CAUTION: Multiple servers will be slow.") UNCEntered = AskLine(DialogTitle, MessageLine, UNC) ; concatenate NDS tree plus user supplied UNC (.context or .server.context) NDSTreeUNCEntered = StrCat(NDSTree, UNCEntered) ; verify that .context or .server.context portion of UNC supplied exists nwGetObjInfo(NDSTreeUNCEntered, 2) ResultCode = LastError() ; determine if not found or if user entered grossly illegal UNC (all numeric or contains no period) If ((ResultCode != 0) || (IsNumber(UNCEntered)) || (StrSub(UNCEntered, 1, 1) != ".")) MessageLine = "ERROR: NDS .context or .server.context" MessageLine = StrCat(MessageLine, "You entered = ", UNCEntered) Message(DialogTitle, MessageLine) Endif Endwhile Else ; batch/command line execution (not interactive) ; UNC (.context or .server.context) supplied as first command line argument UNCEntered = param1 ; concatenate NDS tree plus supplied UNC (.context or .server.context) NDSTreeUNCEntered = StrCat(NDSTree, UNCEntered) ; verify that .context or .server.context portion of UNC supplied exists nwGetObjInfo(NDSTreeUNCEntered, 2) ResultCode = LastError() ; determine if not found or if user entered grossly illegal UNC (all numeric or contains no period) If ((ResultCode != 0) || (IsNumber(UNCEntered)) || (StrSub(UNCEntered, 1, 1) != ".")) ; for batch/command line run, should error message go to console or to report file? ; for now, display it on the screen and wait for user acknowledgement and terminate the program MessageLine = "ERROR: NDS .context or .server.context " MessageLine = StrCat(MessageLine, NDSTreeUNCEntered, " not found! Abending!") Pause(DialogTitle, MessageLine) ; end the program Exit Endif Endif ; return valid base object specification for NDS search Return (NDSTreeUNCEntered) #EndFunction ; ;---------------------------------------------------------------------------------------------------- ; #DefineFunction udfGetServerList(BaseObjectSpec) ; get (unsorted) list from NDS of server objects that satisfy the base object specification ; set up a search filter ; (is cumulative... use *FREE_BUFFER* to reset/deactivate) ; (source of attribute names was the NDS Snoop program.... ; see www.novell.com/coolsolutions/tools/1005.html) ; (another source of attribute names is the output displayed by the example ; WinBatch program supplied in the nwGetObjValue writeup in the NetwareX help) nwSearchFilter(BaseObjectSpec, 'BASECLS','',0,0,0) nwSearchFilter(BaseObjectSpec, 'ANAME','NCP Server',0,0,0) nwSearchFilter(BaseObjectSpec, 'END','',0,0,0) ; set up search flags (combine/add various bit flag values) ; value of 2 says search scope is base-object and all its subordinates Flags = 2 ; tell WinBatch's NetwareX extensions to return typeless names from NDS nwSetOptions(1,@TRUE) ; do the search and get the result code ServerListDistinguishedTabbed = nwSearchObjects(BaseObjectSpec, '', '', Flags, '') ResultCode = LastError() ; verify that search was ok If (ResultCode != 0) ; diagnostic (if needed) report result code MessageLine = StrCat("Servers search failed with result code = ", ResultCode) ;Message(DialogTitle, MessageLine) Message("NDS Servers Configurations", MessageLine) ; End the program Exit Endif ; reset/deactivate the search filter (don't need when done with nwSearchObjects) nwSearchFilter('', '*FREE_BUFFER*', '', 0, 0, 0) ; diagnostic (if needed) ;Message("NDS Servers Configuration", ServerListDistinguishedTabbed) ; diagnostic program termination (if needed) ;exit ; return list of volume objects found Return (ServerListDistinguishedTabbed) #EndFunction ; ;=================================================================================================== Return ; return from interpreter's gosub fallthru of UDFs ; ; so that UDFs can be placed below main code ;===================================================================================================
Article ID: W16057
File Created: 2004:03:30:15:42:38
Last Updated: 2004:03:30:15:42:38