CMD: Popupmessage IF file created < 5 minutes AND file > 1 MB - windows

I want a pop up notification when a .GEO file comes into a folder that was created 5 minutes ago (or less) AND is larger than 1 MB.
Folder: T:\Klanten
This is what I've found so far:
I run a CMD every 5 minutes that checks if there is a file larger than 1MB.
If he found one, it will run another CMD:
forfiles /S /M * /C "cmd /c if #fsize GEQ 1048576 start test2.cmd"
The second CMD gives the pop up message:
echo calling popup
START /WAIT CMD /C "ECHO File in Watch CADMAN too big && ECHO. && PAUSE"
echo we are back!
I need to build a function in the first CMD where it checks if the file larger than 1 MB was created 5 minutes ago or less.
If someone can send a working CMD code that would be great!

#ECHO OFF
SETLOCAL
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "monitor=%sourcedir%\monitor.txt"
:: list files larger than required
(
FOR /f "tokens=1*delims=" %%b IN (
'dir /b /s /a-d "%sourcedir%\*.geo" 2^>nul'
) DO IF %%~zb gtr 10 ECHO "%%b"
)>"%monitor%.new"
:: Compare list against previous list (if any)
IF EXIST "%monitor%" FC "%monitor%" "%monitor%.new" >NUL 2>nul
IF ERRORLEVEL 1 ECHO START "GEO monitor report" ...whatever...
:: replace monitor list
MOVE /y "%monitor%.new" "%monitor%" >nul
GOTO :eof
The for locates files in the required directory and subdirectories (/s) in basic form /b (ie. filename-only) and reports any that have a size (%~zb) greater than - I used 10 for testing. The filenames are gathered into the ...new file and are quoted. The 2>nul suppresses error messages from dir - the ^ is required to tell cmd that the > is part of the dir command, not of the for.
See for /? from the prompt to learn about metavariable modifiers.
Then compare against the previous list, suppressing reports from fc.
fc will set errorlevel to zero if the files are the same, so detect that the files are not the same, and generate your pop-up.
Then replace the previous monitor file with the new version.
Of course, the monitor files may be placed anywhere - I just used the source directory for my convenience.

Related

Check if there are any folders in a directory

CMD. How do I check if a directory contains a folder/s (name is not specified)? Other files are ignored.
If this was in the case of any .txt file, it would kind of look like this :
if exist * .txt
How do I do it with "any" folder?
There are multiple solutions to check if a directory contains subdirectories.
In all solutions below the folder for temporary files referenced with %TEMP% is used as an example.
Solution 1 using FOR /D:
#echo off
set "FolderCount=0"
for /D %%I in ("%TEMP%\*") do set /A FolderCount+=1
if %FolderCount% == 0 (
echo Temporary files folder has no non-hidden subfolder.
) else if %FolderCount% == 1 (
echo Temporary files folder has one non-hidden subfolder.
) else (
echo Temporary files folder has %FolderCount% non-hidden subfolders.
)
pause
The problem with this solution is that FOR with option /D to search for directories matching the wildcard pattern * in specified directory for temporary files ignores the directories with hidden attribute set. For that reason the command SET with the arithmetic expression to increment the value of environment variable FolderCount by one on each each directory is not executed for a directory with hidden attribute set.
The short version of this solution without counting the folders:
#echo off
for /D %%I in ("%TEMP%\*") do goto HasFolders
echo Temporary files folder has no non-hidden subfolder.
goto EndBatch
:HasFolders
echo Temporary files folder has non-hidden subfolders.
:EndBatch
pause
The loop is exited with command GOTO on FOR has assigned first name of a non-hidden directory to the loop variable.
Solution 2 using FOR /F and DIR:
#echo off
set "FolderCount=0"
for /F "eol=| delims=" %%I in ('dir "%TEMP%" /AD /B 2^>nul') do set /A FolderCount+=1
if %FolderCount% == 0 (
echo Temporary files folder has no subfolder.
) else if %FolderCount% == 1 (
echo Temporary files folder has one subfolder.
) else (
echo Temporary files folder has %FolderCount% subfolders.
)
pause
FOR with option /F and a set enclosed in ' results in starting in background one more command process with %ComSpec% /c and the command line within ' appended as additional arguments. So executed is with Windows installed to C:\Windows:
C:\Windows\System32\cmd.exe /c dir "C:\Users\UserName\AppData\Local\Temp" /AD /B 2>nul
DIR executed by background command process searches
in specified directory for temporary files
just for directories because of option /AD (attribute directory)
with including also directories with hidden attribute set because of option /AD overrides the default /A-H (all attributes except attribute hidden)
and outputs them in bare format because of option /B which results in ignoring the standard directories . (current directory) and .. (parent directory) and printing just the directory names without path.
The output of DIR is written to handle STDOUT (standard output) of the started background command process. There is nothing output if the there is no subdirectory in the specified directory.
There is an error message output to handle STDERR (standard error) of background command process if the specified directory does not exist at all. This error message would be redirected by the command process executing the batch file to own STDERR handle and would be output in console window. For that reason 2>nul is appended to the DIR command line to suppress the error message in background command process by redirecting it from handle STDERR to device NUL.
Read the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
FOR with option /F captures the output written to handle STDOUT of started background command process and processes the output line by line after started cmd.exe terminated itself after finishing execution of internal command DIR.
Empty lines are ignored by default by FOR which do not occur here.
FOR would split up the line by default into substrings using normal space and horizontal tab character as string delimiters and would assign just first space/tab separated string to specified loop variable I. This line splitting behavior is unnecessary here and is disabled for that reason by using option delims= which defines an empty list of string delimiters.
FOR would ignore also lines on which first substring after splitting a line up into substrings starts with default end of line character ;. The line splitting behavior is already disabled, but the name of directory can start unusually with a semicolon. Such a directory name would be ignored by FOR. Therefore the option eol=| defines the vertical bar as end of line character which no directory name can have and so no directory is ignored by FOR. See also the Microsoft documentation page Naming Files, Paths, and Namespaces.
The directory name assigned to loop variable I is not really used because of FOR executes for each directory name just command SET with an arithmetic expression to increment the value of the environment variable FolderCount by one.
The environment variable FolderCount contains the number of subfolders in specified directory independent on hidden attribute.
The short version of this solution without counting the folders:
#echo off
for /F "eol=| delims=" %%I in ('dir "%TEMP%" /AD /B 2^>nul') do goto HasFolders
echo Temporary files folder has no subfolder.
goto EndBatch
:HasFolders
echo Temporary files folder has subfolders.
:EndBatch
pause
The loop is exited with command GOTO on FOR has assigned first name of a directory to the loop variable.
Solution 3 using DIR and FINDSTR:
#echo off
dir "%TEMP%" /AD /B 2>nul | %SystemRoot%\System32\findstr.exe /R "^." >nul
if errorlevel 1 (
echo Temporary files folder has no subfolder.
) else (
echo Temporary files folder has subfolders.
)
pause
The output of DIR as explained above executed by cmd.exe processing the batch file is redirected from STDOUT of command process to STDIN (standard input) of FINDSTR which searches for lines having at least one character. The found lines are all lines with a directory name output by DIR. This search result is of no real interest and therefore redirected to device NUL to suppress it.
FINDSTR exits with 1 if no string could be found and with 0 on having at least one string found. The FINDSTR exit code is assigned by Windows command processor to ERRORLEVEL which is evaluated with the IF condition.
The IF condition is true if exit value of FINDSTR assigned to ERRORLEVEL is greater or equal 1 which is the case on no directory found by DIR and so FINDSTR failed to find any line with at least one character.
This solution could be also written as one command line:
dir "%TEMP%" /AD /B 2>nul | %SystemRoot%\System32\findstr.exe /R "^." >nul && echo Temporary files folder has subfolders.|| echo Temporary files folder has no subfolder.
See single line with multiple commands using Windows batch file for an explanation of the operators && and || used here to evaluate the exit code of FINDSTR.
Additional hints:
It would be good to first check if the directory exists at all before checking if it contains any subdirectories. This can be done in all three solutions above by using first after #echo off
if not exist "%TEMP%\" (
echo Folder "%TEMP%" does not exist.
pause
exit /B
)
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
cmd /?
dir /?
echo /?
exit /?
findstr /?
for /?
goto /?
if /?
pause /?
set /?
DIR "your directory" /ad, for example DIR C:\Users /ad brings out all folders that are inside C:\Users
Displays a list of files and subdirectories in a directory.
DIR [ drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N]
[/O[[:]sortorder]] [/P] [/Q] [/R] [/S] [/T[[:]timefield]] [/W] [/X] [/4]
[drive:][path][filename]
Specifies drive, directory, and/or files to list.
/A Displays files with specified attributes.
attributes D Directories R Read-only files
H Hidden files A Files ready for archiving
S System files I Not content indexed files
L Reparse Points
If you just want to use the cmd.exe shell console to see if there are any directories:
DIR /A:D
If you want to check for it in a .bat file script:
SET "HASDIR=false"
FOR /F "eol=| delims=" %%A IN ('DIR /B /A:D') DO (SET "HASDIR=true")
IF /I "%HASDIR%" == "true" (
REM Do things about the directories.
)
ECHO HASDIR is %HASDIR%

Extract 7-zip files into their containing directory from a batch file?

I have a directory, c:\7zip\test, containing many subdirectories, some containing 7-zip files.
I want to find and extract the 7-zip files into their holding directories from a batch file and then delete those 7-zip files.
#If "%1"=="" (Set pathf=c:\7zip\test\) else (Set pathf=%1)
#If "%2"=="" (Set lzma2_test=*.7z) else (Set lzma2_test=%2)
for /r "%pathf%" %%f in ("%lzma2_test%") do 7z x -y -mx1 -m0=lzma2 "%%f" -oFolderName
del "%pathf%" + subfolder name (if needed) + 7-zip file name
Instead of FolderName, I should send a directory name, but I do not know how. And the same for del.
Open a command prompt, run for /? and read the output help from top of first page to bottom of last page, especially the section about referencing the loop variable with a modifier like %~dpI with I being the loop variable to reference the drive and path.
#echo off
if "%~1" == "" (set "pathf=c:\7zip\test") else (set "pathf=%~1")
if "%~2" == "" (set "lzma2_test=*.7z") else (set "lzma2_test=%~2")
for /R "%pathf%" %%I in ("%lzma2_test%") do (
7z.exe x -y -o"%%~dpI" "%%I"
if not errorlevel 1 del "%%I"
)
The compression switches -mx1 -m0=lzma2 are useless on extracting an archive. The archive contains in header the algorithm used on compression and so extraction works always as long as used 7z.exe supports the archive type and used algorithm on creating the archive.
The archive file is only deleted if the extraction was successful, i.e. 7x.exe exited not with a value greater or equal 1 which means equal 0 which is the exit code for a successful extraction.
It would be more safe to use the following code which works also if an archive file contains inside another archive file. This code is recommended also for usage on a FAT16, FAT32 or exFAT drive.
#echo off
if "%~1" == "" (set "pathf=c:\7zip\test") else (set "pathf=%~1")
if "%~2" == "" (set "lzma2_test=*.7z") else (set "lzma2_test=%~2")
for /F "eol=| delims=" %%I in ('dir "%pathf%\%lzma2_test%" /A-D /B /S 2^>nul') do (
7z.exe x -y -o"%%~dpI" "%%I"
if not errorlevel 1 del "%%I"
)
This code makes sure not extracting an archive file inside an archive file by chance which as it could happen by the first code which iterates of the list of archive files with the list changing on each iteration on extracting an archive file containing an archive file and because of deletion of the successfully extracted archives.
It would be a good idea to test the used batch file first by running it from within a command prompt window with echo left to 7z.exe and if not errorlevel 1 to see what would be executed without really executing it.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
del /?
dir /?
echo /?
for /?
if /?
set /?
Read the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background with %ComSpec% /c and the command line between ' appended as additional arguments.

