Is there a way to check if a new folder (exact name is unknown) has been created inside a specific parent folder as a result of running previous commands in bat file? If yes - run one more command with the full path to a new folder as an argument to that command.
Right now I am using a folder monitoring software to run another bat if new folder is created. I would like to have just one script performing both tasks.
Thank you for your help.
change the root_folder location on the second line
#echo off
set "root_folder=C:\something"
setlocal enableDelayedExpansion
set counter=1
for /d /r "%root_folder%" %%a in (*) do (
set "dirs[!counter!]=%%~sa" >nul
set /a counter=counter+1
)
rem ############################
rem # call your code here !!! #
rem ############################
call commands.bat
rem for /l %%l in (1,1,!counter!) do (
rem dir /x /b /s /a:d "%root_folder%" | findstr /i "dirs[%%l]"
rem )
set flag=0
for /d /r "%root_folder%" %%a in (*) do (
set dirs[|find /i "%%~sa" >nul 2>nul ||(
echo "%%~sa" is a new folder
set flag=1
)
)
if %flag% equ 0 (
echo no new folders
)
Related
I need to move few files from one folder to sub folder. My folder structure is already ready.
File current folder: D:\AB\*.*
The file name is: SS-AA-Report-Temp File for Script Testing-Daily-31March.txt
Destination folder: D:\AB\Pm 1.1 File For Script\Daily\
How to check file name substring with folder name substring and move?
Note I have multiple files like this.
set Path1= d:\AB
Pushd %Path1%
echo %Path1%
for %%i in (*.*) do SET "FName=%%~ni"
For /F "Tokens=4-5 Delims=-" %%A In ("%FName%") Do (
Set "FoldOne=%%A"
Set "FoldTwo=%%B"
)
echo out %RDate%
mkdir %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%
move %Path1%\"%FName%".* %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%\
Edit:
File names format:
A-A-Format-Here First connectivity install on Day 0 regurlarly-Daily-All-2017-03-27-09-31-16.xls
A-A-Format-Already First connectivity with 10 days created-Weekly-All-2016-11-28-10-01-02.csv
A-A-Report-withname 1.2 Sample Report (Network Plan Report)-Daily-Detail-2017-01-03-23-53.xls
A-A-Report-Nextreport 1.2 Sample Report (Network Plan Report)-Weekly-Detail-2017-01-03-23-02-53.csv
Now my folder structure is:
D:\AB\Pm 1.1 First connectivity install on Day 0\Daily\05042017
D:\AB\Pm 2.1 First connectivity with 10 days\Weekly\29032017
D:\AB\Pm 1.2 Sample Report\Daily\05042017
D:\AB\Pm 1.2 Sample Report\Weekly\29032017
And here is the batch file I have already:
set Path1= d:\AB
Pushd %Path1%
echo %Path1%
for %%i in (*.*) do SET "FName=%%~ni"
For /F "Tokens=4-5 Delims=-" %%A In ("%FName%") Do (
Set "FoldOne=%%A"
Set "FoldTwo=%%B"
)
echo 1 %FoldOne%
echo 3 %FoldTwo%
IF %FoldTwo% == Daily (
echo here Daily
For /F UseBackQ %%A In (
`PowerShell "(Get-Date).AddDays(-1).ToString('ddMMyyyy')"`
) Do (Set "RDate=%%A"
echo ffor %RDate%
)
)
IF %FoldTwo% == Weekly (
Echo Weekly
For /F UseBackQ %%A In (
`PowerShell "(Get-Date).AddDays(-7).ToString('ddMMyyyy')"`
) Do (Set "RDate=%%A"
echo %RDate%
)
)
mkdir %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%
move %Path1%\"%FName%".* %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%\
Pushd d:\
GoTo :EOF
The logic for matching file name substrings with folder name is still very fuzzy.
However, I coded two possible solutions doing both the same using partly different methods.
The first complete batch code:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
cd /D "D:\AB"
rem Get name of each subfolder starting with string Pm, a space, two single
rem digit numbers separated by a dot, one more space and more characters to
rem indexed environment variables for later usage. And assign the substring
rem after the first 7 characters of each folder name also to an index
rem environment variable.
set FolderIndex=0
for /D %%I in ("Pm ?.? *") do (
set "FolderName!FolderIndex!=%%I"
set "CurrentPath=%%I
set "FolderPart!FolderIndex!=!CurrentPath:~7!"
set /A FolderIndex+=1
)
set "FolderCount=%FolderIndex%"
rem set Folder
rem Get date of yesterday and date of a week ago.
for /F "usebackq" %%I in (`PowerShell.exe "(Get-Date).AddDays(-1).ToString('ddMMyyyy')"`) do set "DateDaily=%%I"
for /F "usebackq" %%I in (`PowerShell.exe "(Get-Date).AddDays(-7).ToString('ddMMyyyy')"`) do set "DateWeekly=%%I"
rem set Date
rem Process now each file matching the wildcard pattern below in
rem current folder and calling a subroutine with current file name.
set "FileNotMoved=0"
for %%I in (*-*-*-*-*) do call :MoveToFolder "%%I"
endlocal & if not %FileNotMoved% == 0 pause
goto :EOF
rem This subroutine first gets fourth and fifth dash delimited part from
rem each passed double quoted file name.
rem Then it replaces in each fourth file name part each folder name part
rem by an empty string until either all folder name parts are processed
rem or the string substitution was successful meaning the file name part
rem really contains the folder name part.
rem Note: The substitution does not work correct if any folder name part
rem contains an equal sign as this character is the delimiter
rem between string to find and replace string for substitution.
rem In second case with substitution being successful the folder for
rem the file could be determined and the file is moved to the found
rem folder if also time part could be determined from file name.
:MoveToFolder
for /F "tokens=4,5 delims=-" %%A in ("%~1") do set "NamePart=%%A" & set "NameTime=%%B"
set "FolderIndex=0"
:FindFolder
if %FolderIndex% == %FolderCount% (
set "FileNotMoved=1"
echo Found no folder for: %1
goto :EOF
)
call set "CurrentPart=%%FolderPart%FolderIndex%%%"
if "!NamePart:%CurrentPart%=!" == "!NamePart!" (
set /A FolderIndex+=1
goto FindFolder
)
call set "CurrentFolder=%%FolderName%FolderIndex%%%"
if /I "%NameTime%" == "Daily" (
set "FolderTime=%DateDaily%"
) else if /I "%NameTime%" == "Weekly" (
set "FolderTime=%DateWeekly%"
) else (
set "FileNotMoved=1"
echo Undefined time for: %1
goto :EOF
)
mkdir "%CurrentFolder%\%NameTime%\%FolderTime%" 2>nul
move "%~1" "%CurrentFolder%\%NameTime%\%FolderTime%\" >nul
if errorlevel 1 (
set "FileNotMoved=1"
echo Failed to move file: %1
)
goto :EOF
The second batch code differs from first solution only on how subroutine MoveToFolder is coded for finding the corresponding folder for current file name. For that reason just the code of the subroutine is posted below.
:MoveToFolder
for /F "tokens=4,5 delims=-" %%A in ("%~1") do set "NamePart=%%A" & set "NameTime=%%B"
for /F "tokens=1* delims==" %%X in ('set FolderPart') do (
if not "!NamePart:%%Y=!" == "%NamePart%" (
set "FolderName=%%X"
goto FoundFolder
)
)
set "FileNotMoved=1"
echo Found no folder for: %1
goto :EOF
:FoundFolder
if /I "%NameTime%" == "Daily" (
set "FolderTime=%DateDaily%"
) else if /I "%NameTime%" == "Weekly" (
set "FolderTime=%DateWeekly%"
) else (
set "FileNotMoved=1"
echo Undefined time for: %1
goto :EOF
)
set "FolderIndex=%FolderName:~10%"
call set "CurrentFolder=%%FolderName%FolderIndex%%%"
mkdir "%CurrentFolder%\%NameTime%\%FolderTime%" 2>nul
move %1 "%CurrentFolder%\%NameTime%\%FolderTime%\" >nul
if errorlevel 1 (
set "FileNotMoved=1"
echo Failed to move file: %1
)
goto :EOF
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 /?
cd /?
echo /?
endlocal /?
for /?
goto /?
if /?
mkdir /?
move /?
pause /?
rem /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and >nul and answer on question Single line with multiple commands using Windows batch file for meaning of operator & on Windows command lines.
Is it possible to make a batch file that will rename a folder if does not have a specific name?
EG:
Parent Directory
- - - > info
- - - > randomfoldername
I have many folders that follow the above pattern. What I would like to do is make a batch file that will rename "randomfoldername" in this structure. There is always two folders in the Parent Directory, one is always "info" and the other changes for each case. Is there a method within a batch file that I could use to always rename the "randomfoldername" directory? I was thinking something along the lines of,
IF NOT == "info" THEN ren... ect.
Is this possible?
you can first check if folder exist then rename folder
if not exist c:\info ( call random.bat )
random.bat:
dir /A:D /b | findstr.exe /n /R "." > s:\sites\file-count.txt
FOR /F "tokens=1-10 delims=:" %%A IN ('type "s:\sites\file-count.txt"') do
set NUMBER-OF-FILES=%%A
FOR /L %%A IN (1,1,%number-of-files%) DO CALL RENAME.bat %%A
rename.bat
:rename
FOR /F "tokens=1-10 delims=:" %%A IN ('type "s:\sites\file-count.txt" ^|
findstr "%1:"') do ren %%B %RANDOM%%%B
also u can use free tool like Bulk Rename Utility
that app has cli for use in bat file here
also You can use powershell script like
$a = test-path c:\info
if ( $a -eq "True" ) { Write-Host nothing to do } Else { gic -directory path | %{$n="$pwd\$((get-random).tostring())$($_.name)";$_.moveto($N)} }
Next script starts with basic checks on command line parameter passed into.
FOR /F loop against the results of another command (dir) used. Next explanation stolen (see dbenham's original) :
FOR /R (as well as the simple FOR) begin iterating immediately, before
it has finished scanning the disk drive. It is possible for the loop
to reiterate the already named file! This would cause it to be renamed
twice, giving the wrong result. The solution is to use FOR /F with
command 'DIR /B', because FOR /F always processes the command to
completion before iterating.
#ECHO OFF >NUL
SETLOCAL enableextensions disabledelayedexpansion
set "ParentDirectory=%*"
if "%ParentDirectory%"=="" goto :usage1
if not exist "%ParentDirectory%\" goto :usage2
if not exist "%ParentDirectory%\info\" goto :usage3
set "SpecificName=Desired Name"
set /A "count=0"
for /F "delims=" %%G in ('dir /B /A:D "%ParentDirectory%\"') do set /A "count+=1"
if %count% neq 2 goto :usage4
for /F "delims=" %%G in ('dir /B /A:D "%ParentDirectory%\"') do (
if /I not "%%~G"=="info" (
if /I not "%%~G"=="%SpecificName%" (
echo renaming "%ParentDirectory%\%%~G" to "%SpecificName%"
rename "%ParentDirectory%\%%~G" "%SpecificName%"
) else (
echo renamed already: "%SpecificName%"
)
)
)
:endlocal
ENDLOCAL
goto :eof
:usage1
echo no paramater
goto :endlocal
:usage2
echo "%ParentDirectory%" folder does not exist
goto :endlocal
:usage3
echo "%ParentDirectory%\info" folder does not exist
goto :endlocal
:usage4
echo "%ParentDirectory%" folder contains %count% subfolders
goto :endlocal
Output:
==>29376745.bat
no paramater
==>29376745.bat x y
"x y" folder does not exist
==>29376745.bat d:\test
"d:\test\info" folder does not exist
==>md "d:\test\info"
==>29376745.bat d:\test
"d:\test" folder contains 6 subfolders
==>29376745.bat d:\test\29376745
renaming "d:\test\29376745\currentName" to "Desired Name"
==>29376745.bat d:\test\29376745
renamed already: "Desired Name"
==>
Required reading (indexes only):
An A-Z Index of the Windows CMD command line
Windows CMD Shell Command Line Syntax
Right now I've got a batch script that is used to go through a bunch of subfolders, and zip up the logfiles therein, the folder structure is basically like this:
+---fakeG
| +---ExclusionFolder
| | +---LimitlessFolders
| | +---MoreFolders
| | \---SoManyFolders
| +---logs1
| +---logs2
| +---logs3
| +---logs4
| +---logs5
| \---logs6
Each of these subfolders must be traversed, and their subfolders traversed as well. This script has to avoid one specific folder, and it does avoid it, but it uses %| find /v. Although in this example, ExclusionFolder is at the top of the list, in the real folder structure it is not.
Here is how I do it now:
FOR /F "delims=" %%A IN (
'DIR "%LogsFilespec%" /B /S ^| find /v "ExclusionFolder"'
) DO CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%zipParams%" %ProcessLog%
Inside ExclusionFolder, there are more subfolders, with potentially many more subfolders, so it would slow down the scripts execution having to go into each of them.
SO: Is there a faster way to exclude a folder from a dir call without |find ?
Or do I have to come up with a totally different way to do this?
Edit Sorry, %LogsFileSpecâ„… refers to the target file. My original edit was right, and my second edit was wrong.
SET LogsLocation="G:\fakeG\Data\Logs"
SET LogsName="trace*%targetDate%.log"
SET LogsFilespec="%LogsLocation%\%LogsName%"
Sorry for not giving more of the script, I figured the question didn't need much.
Edit2 The process :DoZip works like this:
:DoZip
:: Parameter 1 = Filename without .EXT for Archive Name
:: Parameter 2 = Target file specifics
:: Parameter 3 = Zip Command (Winzip/7zip64/7zip32)
:: Parameter 4 = Zip Parameters (a -tzip, -a)
:: Parameter 5 = ProcessLog
setlocal
SET archiveName=%~1
SET SourceFileSpec=%~2
SET zipCommand=%~3
SET zipParms=%~4
SET RunLog=%~5
ECHO %TIME% Archiving %SourceFileSpec%...
ECHO %TIME% Archiving %SourceFileSpec%... >> %RunLog%
ECHO "%zipCommand%" %zipParms% "%archiveName%.zip" "%SourceFileSpec%"
ECHO "%zipCommand%" %zipParms% "%archiveName%.zip" "%SourceFileSpec%" >> %RunLog%
"%zipCommand%" %zipParms% "%archiveName%.zip" "%SourceFileSpec%" >> %RunLog%
:: Check errorlevel of executed command
:: If errorlevel != 0, set EC with the errorlevel and echo that there was an error in archival
IF NOT %ERRORLEVEL%==0 (
ECHO ***ERROR archiving %SourceFileSpec% >> %RunLog%
SET EC=%ERRORLEVEL%
ECHO ***ERRORLEVEL RETURNED: %EC% >> %RunLog%
) ELSE (
:: Otherwise, delete the file
ECHO. >> %RunLog%
ECHO. >> %RunLog%
ECHO %TIME% Deleting %SourceFileSpec%...
ECHO %TIME% Deleting %SourceFileSpec%... >> %RunLog%
::Quietly delete the file
DEL /Q %SourceFileSpec%
:: Set ErrorLevel to capture the Delete command result.
SET EC=%ERRORLEVEL%
)
GOTO :EOF
Edit 3 Here is zipCommand
SET PathWinZip=C:\Program Files\WinZip\wzzip.exe
SET Path7Zip_64bit=C:\Program Files\7-Zip\7z.exe
SET Path7Zip_32bit=C:\Program Files (x86)\7-Zip\7z.exe
:: Check for WinZip
IF EXIST "%PathWinZip%" SET zipCommand=%PathWinZip% & SET zipParms=-a
:: Check for 32-bit version of 7-Zip. If found, configure
:: its command line parameter to produce a .zip file
IF EXIST "%Path7Zip_32bit%" SET zipCommand=%Path7Zip_32bit% & SET zipParms=a -tzip
:: Check for 64-bit version of 7-Zip. If found, configure
:: its command line parameter to produce a .zip file
IF EXIST "%Path7Zip_64bit%" SET zipCommand=%Path7Zip_64bit% & SET zipParms=a -tzip
I believe that the following should exclude the subtree in question:
FOR /F "delims=" %%X IN (
'DIR /B /ad ') DO IF /i "%%X" neq "ExclusionFolder" FOR /F "delims=" %%A IN (
'DIR /B /S "%%X\%LogsFilespec%"'
) DO CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%zipParams%" %ProcessLog%
That is, perform a directory-name scan of the target; if the directory found is not the exclude-name, then do the remainder for that subdirectory.
This approach could be a bit faster:
pushd "%LogsFilespec%"
rem get subfolders of first level only
for /f "tokens=*" %%p in (
'DIR "%LogsFilespec%" /B /AD ^| find /v "ExclusionFolder"'
) do (
rem treat each (here will not be excluded one)
FOR /F "delims=" %%A IN (
'DIR "%%~p" /B /S'
) DO CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%zipParams%" %ProcessLog%
)
popd
goto :eof
The solution below don't use a single FIND command nor a FOR /F ... one (that requires the execution of a copy of cmd.exe), so I think it should run faster:
#echo off
setlocal
rem Enter to the base folder
cd "%LogsFilespec%"
rem Start the recursive process
call :processThisDir
goto :EOF
:processThisDir
rem Process the files in this folder
for %%A in (*.*) do CALL :DoZip "%%~dpnA" "%%~fA" "%zipCommand%" "%zipParams%" %ProcessLog%
rem Process nested subfolders, but omit "ExclusionFolder"
for /D %%a in (*) do (
if "%%a" neq "ExclusionFolder" (
cd "%%a"
call :processThisDir
cd ..
)
)
exit /B
The objective is to display the directory name in MYFOLDER.
MY.exe exists in the folder, but curiously, without the wildcard in ...\desktemp*, the "#echo Showing subfolders" is never displayed, but "#echo G is working" is. However MY.exe is never found when moved to one of the subfolders.
OTOH the current code never finds MY.exe and never displays "#echo G is working" but properly lists each subfolder: "#echo Showing subfolders".
The other problem is the pauses at the end of the block are never reached.
Substituting the inner For with
cd \Users\%USERNAME%\Desktop
for /D /r %%G in ("desktemp*") do (
gets essentially the same result. My.exe isn't found if moved to one of the subfolders of desktemp.
Setlocal EnableDelayedExpansion
set CURRDRIVE=C
SET MYFOLDER=
:SEARCHDRIVES
REM BLOCK
for %%B in (C) do (
if exist %%B: (
PUSHD %%B:\
if NOT DEFINED MYFOLDER (
ECHO "%CD%"
REM This always displays path batch is run from.
REM The above Pushd doesn't change to C:\
for /f "tokens=*" %%G in ('dir /b /s /a:d "%%B:\Users\%USERNAME%\Desktop\desktemp*" ^| find "\"') do (
#echo Showing subfolders
#echo %%G
pause
if exist "%%G\MY.exe" (
call set MYFOLDER=%%G
#echo %%G
#echo G is working
call echo %MYFOLDER%
pause
GOTO GOTMYFOLDER
)
)
)
)
REM Exist Drive
)
REM Drives Loop
:GOTMYFOLDER
cd /d %CURRDRIVE%:\
echo %MYFOLDER%
cd %MYFOLDER%
pause
The above is a chunk whittled from a larger code block: the ultimate aim will be to get the folder names"\Users\New\Desktop\desktemp" into a variable via prompt.
Are the Escape Characters, Delimiters and Quotes in the nested blocks implemented properly?
The answer escaped this poor little brain until it cottoned on to what the "DIR" and "For /D /R" were really up to. What was sought for was in the addition of a new "For /D" (no /R).
This first (extra) "For /D" determines the folder names to iterate from.
(Specifically anything but the Windows directory where we run into problems with >260 filenames.)
This locates the MY.exe file somewhere in the Users folder (more precisely in any root folder beginning with U):
Setlocal EnableDelayedExpansion
set CURRDRIVE=C
SET MYFOLDER=
:SEARCHDRIVES
REM BLOCK
for %%B in (C) do (
if exist %%B: (
PUSHD %%B:\
if NOT DEFINED MYFOLDER (
ECHO "%CD%"
REM This always displays path batch is run from.
REM The above Pushd doesn't change to C:\
for /D %%Z in (U*) do (
cd \%%Z
for /D /r %%G in ("*") do (
if exist "%%G\MY.exe" (
call set MYFOLDER=%%G
#echo %%G
#echo G is working
call echo %MYFOLDER%
pause
GOTO GOTMYFOLDER
)
)
)
)
)
REM Exist Drive
)
REM Drives Loop
:GOTMYFOLDER
cd /d %CURRDRIVE%:\
echo %MYFOLDER%
cd %MYFOLDER%
pause
Edit:
The source of the error spam in the comment below is this command:
Insert batch code to elevate UAC privileges [code][1] from TanisDL
Setlocal EnableDelayedExpansion & pushd "%CD%" & CD /D "%~dp0"
set CURRDRIVE=C
FOR /F "usebackq delims==" %%G IN (dir %CURRDRIVE%:\ /A:D /O:G /S /B ^| FIND /I "myString") DO (set "foundMyString=%%~pG")
Here is what I've come up with, however I can't get the correct reference of xcopy in my code from what Aacini has provided in another post. cmd console will say it cannot find file "!lastName!!baseExt!" and then show that 0 files have been copied. It's not copying because I think the xcopy syntax will not allow for substitutions for the "source" "directory" relationship following xcopy.
Any help would be much appreciated. Thanks
#Echo Off
:: variables
set drive=C:\Users\me\Desktop\Test Source Folder
set backupcmd=xcopy /m /s /c /d /e /h /i /r /y /exclude:AutoFileCopy_Rev1.bat
set basename=
for %%a in ("C:\Users\me\Desktop\Test Source Folder") do (
if not defined baseName (
rem Is first name of first set
set baseName=%%~Na
set baseExt=%%~Xa
set lastname=%%~Na
) else (
rem Check if this name begin with same baseName
set name=%%~Na
for %%b in (!baseName!) do set name=!name:*%%b=!
if "!name!" neq "%%~Na" (
rem Yes: Is next name of same set
set lastName=%%~Na
) else (
rem No: Is first name of next set: copy previous set and pass to next one
%backupcmd% "!lastName!!baseExt!" "C:\Users\me\Desktop\Test Source Folder\! baseName!!baseExt!"
set baseName=%%~Na
set baseExt=%%~Xa
set lastName=%%~Na
)
)
)
rem Copy last set
Set _Delay=10
Set _Monitor=C:\Users\me\Desktop\Test Source Folder\
Set _Base=%temp%\BaselineState.dir
Set _Chck=%temp%\ChkState.dir
Set _OS=6
Ver|Findstr /I /C:"Version 5">Nul
If %Errorlevel%==0 Set _OS=5 & Set /A _Delay=_Delay*1000
:_StartMon
Call :_SetBaseline "%_Base%" "%_Monitor%"
:_MonLoop
If %_OS%==5 (Ping 1.0.0.0 -n 1 -w %_Delay%>Nul) Else Timeout %_Delay%>Nul
Call :_SetBaseline "%_Chck%" "%_Monitor%"
FC /A /L "%_Base%" "%_Chck%">Nul
If %ErrorLevel%==0 Goto _MonLoop
echo ___ Backing up JobBoss files...
::%backupcmd% "C:\Users\john.weakley\Desktop\Test Source Folder" "C:\Users\me\Desktop\Test Destination Folder\"
::CALL "C:\users\me\Desktop\Test Source Folder\Test.bat"
ECHO ___ Checking for new file revisions...
%backupcmd% "!lastName!!baseExt!" "C:\Users\me\Desktop\Test Source Folder\!baseName!! baseExt!"
Echo.Backup Complete!
Goto :_StartMon
:::::::::::::::::::::::::::::::::::::::::::::::::::
:: Subroutine
:::::::::::::::::::::::::::::::::::::::::::::::::::
:_SetBaseline
If Exist "%temp%\tempfmstate.dir" Del "%temp%\tempfmstate.dir"
For /F "Tokens=* Delims=" %%I In ('Dir /S "%~2"') Do (
Set _Last=%%I
>>"%temp%\tempfmstate.dir" Echo.%%I
)
>"%~1" Findstr /V /C:"%_Last%" "%temp%\tempfmstate.dir"
Goto :EOF
You need to enable delayed expansion in order to support !VAR! syntax.
Change your first line to:
#echo off & setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION