Alright, I'm new to scripting and I'm trying to edit a batch script file that sends an email when a file with an extension of .ecl is in a folder longer than 5 min or so. But there are other files with a .ecl.part extension that get flagged and it sends an email instead of the .ecl files. I'm curious if there is something I can add so that it will send an email when there are .ecl files in the folder for more than 5 min and ignore the .ecl.part files. I read one for someone with Linux who used [!(.extension to exclude)].extension not to exclude, I'm just wondering if this will work for my windows batch script. If it will work do I add it just like that or do I add it like this .extension not to exclude[!(.extension to exclude)]
Here is the part of the script in question:
for /f "tokens=1-5 delims=:, " %%a in ('forfiles /p z: /d +0 /s /m *.ecl /c "cmd /c if #isdir==FALSE echo #file,#ftime"') do (
set fnam=%%a
set fhr=%%b
set fmin=%%c
set fsec=%%d
set fampm=%%e
if "!fampm!" == "PM" if "!fhr!" neq "12" (set /a "fhr=!fhr!+12")
There is more of the script, I didn't set this up, and the person who did isn't being very helpful which is why I came here.
#ECHO OFF
SETLOCAL
SET savearea=c:\destdir
SET emldir=c:\sourcedir
ECHO.>"%savearea%\emlfiles.new"
DIR /b /a-d /on "%emldir%\*.eml" >>"%savearea%\emlfiles.new"
IF NOT EXIST "%savearea%\emlfiles.old" GOTO noold
FOR /f "usebackqdelims=" %%i IN ("%savearea%\emlfiles.new") DO (
FINDSTR /b /e "%%i" "%savearea%\emlfiles.old" >NUL
IF NOT ERRORLEVEL 1 (ECHO %%i is MORE than 5 minutes old)
)
:noold
MOVE /y "%savearea%\emlfiles.new" "%savearea%\emlfiles.old" >nul
GOTO :eof
This script saves in %savearea% a sorted basic filelist of the *.eml files in %emldir% then compares the new list to the previous version. If the same filename appears in both, it will generate the message %%i is MORE than 5 minutes old
So - all you need to do is point emldir to wherever your .eml files reside, savearea to some safe directory, replace the message ECHOing with an email-sending command of your liking and schedule it to run each 5 minutes using task scheduler.
Although in my testing I find this not to be the case, it sounds like forfilesis evaluating wildcards against 8.3 short filenames on your computer. You know how if you're in a directory containing both .doc and .docx files and you do a dir *.doc, the .docx files will be listed as well? Same sort of thing.
So *.ecl is matching your .ecl.part files because in 8.3 notation they've got a .ecl extension. You could either make sure %fnam:~-4%==.ecl, enclosing most of the guts of your for loop within an if statement; or you can use find or findstr to filter the output of forfiles as captured by the for loop. Something like this:
for /f "tokens=1-5 delims=:, " %%a in (
'forfiles /p z: /d +0 /s /m *.ecl /c "cmd /c if #isdir==FALSE echo #file,#ftime" ^| find /v /i ".part"'
) do (
set fnam=%%a
set fhr=%%b
set fmin=%%c
set fsec=%%d
set fampm=%%e
if "!fampm!" == "PM" if "!fhr!" neq "12" (set /a "fhr=!fhr!+12")
rem etc.
Since find /v prints lines not matching its search, that should effectively filter out the .ecl.part files. find /v works like grep -v in Linux.
You know, since my test cases don't seem to match the symptom you're describing, I am very curious to know whether simply replacing if #isdir==FALSE with if #ext==\"ecl\" would also prevent the .ecl.part files from being included. But if you don't feel like experimenting to satisfy my curiosity, I totally understand.
Related
I am creating a batch file for task scheduler in Windows 7.
The logic is searching files in a folder, if the filename without a specific string, and it's older than 10 days, move the file to another folder.
I've tried so many commands but cannot achieve this (combine the findstr and date condition). And as I am quite new to batch commands. Could anyone please give me some scripts or advice?
Here is what I wrote for moving the files without specific string in the filename, but dont know where to put the date condition:
for /r %Path_new% %%H in ("*.avi") do (echo "%%~nH" |findstr /i "_connID=">nul ||((move /y "%%H" "%Path_achieve%" ) && (echo %date% %time% - %%H has been moved >> Log4BB.txt)) )
And if I put a date condition in a script, it will be like this but cannot get the files with a specific string in the filename:
forfiles /p %Path_new% /m *.avi /d -%Day_noconnid% /c "cmd /c if #fname like '*_connID=*' (echo #path will be moved)" >> Log4BA.txt
For robocopy, I don't know how to specify the files that i want to move. My scripts as below:
for /r %Path_new% %%G in ("*.avi") do (^
echo "%%~nG" |findstr /i "_connID=">nul ||(^
robocopy "%Path_new%"\"%%~nG%%~xG" "%Path_achieve%" /maxage:10 /mov)^
) >> Log4BC.txt
Finally, I got the answer. Robocopy has a /XF that allows me to put the condition for filename.
robocopy %Path_new% %Path_achieve% *.avi /mov /xf "*_connID=*.avi" /minage:%Day_noconnid% /log+:"Log4B.txt"
Working very good now. Thanks Squashman
imagine that I have 2 folders:
C:\FolderData (will be incremented daily with new files)
C:\FolderTemp (Needs to have only files from the day before executing, excluding hours/timestamp)
The FolderData will receive filenames that if not for date would be equals, as in:
SYS_PURCHASES_20170612.xls
SYS_PURCHASES_20170613.xls
SYS_PURCHASES_20170614.xls
If I run the .bat file today I need that only the SYS_PURCHASES_20170613.xls be copied over to FolderTemp.
I tried using robocopy but apparently it can't receive the same value for minage and maxage
robocopy "C:\FolderData" "C:\FolderTemp" /minage:1 /maxage:1
Also, if I try:
robocopy "C:\FolderData" "C:\FolderTemp" /minage:1 /maxage:2
It will bring both SYS_PURCHASES_20170612.xls and SYS_PURCHASES_20170613.xls, which is not what I need.
Other than that, I tried using forfiles but also with no avail.
forfiles /p C:\FolderData /D -1 /C "/C /copy /y #file C:\FolderTemp"
or even
forfiles /p C:\FolderData /D -1 /C "/C /copy /y C:\FolderData\#file C:\FolderTemp"
And other variables but it returns something along the line "the system can't return the specified file" times the number of files in the folder.
Note that there are other processes involved bellow that should be ignored, It's just that I can't figure out how to do the step above.
All steps my batch filed needs to do:
Copy from folder1 files from 1 day prior to folder2 (what I need help)
Remove last 9 digits from all files from folder2 (will remove the date, used the loop on this solution) so the file will be SYS_PURCHASES.xls
Move and replacing the files from folder2 to folder3 (using a simple move /y)
Since you want to touch the files from yesterday only, I would use forfiles, because this command only regards the date but not the time, when specifying the /D option. robocopy instead also regards the time, which is probably not what you want.
This is a possible way:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=C:\FolderData"
set "_TARGET=C:\FolderTemp"
set "_MASK=?*_????????.*"
set /A "_DAYS_AGO=1"
rem // Check given age and calculate interim value `PREV` needed for `forfiles`:
(if %_DAYS_AGO% LSS 0 set "_DAYS_AGO=0") & set /A "PREV=_DAYS_AGO+1"
rem // Let `forfiles` output the filtered files and capture them by `for /F`:
for /F "delims= eol=|" %%F in ('
rem/ Use two nested `forfiles` loops to filter for files of specified day: ^
^& forfiles /P "%_SOURCE%" /M "%_MASK%" /D -%_DAYS_AGO% ^
/C "cmd /C if #isdir==FALSE > nul 2>&1 forfiles /M #file /D -%PREV% || echo #file"
') do (
rem // Store current file name and extension:
set "FILE=%%~nF" & set "FEXT=%%~xF"
setlocal EnableDelayedExpansion
rem // Copy the file and remove the last 9 characters from its name:
> nul copy /Y "!_SOURCE!\!FILE!!FEXT!" "!_TARGET!\!FILE:~,-9!!FEXT!"
endlocal
)
endlocal
exit /B
My company has a lot of automation that runs overnight via batch scripts. Mostly just copying new files here and there. What I am looking for is a way to run a check of the file creation dates / last modification dates after all the scripts have ran to ensure everything is up to date. It would basically look to a specific file in a shared drive or UNC path. If that file is less than 24 hours old, do nothing. If the subject file is OLDER than 24 hours, then trigger an email. I already have a VBS to send an email so I could add that at the end of the IF statement. Any help is appreciated.
There are ways and means...
Here's a routine that will do something along the lines you outline:
#ECHO Off
SETLOCAL
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
SET "sourcedir=U:\sourcedir"
SET "runflag=runflag.###"
SET "foundrun="
ATTRIB -h "%sourcedir%\runflag.###"
FOR /f "tokens=1,2delims=:" %%a IN ('dir /b /od /a-d "%sourcedir%"^|findstr /n /r "^"') DO (
IF %%b==%runflag% SET foundrun=Y
IF NOT DEFINED foundrun SET "$%%a=%%b"
)
(
ECHO(Old file list
FOR /F "tokens=1,2delims==" %%a In ('set $ 2^>Nul') DO ECHO(%%b
)>"%sourcedir%\%runflag%"
ATTRIB +h "%sourcedir%\runflag.###"
IF DEFINED $1 ECHO(send email
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances. runflag is simply a convenient filename.
The object here is to look for files that have not been updated since the previous run of this routine. This gets over the fixed "24 hours" idea - in case of holidays, weekends, etc.
The names of files that haven't changed would be in runflag.### - ideal for using in a mailer like blat.
I played around with the hidden flag here - to hide the file from "this shouldn't be here - I don't understand. I'll delete it". (those who take that attitude may often be defeated with a simple +H and +R). Improve or remove the ATTRIB commands as you will.
you can get the file modification date with for %a in (file.txt) do echo %~ta (double the % in batch files)
Change \\server\share and use the filename in place of filename.ext and this should launch your email.bat file if the file is older than 1 day.
robocopy "\\server\share" "%temp%" filename.ext /minage:1 /L |find " New File " >nul && call email.bat
OK, I apologize ahead of time for a) using an old, crappy technology (BAT files) and b) asking what seems to be a redundant question. I'm limited in the technology I'm allowed to use in this particular case and after looking at dozens of posts on the subject I can't find anything I can adapt to what I need.
I have a directory structure that looks like this:
A
B
C
D
etc...
XYZ
more folders
My BAT file is located outside this files system. I need to inspect it starting at level "C" and need to find the "XYZ" directory. The folders between C and XYZ can have variable names depending on the environment in which the files were created. I need to end up with a string that consists of the directory names from C through XYZ (i.e. "C\D\E\F....\XYZ") that I can put into a variable so when my BAT file is completed I can reference the variable and run another command.
I've looked at posts using FIND and FOR but I can't seem to figure out how to a) limit the string to the starting directory (for example when I combine FOR with DIR I get "A\B\C...") and how to stop when I get to "XYZ"...
Any help is greatly appreciated.
This should work in most situations:
#echo off
setlocal enableDelayedExpansion
set "root=c:\a\b\c"
set "target=xyz"
for %%R in ("%root%") do for /f "delims=" %%F in (
'dir /b /s /ad "%root%\%target%"'
) do (
set "fullPath=%%F"
set "relpath=!fullPath:%%~dpR=!"
)
echo !relpath!
It can fail if any of your paths contain ! or =. There are solutions for this, but the code is significantly more complicated.
EDIT
Actually, there is a relatively simple solution using FORFILES that should work in all situations. (Assuming your version of Windows has FORFILES)
#echo off
setlocal disableDelayedExpansion
set "root=c:\a\b\c"
set "target=xyz"
for /f "delims=" %%F in (
'forfiles /p "%root%" /m "%target%" /s /c "cmd /c if #isdir==TRUE echo #relpath"'
) do set "relpath=%%~F"
for %%R in ("%root%") do set "relpath=%%~nxR%relpath:~1%"
echo %relpath%
The only restriction is the code has to change slightly if your result contains poison characters like &. In that case you need to add quotes to the final ECHO statement, or else enable delayed expansion at the end and use echo !relpath!
For a) question:
FOR /F "TOKENS=*" %%d IN ('DIR A\B\C\XYZ /S /AD /B') DO SET variable=%%d
For a) and b) question:
FOR /D /R "A\B\C" %%d IN (*.*) DO IF /I "%%~nxd"=="XYZ" (SET variable=%%d& GOTO :EOF)
but this will exit batch script, so you need:
... your batch code
CALL :GET_XYZ
... your batch code
GOTO :EOF
:GET_XYZ
FOR /D /R "A\B\C" %%d IN (*.*) DO IF /I "%%~nxd"=="XYZ" (SET variable=%%d& GOTO :EOF)
ECHO XYZ not found!
GOTO :EOF
I'm lookiong for a batch script which let's me count only the amount of files in a certain sub dir.
I have a directory tree with various projects (300+) and I am only looking for the amount of files in a reocurring subdirectory.
Currently I am using mtee(small program to revert cmd output to a txt file) and dir to count the subdirs and do a manual search in excel.
I was wondering if there is a way to do this in with a batch script.
e.g: Every project has the directory proposals and subdirectory no-go proposals. I want to count the amount of files in the no-go proposals from the basis of the directorytree
for /f %%i in ('dir /s/b/a-d "c:\project"^|find /c "\no-go-dirname\"') do ECHO nogocount=%%i
Well, that's the line within a batch file. If you're running it from the prompt, each %% becomes %
do a directory list of all of the filenames, /a-d not directorynames, /s including subdirectories /b in basic form, so no headers or trailers. Filter this with a FIND and /c count the lines that contain the string "\no-go-dirname\" and assign the count to %%i
Try this:
#echo off &setlocal
set "startfolder=x:\proposals\no-go proposals"
set /a counter=0
for /r "%startfolder%" %%i in (*) do set /a counter+=1
echo %counter% files found in "no-go proposals" .
Read HELP FOR and HELP SET and try the following code
#echo off
setlocal enabledelayedexpansion
for /r /d %%d in (*) do (
call :countf "%%d\nogo"
)
goto :eof
:countf
set count=0
for %%f in ("%~1\*") do (
set /a count+=1
)
echo %~1 has !count! files
goto :eof
Good to see so many alternatives, and all of them works seemlessly however this is my version.
dir /s/b /a-d | find /c /v ""
running this command in a directory where you need the file count will return just the count.