How to get ERRORLEVEL of a command in forfiles? - batch-file

I need to handle files older than a day. Thereforw I use this:
forfiles -m %%~nxf /C "cmd /c start /wait /MIN 7z.exe t %%f" /d +1
Now I'd like to check if the progress of 7z.exe succeeded. How can I get the errorlevel of the command inside the forefiles command? Is there any possibility?
I already tried following ways which did not work. errorlevel always returns 0, even if I use broken files, that should return an error (2).
forfiles -m %%~nxf /C "cmd /c start /wait /MIN 7z.exe t %%f && echo ok || echo delete %%f" /d +1
forfiles -m %%~nxf /C "cmd /c start /wait /MIN 7z.exe t %%f && if errorlevel 2 (DEL %%f)" /d +1

Assuming 7z.exe does really deliver an ErrorLevel, I think that the conditional command separators query the ErrorLevel of cmd rather than of 7z.exe. The following should work:
forfiles /M "%%~nxf" /C "cmd /C 0x22start /WAIT /MIN 7z.exe t 0x22%%~f0x22 && echo ok || echo delete 0x22%%~f0x220x22" /D +1
Or you can do that also without start:
forfiles /M "%%~nxf" /C "cmd /C 0x227z.exe t 0x22%%~f0x22 && echo ok || echo delete 0x22%%~f0x220x22" /D +1
As you might have noticed, I also fixed some quote issues for the given paths.

Related

Batch script Mix Forfiles Cmd to print a PDF

