Scheduled Folder Cleanup - Batch File - batch-file

I am currently working at my first Junior IT position, and I am having trouble with a simple batch file.
Essentially the file is ran weekly through the task scheduler. It removes files and folders from a server directory that are older than 8 days. It is also supposed to remove empty folders.
forfiles /p "P:\blahblah" /s /m * /d -8 /c "cmd /c del /Q /S /F /A #path"
cd /d P:\blahblah
for /f "usebackq" %%d in (`"dir /ad/b/s | sort /R"`) do rd "%%d"
REM robocopy "P:\blahblah" "P:\blahblah" /s /move"
There are two problems here;
It will occasionally delete files only a few days old.
It will not remove empty folders.
The file was written by an old junior IT employee and there is no documentation. My guess is multiple methods were used in order to ensure the cleanup (ironically). I have searched google and here are my current thoughts on each command..
1) forfiles - the forfiles command seems to be written correctly and I do not see any issues with it.
2) cd - simple enough
3) for - not entirely sure. The batch variables are new to me and I am not sure if it is working correctly.
4) robocopy - I have not been able to find an instance online where someone copies a directory to itself for cleanup. I also notice the extra quotation in there, but i am not certain of its incorrectness. This line especially seems odd to me.
Normally I would try and test my through something like this, but It is a bit harder to test quickly given I need to see if it is removing things based on calendar date. That's why I am here!
I promise I would not have asked if I had not already scoured the internet for an idea. Any help would be greatly appreciated, and I would love to learn a little more about the above commands!
Thanks for your help!

forfiles
Being syntactically correct doesn't mean it does what you want, it does what you ask. Here the problem is the del command. It will delete what the forfiles has selected, but you should test the selected element is not a folder. If you call del /q /s /f /a with a folder reference, you delete the folder contents.
cd
Simple enough, but as you don't check the operation was sucessful (maybe P: is not available) maybe the following for command removes information where it should not.
for
As Squashman comments, if you change the back quotes into single quotes you will not need the usebackq.
But you need the delims clause to avoid problems with paths containing spaces. for /f does not iterate over file references, but over lines of text (in this case generated by a dir command). By default tabs and spaces are delimiters that split the lines being processed and, also by default, only the first token is retrieved. Setting the delims clause to an empty list of characters will disable this behaviour.
You can try with something like
#echo off
setlocal enableextensions disabledelayedexpansion
pushd "p:\blahblah" && (
forfiles /s /m * /d -8 /c "cmd /c if #isdir==FALSE del /q /f /a #path"
for /f "delims=" %%d in ('" dir /ad /s /b | sort /R "') do rd "%%d"
popd
)
The pushd will change the current active directory to the required one. If the command is sucessful, the conditional operator && (execute next command if the previous one did not fail) will execute the rest of the code, restoring the active directory at the end.
4) robocopy
It can be used to do the clean, but not from a folder into itself.
#echo off
setlocal enableextensions disabledelayedexpansion
pushd "p:\blahblah" && (
rem Use a random temporary folder
for %%t in ("%temp%\clean_%random%%random%%random%%random%.tmp") do (
rem Select the files to keep
robocopy "." "%%~ft" /MAXAGE:8 /CREATE /s /njh /njs /nfl /nc /ns
rem Remove anything not selected
robocopy "%%~ft" "." /NOCOPY /PURGE /e /njh /njs /nfl /nc /ns
rem remove temporary folder
) & rd /s /q "%%~ft"
rem Restore previous active directory
popd
)
This code creates a replica of all the selected files (not older than 8 days) into a temporary folder, but the /CREATE switch tells robocopy to not copy the files, but to create 0 bytes files into the temporary target.
Once we have a replica with only the selected elements, the oposite operation is done, from temporary folder into work folder but requesting that no copy operation should be done (/NOCOPY), just a removal of elements not present in source (/PURGE).

Related

Ignore one folder and its contents in batch operation