batch - execute command for every file with specific creation date

got this piece of code:
forfiles /P %ParentFolder% /S /M %Format% /C "cmd /c %exeFile% #path"
executing some exe for every file matching format as parameter.
any way to add "creation date" as a condition to run command via CMD?
something like :
for all files in directory (recursive) X if creation date newer then 1 day ago do (run) some exe with this file's path as param
This is not possible with forfiles, because, when the /D option is provided, it only regards the last modification date only (not even the modification time).
Unfortunately, there are no native commands for date/time maths, so I suggest to switch to a language that is capable of that; for instance, PowerShell, VBScript, JavaScript (which are all native to Windows past XP).
In case the modification date could be used, and a simple check with the date of today is sufficient, the following forfiles command line could be used:
forfiles /S /P "%ParentFolder%" /M "%Format%" /D +0 /C "cmd /C \"%exeFile%\" #path"
The /D option with a non-negative number lets forfiles return files that have been modified the given number of days after today or later (although you would need a time-machine; hence I consider this a design flaw). For +0 as the given number of days, all matching files modified today are returned, because forfiles /D only checks the modification date but does not care about the modification time.
If a simple equality check of the creation date with the date of today is fine for you, it can be done in batch-file scripting quite easily though (see all the explanatory rem remarks for how the following script works):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "ParentFolder=."
set "Format=*.*"
set "exeFile=" & rem // (full path to executable file)
set "tmpFile=%TEMP%\%~n0_%RANDOM%.tmp"
rem // Create a temporary file and retrieve its creation date:
2> nul del "%tmpFile%" & > "%tmpFile%" break & set "TODAY="
for /F "skip=5" %%J in ('dir /N /4 /-C /T:C "%tmpFile%"') do (
if not defined TODAY set "TODAY=%%J" & del "%tmpFile%"
)
rem // Change to predefined parent directory:
pushd "%ParentFolder%" && (
rem // Return all files recursively:
for /F "delims=" %%I in ('dir /B /S /A:-D "%Format%"') do (
rem // Determine the creation date for the current file:
set "FIRST=#"
for /F "skip=5" %%J in ('dir /N /-C /T:C "%%I"') do (
rem // Regard line listing file only, ignore summary lines:
if defined FIRST (
set "FIRST="
rem // Check creation date against today:
if "%%J"=="%TODAY%" (
rem // Return files created today:
echo "%%I" has been created today.
rem // Run external program on found file:
if defined exeFile "%exeFile%" "%%I"
)
)
)
)
rem // Restore previous working directory:
popd
)
endlocal
exit /B
I am using two dir command lines here:
the first one returns a bare list of files recursively (/S; no directories because of /A:-D) without any dates/times, headers and footers, due to switch /B; not using this switch would lead to header and footer lines for the whole output and for every iterated sub-directory also, so the output would be quite complicated to be parsed;
the second one receives each file returned by the first one; since there is no /B but the /N option, the file creation date/time is returned (/T:C); for every file the output looks like this:
Volume in drive D is DATA
Volume Serial Number is 0000-0000
Directory of D:\Data
2016/09/29 16:00 1024 current_file.txt
1 File(s) 1024 bytes
0 Dir(s) 1099511623680 bytes free
the first token of the sixth line constituting the creation date is split off and compared against the current date %DATE%; to ignore the header, the skip=5 option of the for /F loop is used; to ignore the summary lines, the variable FIRST is used;
Note that the date format is locale-dependent; as long as there appear no spaces in the date, this is no problem as the current date is also determined by the dir command applied on a temporary file.
Looking at the forfiles /? shows the switch /D that will exclude files that are younger (/d -<days>) or older (/d +<days>) than the given value for <days>.
As you want the files from today, you would set <date> to 0.
Notice, that this will look on the changed date!
Other way would be to use a for /r-loop and get a list of the creation date with dir /T:C ; to sort it add /O-D. Then separate that using a for /f loop to get the lines of the output of dir and another one to separate it (possibly easier without the nested loops).
You can than compare the creation date with %date% or when using one day=24 hrs compare the creation time with %time% additionally.