I'm stuck with this script
echo off
SET pathAdobe="C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
SET pathDestination=T:\
cd %pathDestination%
(1)
forfiles /P %pathDestination% /M *8.pdf /D +0 /C "cmd /c echo #PATH"
(2)
"C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe" /o /h /s /t "%pathDestination%\pdf8.pdf" "MyPrinterName"
pause
(1) Work fine, i got a list of pdf according my forfiles
(2) Work fine, print my file
(3) But when i want to mix the 2 first step that doesn't work like i want
forfiles /P %pathDestination% /M *8.pdf /D +0 /C "CMD /C "%pathAdobe%" /o /h /s /t #PATH"
I got this error:
Error: Invalid argument or option - « Files\Adobe\Acrobat »
I try to escape with ^ " \ but don't change the result
Can't find a solution!
Thanks for any help you can give me :)
J
Your issue is that you are including double quotes, in the wrong places, and that those double quotes require escaping. You can escape those using backward slashes (\"), or by using their hexadecimal character code, (0x22).
Backward slash example:
#Echo Off
Set "pathAdobe=%ProgramFiles%\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
Set "pathDestination=T:\"
CD /D "%pathDestination%" 2> NUL || Exit /B
%SystemRoot%\System32\forfiles.exe /M "*8.pdf" /D 0 /C "%SystemRoot%\System32\cmd.exe /D /C \"\"%pathAdobe%\" /o /h /s /t #Path \"MyPrinterName\"\""
Pause
Hexadecimal character example:
#Echo Off
Set "pathAdobe=%ProgramFiles%\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
Set "pathDestination=T:\"
CD /D "%pathDestination%" 2> NUL || Exit /B
%SystemRoot%\System32\forfiles.exe /M "*8.pdf" /D 0 /C "%SystemRoot%\System32\cmd.exe /D /C 0x220x22%pathAdobe%0x22 /o /h /s /t #Path 0x22MyPrinterName0x220x22"
Pause

Batch File path with an [at] # sign

I am trying to run a script to clear out the recycle bin on a QNAP NAS periodically.
The problem is the path for the recycle bin on the NAS includes an [at] sign:
"\nas01\SQLBackup\#Recycle" (Had to use double slash here to get it to display correctly)
Can someone please point me in the right direction as to what I'm doing wrong?
Thanks in advance for your help.
Batch File Code
#ECHO ON
NET USE X: "\\nas01\SQLBackup\#Recycle"
forfiles /p "X:\" /s /m * /c "cmd /c del #path"
NET USE X: /delete
PAUSE
Output
C:\Windows\system32>NET USE X: "\\nas01\SQLBackup\#Recycle"
The command completed successfully.
C:\Windows\system32>forfiles /p "X:\" /s /m * /c "cmd /c del #path"
ERROR: Invalid argument/option - '#path'.
Type "FORFILES /?" for usage.
C:\Windows\system32>NET USE X: /delete
X: was deleted successfully.
C:\Windows\system32>PAUSE
Press any key to continue . . .
The reason you get the error is due to the double quotes around the path, where backslash is present. The backslash escapes the last double quote. You should either use:
forfiles /p "X:" /s /m * /c "cmd /c del #path"
or
forfiles /p X:\ /s /m * /c "cmd /c del #path"
anyway, I would not use forfiles at all here. You can quite simply use del /s:
net use X: "\\nas01\SQLBackup\#Recycle"
pushd "x:\">nul 2>&1 && del /Q /S *.* || echo X:\ Not available.
popd
net use X: /delete
pause
Quite simply, we attempt pushd to x:\ if not available, it will fail with a message, if available it will del /s everything on X:\ where /s is basically recursive search throughout the root of X:\ in this instance.
The #-symbol in your path does not cause the error. It is the backslash in:
forfiles /p "X:\" /s /m * /c "cmd /c del #path"
that unintentionally escapes the closing quote (this is specific to forfiles!). To avoid that, simply append a . to the path, like:
forfiles /p "X:\." /s /m * /c "cmd /c del #path"
The . means current directory, so in a path it does not change anything, hence X:\ equals X:\., and D:\some\.\path equals D:\some\path. Of course, you could just remove the quotes around X:\ in your particular situation, but appending . is a general solution that even works with a relative path like X: (meaning the current directory of drive X:), and removal of quotes introduces problems with paths containing SPACEs.
By the way, are you aware that forfiles returns both files and directories, and that del is there to delete just files, and there is rd to delete directories?
So to ensure to handle only files, use this:
forfiles /S /P "X:\." /M * /C "cmd /C if #isdir==FALSE del #path"
And to ensure to handle only directories, use this:
forfiles /S /P "X:\." /M * /C "cmd /C if #isdir==TRUE rd /S /Q #path"
Of course you can handle both, if you want:
forfiles /S /P "X:\." /M * /C "cmd /C if #isdir==TRUE (rd /S /Q #path) else (del #path)"
When you use PushD, it will create a temporary drive map, (allocated in available reverse alphabetical order, Z:..A:), and will then use that new drive. For that reason you should be able to do this without using net.exe.
Example:
#PushD "\\nas01\SQLBackup\#Recycle" 2> NUL && (RD /S /Q . 2> NUL & PopD)
This example uses RD to Remove the Directory instead of your used Del command. When the target directory is the current working directory, it cannot be removed, (returning an error message), however its contents will be. The code above redirects the error message to the NUL device, so that it is not output.

Get list of empty folders older then x days

I need to get a list of empty folders in a given location, older then x days. Using "forfiles" I'm able to get all older folders, but not the empty ones. Using "for" I'm able to get all empty folders, but I can't seem to set the older ones.
Get empty folders:
#for /r "c:\FileStore" /d %F in (.) do #(dir /b "%F" | findstr "^" >nul || echo %~fF)
Get older folders:
ForFiles /p "C:\FileStore" /s /d -3 /c "cmd /c if #isdir==TRUE echo #path"
How do I combine these 2 commands?
You need to escape the quotation marks of the part findstr "^" for forfiles. There is the way \", but I do not recommend this, because the " are still recognised by the command interpreter cmd (user Ben Personick shows how to do this in his answer though). Anyway, I would use 0x22 instead in order to hide the quotes from cmd, like this:
forfiles /S /P "C:\FileStore" /D -3 /C "cmd /C if #ISDIR == TRUE (dir /B /A #PATH | findstr 0x22^0x22 > nul || echo #PATH)"
Instead of findstr "^" you could also use find /V "":
forfiles /S /P "C:\FileStore" /D -3 /C "cmd /C if #ISDIR == TRUE (dir /B /A #PATH | find /V 0x220x22 > nul || echo #PATH)"
But the easiest way is to use set /P:
forfiles /S /P "C:\FileStore" /D -3 /C "cmd /C if #ISDIR == TRUE (dir /B /A #PATH | set /P _= || echo #PATH)"
N. B.:
forfiles only regards the date (not the time) of the last modification, but not the creation date/time.
Your biggest hurdle is escaping the double quotes in the FindStr and the Carrot needing doubling too (or it will stop the following quote from being escaped.)
Hmm strange I thought you asked to delete these directories, since you haven't I'll amend it as such.
ForFiles /P "c:\FileStore" /d -3 /C "CMD /C if #isdir==TRUE ( DIR /B #Path | FindStr \"^^\" >NUL || ECHO Empty Folder: #Path )"
Also since you are only looking for a list of those it does make sense to kill the output from the FindStr so I added the >Nul back in.
Again not sure how I ot it into my head that you wanted to remove the empty folders older than 3 days old, since there isn't such a requirement, the portion about needing to re-run the command is moot and I've remove dit for now.

Batch file (ForFiles multiple conditional commands for logic)?

I am just getting into Bat files.
I am trying to delete old folders on a network shared drive but skip 2 of the containing folders by name.
Basically I need to all files that I make daily and always keep 2 old files.
Code that deletes all files that are older than 3 days:
PushD "\\****-****\build" &&(
ForFiles /D -3 /C "CMD /C if #ISDIR==TRUE echo RD #FILE &RD /S #FILE
) & PopD
And I was thinking something like this: if NOT #FNAME == %name%. I don't totally understand the process, am I able to have two conditions in the forFiles? do I have to have /c before?
PushD "\\****-****\build" &&(
ForFiles /D -3 /C "CMD /C if NOT #FNAME == %name% if #ISDIR==TRUE echo RD #FILE &RD /S #FILE
) & PopD
I can't seem to get it, would you mind helping me out?
Thanks!
Yes, nesting if commands in their then branches is the way how-to have logical AND. Note proper quoting in next code snippet:
#ECHO ON >NUL
#SETLOCAL enableextensions
set "name=SO"
set "nam2=SU"
pushd "D:\VB_scripts"
#rem all directories
ForFiles /D -2 /C "CMD /C if #ISDIR==TRUE echo #FILE"
#rem all directories except "SO"
ForFiles /D -2 /C "CMD /C if #ISDIR==TRUE if not #FNAME=="""%name%""" echo #FILE"
#rem all directories except "SO" and "SU"
ForFiles /D -2 /C "CMD /C if #ISDIR==TRUE if not #FNAME=="""%name%""" if not #FNAME=="""%nam2%""" echo #FILE"
popd
#ENDLOCAL
Output:
==>D:\bat\SO\31346676.bat
==>set "name=SO"
==>set "nam2=SU"
==>pushd "D:\VB_scripts"
==>ForFiles /D -2 /C "CMD /C if #ISDIR==TRUE echo #FILE"
"Class Pack"
"Oldies"
"SO"
"SU"
"WMI"
==>ForFiles /D -2 /C "CMD /C if #ISDIR==TRUE if not #FNAME=="""SO""" echo #FILE"
"Class Pack"
"Oldies"
"SU"
"WMI"
==>ForFiles /D -2 /C "CMD /C if #ISDIR==TRUE if not #FNAME=="""SO""" if not #FNAME=="
""SU""" echo #FILE"
"Class Pack"
"Oldies"
"WMI"
==>popd
It is a little bit messy but I was able to do it on a local directory:
#echo off
mkdir Temp\Temp
REM Copy all old file to Temp dir
forfiles -p "%cd%" -m *.* /D -2 /C "cmd /c xcopy #path %cd%\Temp"
REM copy a random file from Temp dir to Temp/Temp dir and then delete it
FOR %%A in (%cd%\Temp\*) do (
COPY "%%A" %cd%\Temp\Temp\
DEL "%%A"
GOTO :Second
)
:Second
Rem copy second random file from Temp dir
FOR %%A in (%cd%\Temp\*) do (
COPY "%%A" %cd%\Temp\Temp\
GOTO :Del
)
:Del
Rem delete all old files from local dir
forfiles -p "%cd%" -m *.* /D -2 /C "cmd /c del #path"
Rem Copy back two random old files to local dir
xcopy %cd%\Temp\Temp\* %cd%
Rem remove Temp dir
rmdir /s /q Temp

Forfiles - spaces in folder path

I am running a batch file and I have one forfiles command in it
FORFILES -p%spinputarchrootpath% -m*.csv -d-365 -c"CMD /C DEL #FILE"
%spinputarchrootpath% variable maps to a folder location (Y:\Temp Documents\testfolder).
Now the above command is throwing an error because of the space in the folder name (Temp Documents).
How to handle this space? I have tried putting quotes around %spinputarchrootpath% variable but it is not working.
I'd the same problem and found the solution.
I think your folder-variable of the folder you wish to empty has a backslash at the end.
This will NOT work:
echo J|forfiles /P "C:\temp files\" /S /M * /D -7 /C "cmd /c del /F /S /Q #path"
... but this works (without backslash)
echo J|forfiles /P "C:\temp files" /S /M * /D -7 /C "cmd /c del /F /S /Q #path"
Regards
Tino
Enclose the path in quotes:
FORFILES -p "%spinputarchrootpath%" -m *.csv -d -365 -c "CMD /C DEL #FILE"
Note, there's a space between -p and "%spinputarchrootpath%". Without a space in this case it won't work.
As a work around first change directories to the folder you want, and then execute forfiles without the /p parameter.
CD %spinputarchrootpath%
FORFILES -m*.csv -d-365 -c"CMD /C DEL #FILE"
Check post:
How to Tell FORFILES to Execute Command on Path?
The problem lies in the part:
-c"CMD /C DEL #FILE"
Use:
-c"CMD /C DEL ^0x22#FILE^0x22"
to put extra double quotes around the file

Resources