I've tried to create a batch file that will remove all files and sub-directories from a folder. The command I found that worked is this
FORFILES /p “X:\DAILY\1 MONDAY” /m *.* /c “cmd /c Del /F /Q #path” /d -7 /s & FORFILES /p “X:\DAILY\1 MONDAY” /S /D -7 /C “cmd /c IF #isdir == TRUE rd /S /Q #path”
Now my users tell me there is a Reference folder under 1 MONDAY that they don't want purged (but all other subdirectories should be emptied and deleted.) Can anyone advise how I might accomplish that?
Thank you!
for /f %%a in ("X:\Daily\1 MONDAY\*") do (if %%a neq "<filename you want to save>" (del %%a))
NOT YET TESTED
This should work though. Put the files you want to save in <filename you want to save>
It is extremely inefficient to use FORFILES for such a task because FORFILES has to start cmd.exe for each file found to delete the file older than seven days and for each folder to remove.
A much better solution would be:
#echo off
%SystemRoot%\System32\robocopy.exe "X:\DAILY\1 MONDAY" "X:\DAILY\1 MONDAY\WeeklyDelete" /E /XD "X:\DAILY\1 MONDAY\WeeklyDelete" "X:\DAILY\1 MONDAY\Reference" /MINAGE:7 /MOVE /NDL /NFL /NJH /NJS
if exist "X:\DAILY\1 MONDAY\WeeklyDelete\" rd /Q /S "X:\DAILY\1 MONDAY\WeeklyDelete"
ROBOCOPY searches
for all files in the directory X:\DAILY\1 MONDAY
and its subdirectories including empty directories because of option /E with
excluding the files in the two directories X:\DAILY\1 MONDAY\WeeklyDelete and X:\DAILY\1 MONDAY\Reference and all their subdirectories because of option /XD "X:\DAILY\1 MONDAY\WeeklyDelete" "X:\DAILY\1 MONDAY\Reference" with
excluding all files last modified in last seven days because of option /MINAGE:7.
The found files and folders matching theses criteria are moved to X:\DAILY\1 MONDAY\WeeklyDelete whereby the destination folder is automatically created on not already existing.
The options /NDL /NFL /NJH /NJS are for not printing the list of moved directories, list of moved files, the header and the summary.
A folder is moved only if being empty after moving all files matched by these criteria. So a folder is not moved on containing a file or subfolder.
The option /S instead of /E and the option /MOV instead of /MOVE can be used to move only files and do not move also folders being empty before or after moving the files.
The file and folder movements are done very fast by ROBOCOPY because of destination folder is on same drive as source folder which means just the file system of this drive must be updated and no file data must be moved at all.
An IF condition is used after ROBOCOPY finished with updating the file system to move the files and folders to verify if the destination folder X:\DAILY\1 MONDAY\WeeklyDelete exists. In this case command RD is used to delete this folder quietly because of option /Q and with all files and subdirectories because of option /S. This action is again just a file system update not really deleting file data stored on storage media and so is processed very fast.
Open a command prompt window and execute there the following commands to read more about the used commands in the three lines above.
echo /?
if /?
rd /?
robocopy /?
The commands are described also
by Microsoft with the documentations for the Windows Commands and
by SS64.com with A-Z index of Windows CMD commands and on many other websites.
Based upon your provided information, I would suggest this as your updated batch file:
#%__AppDir__%forfiles.exe /P "X:\DAILY\1 MONDAY" /C "cmd /C If #IsDir == FALSE 0x28Del /A /F #Path0x29 Else If /I Not #File == 0x22Reference0x22 RD /S /Q #Path" /D -7
That's it, nothing else to be added or modified.

How to exclude folders from being deleted using a for loop in a Batch script?

