//////////////////////////////////////////////////////////////////////////////// // // Task: MIGRATE.TSK // (Move files with defined pattern(s) / last modifed age to a volume.) // Author: Avanti Technology, Inc. // http://www.avanti-tech.com // Version: 1.0 - Initial Release // 1.1 - Fix parsing problem with some remote destinations & optimize // 1.2 - Enhanced to support migrating files from 0001-9999 days old // // Description: // ============ // Search for files matching specific extensions which were last modified more // than a defined number of days ago then migrate them to an archive volume, // maintaining original directory tree structure. // // Objective: // ========== // Automate File System cleanup. // // Usage: // ====== // Script can be manually executed using the TaskMaster TMRUN command // at the TMConsole (Shell) Screen: // // Example: TMRUN [vol:path\]MIGRATE.TSK // // Note: [vol:path\] is not required if the task resides either // in SYS:SYSTEM or the TaskMaster NLM load directory. // // Script can be scheduled for automatic execution using Client interface or // using the TaskMaster TMSCHEDULE command at the TMConsole (Shell) Screen: // // Examples: TMSCHEDULE ADD MIGRATE.TSK 01 02:00 // (Executes the 1st of each month at 2:00am) // // TMSCHEDULE ADD MIGRATE.TSK YNNNNNN 02:00 // (Executes every Sunday [SMTWTFS] at 2:00am) // // Note: Scheduled tasks must reside either in SYS:SYSTEM or the // TaskMaster NLM load directory for security reasons. // // Compatibility: // ============== // This task has been tested on the following platforms without demonstrating // any compatibility issues or any other reported/confirmed conflicts: // TaskMaster v4.05 (or later) // NetWare v4.1x / v5.x / v6.x // // Warning: // ======== // AS WITH ANY NEW SOFTWARE PROGRAM, BATCH SCRIPT, OR AUTOMATED PROCESSING // PROCEDURE, CAUTION SHOULD BE EXERCISED AND DUE DILIGENCE OBSERVED DURING // INITIAL IMPLEMENTATION. WHERE POSSIBLE, TESTING SHOULD BE PERFORMED ON // NON-PRODUCTION SYSTEMS PRIOR TO FULL IMPLEMENTATION. // //////////////////////////////////////////////////////////////////////////////// // Check for compatible version of TaskMaster NLM IF "%TM_VERSION%.%TM_SUBVERSION%%TM_REVISION%"<"4.05" // Report the status ECHO. ECHO Error: Incompatible TaskMaster release (requires v4.05 or later)! ECHO. ABORT ENDIF // Declare the task variables to be used VARALIAS %VAR10% %SRC_PATH% VARALIAS %VAR11% %DST_PATH% VARALIAS %VAR12% %RSERVER% VARALIAS %VAR13% %DAYS_OLD% // Define the default contents of the declared task variables // // All three of the following parameters can be passed on the command line // (in the same order as defined). If no command line parameters are provided // the default THEN DEFINE deinitions are used (must be specified for default). // (MODIFY) Definition which follows must be modified appropriately: // Source directory for processing (do not include trailing separator '\') // // Notes: Set the default source (VOL:) as appropriate. IF '%SRC_PATH%'=='' THEN DEFINE %SRC_PATH% VOL:PATH // Insure source specification does not include trailing separator ('\') // (Get spec length then check if last char is '\' and parse out if true.) FINDLEN %9 "%SRC_PATH%" PARSE %8 %SRC_PATH% %9-%9 IF '%8'=='\' DEFINE %9 %9-=1 PARSE %SRC_PATH% %SRC_PATH% 1-%9 ENDIF // (MODIFY) Definition which follows must be modified appropriately: // Destination directory for processing (do not include trailing separator '\') // // Notes: Set the default destination (RSERVER/ARCVOL:) as appropriate. // If the destination (%DST_PATH%) is on the local Server (i.e., same // Server as the source) then the Server specification is not required // (i.e., use the Volume substituted for ARCVOL: only). // Be sure to use a forward slash (/) for the Server/Volume: separator // and a backward slash (\) for any Server/Volume:\Path path separators. IF '%DST_PATH%'=='' THEN DEFINE %DST_PATH% RSERVER/VOL:\PATH // Insure destination specification does not include trailing separator ('\') // (Get spec length then check if last char is '\' and parse out if true.) FINDLEN %9 "%DST_PATH%" PARSE %8 %DST_PATH% %9-%9 IF '%8'=='\' DEFINE %9 %9-=1 PARSE %DST_PATH% %DST_PATH% 1-%9 ENDIF // Check if dest is Local (i.e., ARC_VOL:) or Remote (i.e., RSERVER/ARC_VOL:) // by scanning for a forward slash (/). If FINDCHR returns a 0 (not found), // scan for a backward slash (\), in case Server\Volume: incorrectly used. // If either exist and return a position (3 digit fixed, zero filled format) // prior to the colon (:) volume separator, parse the Remote Server name FINDCHR %7 "\" "%DST_PATH%" FINDCHR %8 "/" "%DST_PATH%" FINDCHR %9 ":" "%DST_PATH%" REFORMAT %7 3 RIGHT REPLACE %7 " 0" REFORMAT %8 3 RIGHT REPLACE %8 " 0" REFORMAT %9 3 RIGHT REPLACE %9 " 0" IF "%7">"000" AND "%7"<"%8" THEN DEFINE %8 %7 IF "%8">"000" AND "%8"<"%9" DEFINE %8 %8-=001 PARSE %RSERVER% %DST_PATH% 1-%8 DEFINE %8 %8+=002 FINDLEN %9 "%DST_PATH%" PARSE %DST_PATH% %DST_PATH% %8-%9 ENDIF // (MODIFY) Definition which follows must be modified appropriately: // Cut off date for processing (in days) // // Note: Valid supported range is 1-9999. IF '%DAYS_OLD%'=='' THEN DEFINE %DAYS_OLD% 3650 // Insure cut off date is 4 digit fixed length and zero filled for comparison DEFINE %DAYS_OLD% 0000+=%DAYS_OLD% // Store the current year for processing to calendar date DEFINE %8 %YEAR% // Store max age (%DAYS_OLD%) in temporary variable for processing DEFINE %9 %DAYS_OLD% // Check if max age is more than one year (365 days) and adjust year accordingly WHILE %9>365 DEFINE %9 %9-=365 DEFINE %8 %8-=1 LOOP // Store %NDAY_OF_YEAR% (3 digit value - 001-365) is %7 as 4 digit value (0001-0365) DEFINE %7 0000+=%NDAY_OF_YEAR% // Check if the current day of year is less than the max age // If so, dec year then sub max age from current day plus 365 (dec year) // else subtract max age from current day IF %7<%9 CALC %9 (%NDAY_OF_YEAR% + 365) - %9 DEFINE %8 %8-=1 ELSE CALC %9 %NDAY_OF_YEAR% - %9 ENDIF // Convert calculated day of year (4 digit value) to required 3 digit format DEFINE %9 000+=%9 // Converted adjusted year and day of year to calendar date TOCALENDAR %7 %8%9 // Define a variable to store the cut off date for processing matching files VARALIAS %VAR14% %MAX_DATE% // Parse converted date into day (%9), month (%8), and year (%MAX_DATE%) PARSE %9 %7 7-8 PARSE %8 %7 5-6 PARSE %MAX_DATE% %7 1-4 // Merge the date fields into %MAX_DATE% in same format DIR /T= requires DEFINE %MAX_DATE% %MAX_DATE%/%8/%9 // Define remaining variables used for processing VARALIAS %VAR15% %SRC_SPEC% VARALIAS %VAR16% %DST_SPEC% VARALIAS %VAR17% %BEG_POS% VARALIAS %VAR18% %CHR_POS% VARALIAS %VAR19% %COUNT% VARALIAS %VAR20% %ERRORS% VARALIAS %VAR21% %SIZE_KB% VARALIAS %VAR22% %SIZE_MB% // Zero counter, errors, and size variables DEFINE %COUNT% 0 DEFINE %ERRORS% 0 DEFINE %SIZE_KB% 0000000000 DEFINE %SIZE_MB% 0000000000 // (MODIFY) The command which follows may be modified as appropriate: // File search and logging is easier/quicker using DIR due to new options in v4 // The default file specification in this .TSK is *.* which matches all files. // The different file specification can be changed (i.e., *.bak, *.tmp, etc.). // Process multiple file types by adding multiple DIR commands, using a specific // search pattern for each DIR, and appending >> to the log after the first DIR. // Note: The first DIR must use new/truncated redirection (i.e., > [single]). // Any subsequent DIR should use append redirection (i.e., >> [double]). // // Example: // // DIR %SRC_PATH%\*.bak /B /-D /S /T=M-%MAX_DATE% >%TASK_PATH%\%TASK_FILE%.DIR // (Using > creates/overwrites the log) // // DIR %SRC_PATH%\*.old /B /-D /S /T=M-%MAX_DATE% >>%TASK_PATH%\%TASK_FILE%.DIR // (Using >> appends to existing log) // // DIR %SRC_PATH%\*.tmp /B /-D /S /T=M-%MAX_DATE% >>%TASK_PATH%\%TASK_FILE%.DIR // (Using >> appends to existing log) // // // The following options are required: // // /B - Bare (file name only, includes full path if /S is specified) // /-D - Directories excluded (list files only) // // // The following options can be used to narrow the matching files: // // /S - recurse subdirectories (i.e., process all dirs below) // Note: If /S removed, only %SRC_PATH% is processed. // // /T=A-%MAX_DATE% - Last Accessed on or before %MAX_DATE% (yyyy/mm/dd) // /T=C-%MAX_DATE% - Created on or before %MAX_DATE% (yyyy/mm/dd) // /T=M-%MAX_DATE% - Last Modified on or before %MAX_DATE% (yyyy/mm/dd) // Note: Only a single date option can be specified. // DIR "%SRC_PATH%\*.*" /B /-D /S /T=M-%MAX_DATE% >%TASK_PATH%\%TASK_FILE%.DIR // Open the output redirection file for processing OPEN READ %TASK_PATH%\%TASK_FILE%.DIR IF ERRORLEVEL OPEN WRITE %TASK_PATH%\%TASK_FILE%.ERR TRUNCATE IF NOT ERRORLEVEL WRITE ERROR: Unable to OPEN READ log - Check %TASK_PATH%\%TASK_FILE%.DIR CLOSE ENDIF ECHO. ECHO ERROR: Unable to OPEN READ log (%TASK_PATH%\%TASK_FILE%.DIR)! ECHO. EXIT ENDIF // Open the log file for report processing OPEN WRITE %TASK_PATH%\%TASK_FILE%.LOG TRUNCATE IF ERRORLEVEL OPEN WRITE %TASK_PATH%\%TASK_FILE%.ERR TRUNCATE IF NOT ERRORLEVEL WRITE ERROR: Unable to OPEN WRITE log (%TASK_PATH%\%TASK_FILE%.LOG)! CLOSE ENDIF ECHO. ECHO ERROR: Unable to OPEN READ log - Check %TASK_PATH%\%TASK_FILE%.DIR ECHO. EXIT ENDIF // Calc beginning position of source file for parsing DEFINE %9 %FILE_NAME_LONG_%SRC_PATH%% FINDLEN %BEG_POS% "%9" PARSE %8 %9 %BEG_POS%-%BEG_POS% IF NOT "%8"=="\" THEN DEFINE %BEG_POS% %BEG_POS%+=1 DEFINE %BEG_POS% %BEG_POS%+=1 // Process matching files WHILE // Read the first/next record in the log READ %SRC_SPEC% // ERRORLEVEL is set on End Of File (EOF) or ERROR IF ERRORLEVEL THEN BREAK // Get next record if last record read was null IF "%SRC_SPEC%"=="" THEN CONTINUE // Verify that the file exists (not already processed or error record) IF NOT EXIST "%SRC_SPEC%" THEN CONTINUE // Process the file // (MODIFY) The commands which follow may be modified as appropriate: // In this template, the old files are deleted once successfully migrated. // Innumerable other processing options exist. // First, FLAG the file to Normal attributes (i.e., reset Di and Ri, if set) FLAG "%SRC_SPEC%" N // Note: This format assumes the /S option was included in the DIR. // If not (i.e., no /S option in the DIR), use the following: // // FLAG "%SRC_PATH%\%SRC_SPEC%" N // Convert any non-Long name files to their Long name for processing DEFINE %SRC_SPEC% %FILE_NAME_LONG_%SRC_SPEC%% // Get entry information after source directory PARSE %8 %SRC_SPEC% %BEG_POS%-511 PACK // Copy file to destination as appropriate IF "%RSERVER%"=="" DEFINE %DST_SPEC% %DST_PATH%\%8 XCOPY "%SRC_SPEC%" "%DST_SPEC%" ELSE DEFINE %DST_SPEC% %RSERVER%/%DST_PATH%\%8 SXCOPY "%SRC_SPEC%" "%DST_SPEC%" ENDIF // If error, check that destination directory exists IF ERRORLEVEL // Parse directory structure for destination to use to create (MD/MKDIR) FINDCHR %CHR_POS% "\" "%SRC_SPEC%" LAST DEFINE %CHR_POS% %CHR_POS%-=1 PARSE %8 %SRC_SPEC% %BEG_POS%-%CHR_POS% // Check if destination is on a Remote Server and process accordingly IF NOT "%RSERVER%"=="" TMSCMD %RSERVER% MD "%DST_PATH%\%8" ELSE MD "%DST_PATH%\%8" ENDIF // Re-try the copy if not an error (i.e., exists or problem) IF NOT ERRORLEVEL IF "%RSERVER%"=="" XCOPY "%SRC_SPEC%" "%DST_SPEC%" ELSE SXCOPY "%SRC_SPEC%" "%DST_SPEC%" ENDIF ELSE WRITE *ERROR* : "%DST_PATH%\%8" issue ENDIF ENDIF // Update log according to the result IF NOT ERRORLEVEL DEFINE %9 %FILE_SIZE_%SRC_SPEC%% CALC %SIZE_MB% %SIZE_MB% + (%9 / 1048576) CALC %SIZE_KB% %SIZE_KB% + (%9 - ((%9 / 1048576) * 1048576)) IF "%SIZE_KB%">"0001048576" DEFINE %SIZE_KB% %SIZE_KB%-=0001048576 DEFINE %SIZE_MB% %SIZE_MB%+=0000000001 ENDIF WRITE ARCHIVED: %SRC_SPEC% -> %DST_SPEC% DELETE "%SRC_SPEC%" DEFINE %COUNT% %COUNT%+=1 ELSE WRITE *ERROR* : %SRC_SPEC% -> %DST_SPEC% DEFINE %ERRORS% %ERRORS%+=1 ENDIF LOOP // Format size data for easier to read logging. REFORMAT %SIZE_MB% PACK CALC %SIZE_KB% %SIZE_KB% / 10486 PARSE %SIZE_KB% %SIZE_KB% 9-10 // Log the summary information WRITE. WRITE %COUNT% files migrated (%SIZE_MB%.%SIZE_KB% MB) IF "%ERRORS%">"0" THEN WRITE %ERRORS% files not migrated due to error(s)... WRITE. // Close the redirected output and log file CLOSE // Delete redirected DIR output file used for OPEN READ DELETE %TASK_PATH%\%TASK_FILE%.DIR