1

I'm trying to create a little batch script to run via task scheduler but running into an issue with the multiple PDF files in the same directory.

My aim is:

  1. map the remote NAS (this is to take load off the server, and as a backup)
  2. move the existing PDFs into an archive folder (of the same directory) except newest 2 files
  3. clean the archive to delete the oldest n
  4. email the attachments to my address
  5. unmount the NAS

The code so far:

:: delete the old mapping
NET USE A: /DELETE

:: map the backup location
NET USE A: \\NAS\Share\BU

:: set the time and date YYYYMMDD-HHMMSS.UUU
for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j
set ldt=%ldt:~0,4%%ldt:~4,2%%ldt:~6,2%-%ldt:~8,2%%ldt:~10,2%%ldt:~12,6%

:: archive older than the last one - local
pushd "C:\Users\Administrator\Documents\My Database Backups"
echo :: Move these files  ::
echo ------------------------
for /f "skip=2 eol=: delims=" %%F in ('dir /b /o-d *.pdf') do MOVE "%%F" ".\archive"

:: clean the archive folder - local
echo :: Delete these files ::
echo ------------------------
pushd "C:\Users\Administrator\Documents\My Database Backups\archive"
for /f "skip=46 eol=: delims=" %%a in ('dir /a-d /o-d /b /s *.pdf') do del "%%a"

:: go to export directory
cd "C:\Users\Administrator\Documents\My Database Backups"

:: copy to NAS
copy /b *.pdf "\\NAS\Share\BU\File_PDF_BU_%ldt%.pdf"

:: archive older than the last one - remotely
pushd "A:\"
echo :: Move these files  ::
echo ------------------------
for /f "skip=2 eol=: delims=" %%F in ('dir /b /o-d *.pdf') do MOVE "%%F" "A:\archive"

:: delete old archives - remotely
echo :: Delete these files ::
echo ------------------------
pushd "A:\archive"
for /f "skip=46 eol=: delims=" %%b in ('dir /a-d /o-d /b /s *.pdf') do del "%%b"

:: send confirmation email
"C:\Program Files\sendEmail\sendEmail.exe" -o -f "FromServer" -t me@domain.ltd -a "\\NAS\Share\BU\File_PDF_BU_%ldt%.pdf" -s smtp.domain.ltd:25 -u "Subject: %ldt%" -m Script successfully run"

:: wait 60 seconds
TIMEOUT /T 60

:: delete the old mapping
NET USE A: /DELETE /Y

:: exit the script
exit

At the moment, I am having issues with the files being generated from the programme itself. I am receiving two files Database01_YYYYMMDD-HHMMSSUUUU.pdf and Database02_YYYYMMDD-HHMMSSUUUU.pdf in the C:\Users\Administrator\Documents\My Database Backups folder. So when I am copying, there is no way to limit to the two PDFs.

Is there a way to move the current two files in the root folder into a folder, then move that into the archive folder. Then keep the most recent 11 folders (runs for 12 hours - 11 + 1 in root) in the archive folder. And attach the folder to the sendemail.exe?

TylerH
  • 20,799
  • 66
  • 75
  • 101
markb
  • 1,100
  • 1
  • 15
  • 40
  • Are the files named like `Database01_YYYYMMDD-HHMMSSUUUU.pdf` being generated by some other program? If so, what is the use of `ldt` as the date time could be reused from the filename. Seems that `ltd` containing a single constant value is no good for copying multiple files based on wildcard. I rewrote some of your code, though now I see `ltd` as obsolete, or perhaps I misunderstand the actual process. – michael_heath Feb 27 '20 at 08:45
  • @michael_heath those names are being generated from another programme on its output - but have since changed it to be `Database0#_YYYYMMDD-HHMM.pdf`. `%ltd%` is used in the email to notify what time the script ran/sent the email - my mistake to not remove it. I have solved it as it was a limitation to `sendEmail.exe` I am using `cMail.exe` as it has a wildcard feature for them. – markb Feb 28 '20 at 00:22
  • Thanks for info, I guess I was on the right path. I posted my answer for ideas for you rather than deleting it. `cMail` seems better with the wildcard support helps to keep the code simple. Just watch using `dir` with `/s` while ordering by date as `dir` does it by directory, so you may not necessarily be deleting the latest PDFs if exist in multiple directories. – michael_heath Feb 28 '20 at 14:15

2 Answers2

1

I solved the issue with changing from sendEmail.exe to cMail.exe:

@ECHO OFF

:: set the time and date YYYYMMDD-HHMMSS.UUU
for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j
set ldt=%ldt:~0,4%%ldt:~4,2%%ldt:~6,2%-%ldt:~8,2%%ldt:~10,2%%ldt:~12,6%

:: map the backup location
NET USE A: \\NAS\SHARE\DB_BU

:: archive the old files - local
pushd "C:/Users/Administrator/Documents/My Database Backups/"
for /f "skip=2 eol=: delims=" %%F in ('dir /b /o-d *.pdf') do MOVE "%%F" ".\archive"

:: clean the archive folder - local
pushd "C:/Users/Administrator/Documents/My Database Backups/archive/"
for /f "skip=22 eol=: delims=" %%a in ('dir /a-d /o-d /b /s *.pdf') do DEL "%%a"

:: go to export directory
cd "C:\Users\Administrator\Documents\My Database Backups"