I am trying to delete everything in a user defined location with exception on one pre-defined folder using a for loop. How do I go about adding a exception in order to not delete a folder.
I am trying to learn how to code, but I admit I am doing baby steps. I got some excellent tips for the first input part of this script, but I lack the knowledge to move forward. I have searched and found similar code, but none seems to work. This script is intended for flight simulation and hopefully ease the workload of installing a particular item.
This is just the part of the code due to stackoverflow guidelines, it deletes everything including the folder I want to exclude.
...
Rem This code is intended to delete all except one pre-defined folder
Echo Deleting all the files except testmappe3
del /s /q "%CD%"
for /d %%p in ("%CD%") do rmdir "%%p" except "%%testmappe3" /s /q
dir
Pause
...
I expected the output to delete all folders except testfolder3
for /d %%A in ("%CD%\*") do (
set "except="
if /i "%%~nxA" == "testmappe3" set "except=1"
if not defined except rmdir /s /q "%%~A"
)
This code will iterate the folders in the current directory.
If the name+extension of the folder is testmappe3,
then except will be set as 1 i.e. defined with a value.
If except is not defined, rmdir will remove the folder.
You can add more if lines for checking folders to except.
The modifiers will recognize a folder such as named
testmappe3.test1 as name testmappe3 and
extension of .test1.
View for /? and call /? about modifiers.
View for /?, set /?, if /? and rmdir /? for
help with those commands.
First of all, I would be a very careful deleting everything using %cd% especially if the script can accidently be run as Administrator, where %cd% would then be c:\windows\system32.
Instead, use %~dp0 as path to ensure that you are in the correct directory. This all assumes you did not cd somewhere else earlier in the script.
Then to the actual issue, I would include findstr to exclude your directory `testmappe3 as well as your script itself.
#echo off
cd /d "%~dp0"
for /f %%p in ('dir /b ^| findstr /vi /r /c:^testmappe3$') do (
rmdir "%%p" /s /q >nul 2>&1
if not "%%p"=="%~nx0" del /s /q "%%p" >nul 2>&1
)
If you want to stick to your original delete method, then it would be as below, but if your script is in the same dir, then it will also be deleted:
#echo off
cd /d "%~dp0"
del /s /q *
for /f %%p in ('dir /b ^| findstr /vi /r /c:^testmappe3$') do (
rmdir "%%p" /s /q >nul 2>&1
)
If your folder to exclude contains spaces, double quotes are required.. i.e
dir /b ^| findstr /vi /r /c:^"test mappe3"$

How do I specify in a batch file to not delete a file if it is not at least N days old?

I have two parameters. It was suggested that this is a duplicate question, but I want to specify a minimum age AND a minimum number of files to be kept. I'm not sure how to combine those parameters.
I have a batch file which includes this code:
#echo off
set "backupDir=[BACKUP DIR PATH HERE]"
copy /Y "[PATH OF FILE TO BE COPIED]" "[PATH WHERE BACKUP IS SAVED]"
for /f "skip=4 delims=" %%a in ('dir "%backupDir%\" /b /a-d /o:-d') do del "%backupDir%\%%a"
It creates a backup of a database and deletes everything except the four most recent instances. What I want is to make sure that if the batch file is run more than once in a day, I don't end up deleting the old files and end up with four copies of what would essentially be the same backup.
How can I specify that the file must be at least "N" days old before deletion?
It might be better to have something that limits the file from running again if it hasn't been at least 24 hours since the last time. But I don't know how to do that either.
If I understand correctly, you want to delete all but the newest four backups, but only if they have got a minimum age (or, more precisely, if they have been modified earlier than a certain number of days ago).
The following code does exactly that:
pushd "%backupDir%" || exit 1
rem // Iterate files but skip the four ones that have been modified most recently:
for /F "skip=4 delims=" %%F in ('dir /B /A:-D /O:-D "*.*"') do (
rem // Verify whether the last modification date is at least seven days ago:
for /F "delims=" %%I in ('
2^> nul forfiles /P "%%~dpF." /M "%%~nxF" /D -7 /C "cmd /C echo #path"
') do (
ECHO del "%%I"
)
)
popd
Remove the upper-case ECHO after having verified the correct output.
use forfiles
forfiles /P "%backupDir%" /M *.* /D -10 /C "cmd /C echo #path"
You can change the number of days where -10 is.
Change echo to del only when you are 100% sure it echo's the correct files you want to delete.
You can be more specific with your file types by replacing *.* with your file extension or actual file name. i.e *.MYD or backup_db* etc.
For more info run forfiles /? from cmd.exe
To add the line above to your script, simply replace this line:
for /f "skip=4 delims=" %%a in ('dir "%backupDir%\" /b /a-d /o:-d') do del "%backupDir%\%%a"
with the forfiles line.

Batch / CMD script to delete folder but excluding more than one

In advance: I'm new to batch or programming in general so please explain as much as possible.
My problem:
I want to delete all folders not named X and Y in a directory Z (ex. D:\Test\z)
So let's say Z contains these folder:
backup
resources
project1
project2
project3
I'd need to exclude only backup and resources from deletion via a script.
I looked up multiple soultions for not deleting only one folder with a certain name but I don't know if it's possible for multiple values with Batch.
not tested:
#echo off
set "root_dir=C:\Z"
set "exclude_list=backup resources"
pushd "%root_dir%"
for /f "tokens=* delims=" %%# in ('dir /b /a:d^| findstr /v "%exclude_list%"') do (
echo rd /s /q "%%~f#"
)
if this looks ok delete the echo on the last line to activate deletion.
If all folders you want to delete are like project* you can try also :
for /d %%a in ("project*") do rd /s /q "%%~fa"
#echo off
setlocal EnableDelayedExpansion
rem Define working variables
set "dir=D:\Test\z"
set "exclude=/backup/resources/"
rem Change current dir to working dir
cd /D "%dir%"
rem Process all folders in this dir
for /D %%f in (*) do (
rem If current folder is not in "exclude" var
if "!exclude:/%%f/=!" equ "%exclude%" (
rem Delete it
ECHO rd /s /q "%%f"
)
)
This method use internal cmd.exe commands only, so it run faster than other methods that may use external .exe files (like findstr.exe).
The way to detect if a name is in the exclude variable is trying to delete such name from it: "%exclude:/%%f/=%": if the result is equal to the original variable contents, the folder was not there. This method is very simple and efficient and works not matter the case of the letters, so it don't requires any /I ignore case switch in the if command.
The names are delimited by slashes to avoid any problem caused by partial name matches; for this reason the %%f part is enclosed in slashes in the if command.
Note that the value of %%f change in each iteration of the for command. For this reason, the exclude variable is surrounded by exclamation marks instead percent signs and the setlocal EnableDelayedExpansion command is given at beginning; otherwise, the %expansion% would be done just one time, before the for command start iterations. You may look for "delayed expansion" in this forum for a further explanation of this point.

Batch file that deletes folders of users in C:\users that are more than 210 days

I am trying to write a batch file that removes/deletes different user(s) folders in C:\users that are older than 210 days.
I tried this
forfiles /p C:\users /d -210 /c "cmd /c del #file"
However this command deletes the shortcut of the current user as well as those shortcuts are older than 210 days.
Can I get the batch file to only remove the entire folder if the last modified date of the content is older 210 days
Also can I specify the starting name of the folder to be deleted(the users starts with PDC), as I fear it may delete some of the important hidden document of a computer, as this batch file will be run on an administrator account.
Any help is appreciated thanks
First run robocopy in list-only mode and if there were no files newer than the specified age proceed with the actual delete operation:
#echo off
set AGE=2
set EXCLUDE="Public" "admin1" "admin2"
for /d %%D in (C:\users\*) do (
echo %EXCLUDE% | find /i """%%~nD""" >nul
if errorlevel 1 (
set too_new=0
robocopy "%%D" "%%D" /L /v /s /xjd /minage:%AGE% | findstr /r /c:"^. *too new" >nul
if errorlevel 1 (
echo Deleting %AGE% days old %%D
rd /s /q "%%D"
)
)
)
pause
Don't forget to do a test run first by commenting out the rd line: put rem and a space before it.
Notes:
/L = list-only mode, no copying performed
/V = verbose mode, report files skipped for various reasons, e.g. the "too new" we look for
/S = look in subdirectories
/xjd = don't follow junction points for directories, useful if those point to an unavailable device
^. *too new regular expression in findstr lists lines beginning with a tab character followed by lots of spaces and then too new.

Resources