How to check the result of an overwrite file request in Windows CMD?

I have searched online for this, but can't seem to find an answer. I have code that creates a text file after asking one what name he/she would like to give the text file. The file is then opened after being created. However, if I choose N (No) to an overwrite request, I don't want the file to open. I would instead want to be asked again to specify another file name after saying N (No) to the overwrite request.
I however have no idea as to how to check the answer given to the overwrite request.
Also, I would need the entire code to be in one line.
This is what I have without the extras that I am mentioned above:
cmd /c #ECHO OFF & SET /P filename=What File name: & cmd /v /c copy /-y NUL !filename!.txt & cmd start /v /c start notepad !filename!.txt & Exit
Later Added:
I am working on the following and keep getting the error message "( was unexpected at this time." after the filename is echoed. If I edit the file by commenting parts out so that it works, and then continue to edit it to what I currently have, it still works. However, if I exit the cmd box, and then start it again, then it doesn't work and I get an error message. This is the code thus far:
#echo off
SET /P filename=What File name?
echo %filename%
::loop
if exist !filename!.txt (
echo File Exists
SET /P overwrite=Overwrite File?
echo overwrite is %overwrite%
If %overwrite%==Y (
echo "Yes, Y"
)
)
echo finish
If I put single quotes around %overwrite% in If '%overwrite%'==Y I no longer get the unexpected error message. The problem I still face though is when exiting the session / the cmd box, I can't get the line above to echo the value of overwrite. It just says "overwrite is" (without quotes and with no value after it). If I continue in the same session running the batch file over again, I get a value for overwrite.
Solution to unable to echo value of %overwrite% (user input) from if statement can be found here.
edited to adapt to comments
cmd /v:on /q /c "for /l %a in (0 0 1) do (set /p "file=file? " & if exist "!file!" ( set "q=" & set /p "q=overwrite? " & if /i "!q!"=="y" ( type nul > "!file!" & start "" notepad "!file!" & exit ) ) else ( type nul > "!file!" & start "" notepad "!file!" & exit ))"
As requested, in one line. To include it inside a batch file, replace %a with %%a
edited one line, with input validations and error checks added on file operations, and shortened (variables length reduced, unneeded spaces removed, file creation code deduplicated, ...) to fit into windows "Run" dialog
edited added initial cd /d "%userprofile%" to ensure the working folder is writeable. Why? Because from windows 7, including the /v:on (or off) in the call to cmd from the windows Run dialog (the OP reason for a one liner), the active directory for the command is c:\windows\system32 (or wherever the system is). Without the /v switch, the active directory is the user profile folder.
cmd /v:on /q /c "cd/d "%userprofile%"&for /l %a in () do ((set/p"f=file? "||set "f=")&(if defined f if exist "!f!" ((set/p"q=overwrite? "||set "q=0")&if /i not "!q!"=="y" (set "f=")))&if defined f (type nul>"!f!" &&(start "" notepad "!f!" &exit)))"
edited After a lot of tests i make it fail in XP. The previous code will fail if the machine is configured with command extensions disabled. Also, the problem with Ctrl-C can be anoying. This should handle the first problem and minimize the second.
cmd /v:on /e:on /q /c "cd/d "%userprofile%"&for /l %a in ()do ((set/p"f=file? "||(set f=&cd.))&(if defined f if exist "!f!" ((set/p"q=overwrite? "||(set q=&cd.))&if /i not "!q!"=="y" (set f=)))&if defined f (cd.>"!f!"&&(start "" notepad "!f!" &exit)))"
It is better to avoid overwriting by copy in this case (because it's ERRORLEVEL ignores overwriting status). You can do everything on your side:
You can check existance of file (IF EXISTS !filename!.txt),
If file exists, you can ask user what to do (SET /P userInput=Overwrite? (Yes/No/All)),
After it you can analyzed %userInput% to decide what to do (delete existent file and create empty one with the same name + open editor or ask file name again).
If %overwrite%==Y : if %overwrite% is empty, this is executed as If ==Y - obviously a syntax error.
With the singlequoutes you mentioned: If '%overwrite%'==Y is executed as If ''==Y - this is proper syntax, so your code doesn' fail (but is not running as intended)
The reason why %overwrite% is empty: you are using it inside a block (between if ( and the corresponding ), so for parsing reason it' easy (search for delayed expansion).
You can easily avoid that:
#echo off
SET /P filename=What File name?
echo %filename%
:loop
if not exist %filename%.txt goto finish
echo File Exists
SET /P overwrite=Overwrite File?
echo overwrite is %overwrite%
If "%overwrite%"=="Y" ( echo "Yes, Y" ) else ( goto loop )
this line is never reached
:finish
echo finish
When using a single line you can't loop back to the start - but this will only create the file AND start notepad with the file, if the file does not exist.
If the file exists it will just exit and NOT start notepad so you know that you have to try again.
cmd /c #ECHO OFF & SET /P filename=What File name: & cmd /v /c "if not exist !filename!.txt copy NUL !filename!.txt & start "" notepad !filename!.txt" & Exit

Print request upon new file in folder

I've got the following problem:
I need to make something that checks to see whether a file has been added to a specific folder, ifso this file needs to be printed. I heard Windows maybe has something similar built in?
*Program constantly checks whether a file has been added*
File has been added
File gets printed immediately
I have found solutions, but you need to pay for them.
UPDATE
"Code supplied by Vik"
:start
set SECONDS=60
SET FILENAME=*.jpg
IF EXIST %FILENAME% MSPAINT /p %FILENAME%
choice /C a /T %SECONDS% /D a
DEL /Q %FILENAME%
goto :start
"Edits: COPY *.JPG file to a different folder (E.G. ImageHistory)"
"Edits: DELETE local *.JPG file leaving the monitor folder empty"
Any tips or help are welcome!
This batch file will check if the file printme.jpg exists every 60 seconds. If it exists, it will use the built-in MSPAINT program to print it. Feel free to configure SECONDS and FILENAME to suit your environment.
:start
set SECONDS=60
SET FILENAME=printme.jpg
IF EXIST %FILENAME% MSPAINT /p %FILENAME%
choice /C a /T %SECONDS% /D a
goto :start
Additional mods you may want to make:
If you are using an older version of Windows like XP, you may not have the CHOICE command. In that case, use ping to simulate sleeping: PING 1.1.1.1 -n 1 -w 60000 >NUL
You can add a line to delete the file after it's printed: DEL /Q %FILENAME%
EDIT (Below): Added multi-file, move and delete capability
set SECONDS=20
set FILEFOLDER=C:\dropfolder
set TEMPFOLDER=%FILEFOLDER%\TEMPFOLDER
set FILEWILDCARD=*.jpg
if not exist "%FILEFOLDER%" ECHO %FILEFOLDER% NOT FOUND ... CTRL-C TO EXIT && PAUSE
if not exist "%TEMPFOLDER%" ECHO %TEMPFOLDER% NOT FOUND ... CTRL-C TO EXIT && PAUSE
:start
cd "%FILEFOLDER%"
dir /b "%FILEWILDCARD%" > filelist.txt
for %%A in (filelist.txt) do if not %%~zA==0 goto printfiles
choice /C a /T %SECONDS% /D a
goto :start
:printfiles
echo FILE(s) FOUND!
del /q "%TEMPFOLDER%\%FILEWILDCARD%"
move "%FILEWILDCARD%" "%TEMPFOLDER%"
cd "%TEMPFOLDER%"
for %%A in ("%FILEWILDCARD%") do MSPAINT /p "%%A"
goto :start
Run a VB.Net in Background and use a FileSystemWatcher to get events for each change in that folder. Upon receiving an event, check the file / action and print the file using whatever App that can print them. A Batch file will likely not work here.

Resources