:: copy PDFs to A: drive
copy /b "*.pdf" "A:/"

:: archive the old files - local
pushd "A:/"
for /f "skip=2 eol=: delims=" %%F in ('dir /b /o-d *.pdf') do MOVE "%%F" ".\archive"

:: clean the archive folder - local
pushd "A:/archive/"
for /f "skip=22 eol=: delims=" %%a in ('dir /a-d /o-d /b /s *.pdf') do DEL "%%a"

:: send confirmation email
"C:\Program Files\cMail\CMail.exe" -host:smtp.domain.ltd:25 -from:backup@domain.ltd -to:me@domain.ltd -awild:"A:\Database_*.pdf" "-subject:PDF backup: %ldt%" "-body:Backup script successfully run at %ldt%\nPlease find attached database documents\n\nThis is automated"

:: wait 60 seconds
TIMEOUT /T 60

:: delete the old mapping
NET USE A: /DELETE /Y

:: exit the script
exit
markb
  • 1,100
  • 1
  • 15
  • 40
1
@echo off
setlocal

set "attachments=%=do_not_modify=%"
set "db_backups_dir=C:\Users\Administrator\Documents\My Database Backups"
set "nas_dir=\\NAS\Share\BU"
set "email=C:\Program Files\sendEmail\sendEmail.exe"

rem Push initial dir to connect drive
pushd "%nas_dir%" || exit /b 1

rem Set the time and date YYYYMMDD-HHMMSSUUUU
set "ldt="
for /f "usebackq tokens=1,2 delims==" %%I in (
    `wmic os get LocalDateTime /VALUE 2^>nul`
) do if ".%%~I." == ".LocalDateTime." set "ldt=%%~J"
if not defined ldt popd & exit /b 2
set "ldt=%ldt:~0,8%-%ldt:~8,6%%ldt:~15,4%

rem Archive older than the last one and delete old archives - local
call :process_files "%db_backups_dir%" "%nas_dir%"

rem Archive older than the last one and delete old archives - remote
call :process_files "%nas_dir%"

rem Pop initial dir to disconnect drive
popd

rem Send confirmation email
if not defined attachments exit /b 3
echo(%attachments%| find "|" && exit /b 4

echo "%email%" -o -f "FromServer" -t me@domain.ltd -a %attachments% ^
 -s smtp.domain.ltd:25 -u "Subject: %ldt%" -m Script successfully run"

exit /b 0

:process_files  target, destination
rem :process_files "%~1" "%~2"
setlocal
if "%~1" == "" exit /b 1
pushd "%~1" || exit /b 2
echo cd   "%~1"

set "copy_file="
set "copied_file_1="
set "copied_file_2="

if not exist "archive" md "archive"

rem Copy files from local to remote and move files to archive
for /f "eol=: delims=" %%A in ('dir /b /o-d *.pdf 2^>nul') do (
    if defined copied_file_1 if defined copied_file_2 (
        echo move "%%~nxA" "archive\"
        move "%%~A" "archive\" >nul
    )

    if not defined copied_file_1 (
        set "copy_file=y"
    ) else if not defined copied_file_2 (
        set "copy_file=y"
    )

    if defined copy_file (
        set "copy_file="

        if not "%~2" == "" (
            for /f "tokens=1,2 delims=_" %%B in ("%%~nA") do (
                echo copy "%%~A" "%~2\File_PDF_BU_%%~C.pdf"
                copy /b "%%~A" "%~2\File_PDF_BU_%%~C.pdf" >nul

                if not defined copied_file_1 (
                    set "copied_file_1=%~2\File_PDF_BU_%%~C.pdf"
                ) else if not defined copied_file_2 (
                    set "copied_file_2=%~2\File_PDF_BU_%%~C.pdf"
                )
            )
        ) else if not defined copied_file_1 (
            set "copied_file_1=|"
        ) else if not defined copied_file_2 (
            set "copied_file_2=|"
        )
    )
)

rem Delete old files in the archive folder
pushd "archive" || exit /b 3

for /f "skip=46 eol=: delims=" %%A in ('dir /a-d /o-d /b /s *.pdf 2^>nul') do (
    echo del  "%%~nxA"
    del "%%~A"
)

popd

rem Set attachments as global if set as file paths
endlocal & if not "%copied_file_1%" == "|" if not "%copied_file_2%" == "|" (
    set attachments="%copied_file_1%" "%copied_file_2%"
)
exit /b 0

This code follows the 5 specified aims. I stayed with the similar concept with the files rather than your idea of adding folders to the archive folder.

The LocalDateTime value stored in ltd is YYYYMMDD-HHMMSSUUUU, not the YYYYMMDD-HHMMSS.UUU that your posted code has which conflicts with your posted summary. It can be changed if needed to match the correct pattern.

The code does 2 file copies at most, as it is tracked by the set variables of copied_file_1 and copied_file_2. Those same 2 values are used for emailing of the 2 attachment files.

The mapped drive connection is done by use of pushd and the final use of popd will disconnect the drive. If the final use of popd is not used, then the drive may remain when the does script exit. So, pushd and popd require pairing to finish correct.

Your code copies a wildcard path to one filename. This code uses a for loop to copy each file and uses the original date stamp.

michael_heath
  • 5,262
  • 2
  • 12
  • 22