Windows batch script issue - windows

I am having an issue with the following Windows batch script. I have multiple XML files in the %indir% that I want to import one at a time and email the report. Basically the section starting with "if /I %v_continue% == y" is not executing as expected. I did some debugging step by step with echo on, and it goes through the script till the %BLAT% command without executing any of the steps, and then it starts execution with the first "copy %script_path%.....". It executes the import.exe correctly, but then nothing gets assigned to %subj% and subsequently the %BLAT% command fails. Any advice?
Thanks!
#echo off
set environment=%1
set domain=%2
if [%environment%] == [] goto :endofscript
rem - Get the script path
set script_path=%~dp0
rem - Get the script name without the extension
set script_name=%~n0
rem - Get the script name with the extension
rem set script_name=%~nx0
rem - get the script extension
set script_ext=%~x0
rem - Set environment variables
call %script_path%\setenv.cmd
set cnt=0
set filemask=*.xml
for /f %%a in ('dir /b /a-d %indir%\%filemask%') do call :procfile %%a
goto :EOF
:procfile
set impfile=%1
set v_continue=n
set emailyn=y
set trset=%impfile:~0,3%
set /A cnt + = 1
if 1%cnt% lss 100 set cnt=0%cnt%
if %trset% == RCT (
set "subtxt=Receipt Confirmation"
set v_continue=y
)
if %trset% == SHP (
set "subtxt=Shipment Confirmation"
set v_continue=y
setlocal EnableDelayedExpansion
set MOFound=
for /f "tokens=3 delims= " %%f in ('find /i /c "<RefID>MO-ORD</RefID>" %indir%\%impfile%') do (set MOFound=%%f)
if !MOFound! GTR 0 (
copy %indir%\%impfile% %inarchdir%
move %indir%\%impfile% %S_INDIR%\FX%dttmstamp%%cnt%.xml 2>NUL
goto :EOF
)
endlocal
)
if /I %v_continue% == y (
copy %script_path%\%script_name%.dat %infile%
cscript %REPLACEVBS% %infile% "DOMAIN" "%domain%" 1>NUL 2>&1
cd /d %rptdir%
%DLC%\bin\import.exe -b -T d:\tmp -p %pfile%
rem - Check for errors
find /i /c "ERROR:" %rptfile% > NUL
if %ERRORLEVEL% NEQ 0 (
set "subj=SUCCESS: %subtxt% Import Report (%environment%/%domain%)"
set emailyn=y
) else (
set "subj=ERROR: %subtxt% Import Report (%environment%/%domain%)"
set emailyn=y
)
move %rptfile% %logdir%\%script_name%_%datestamp%_%cnt%.prn 2>NUL
move %outfile% %logdir%\%script_name%_%datestamp%_%cnt%.out 2>NUL
if /I %emailyn% == y (
echo Report location: %logdir%\%script_name%_%datestamp%_%cnt%.prn > %msgfile%
%BLAT% %msgfile% -server abc-com.mail.protection.outlook.com -f donotreply#abc.com -s "%subj%" -t %INBEMAIL% -attachi %logdir%\%script_name%_%datestamp%_%cnt%.prn
)
)
del /f /q %infile%
del /f /q %pfile%
del /f /q %msgfile%
:delfiles
rem - Delete log files that are older than 10 days.
PushD "%logdir%" && (
forfiles /M %script_name%_*.prn /D -10 /C "CMD /C del /f /q #PATH" 2>NUL
) & PopD
:endofscript
exit /B

Related

Use a Batch File to list files and allow the user to select which file to copy into a new destination

I am a newbie to Windows Scripting.
I am trying to list some txt files in several sub directories & want to copy a user selected file to a new destination. Please note that the file name is unique in different locations.
I got the first part to work (Listing out the files & locations) using the following script, but I am unable to copy the selected file to the new location.
#ECHO OFF
SET index=1
SETLOCAL ENABLEDELAYEDEXPANSION
SET FFPath="C:\Scripts - Backup Server\DKXpress_bkp"
SET NewPath=C:\DKServer
ECHO Recursively searching %FFPath%
echo.
FOR /F "delims=" %%f in ('DIR %FFPath%\*.txt /a:-d /s /b') DO (
SET file!index!=%%f
ECHO !index! - %%f
SET /A index=!index!+1
)
SETLOCAL DISABLEDELAYEDEXPANSION
SET /P selection="select file by number:"
SET file%selection% >nul 2>&1
IF ERRORLEVEL 1 (
ECHO invalid number selected
EXIT /B 1
)
SET NewFile=file%selection%
ECHO Copying %NewFile% to %NewPath%
ECHO.
COPY /Y "%NewFile%" "%NewPath%"
ECHO.
PAUSE
I think I am doing this part wrong
SET NewFile=file%selection%
Thank you all in advance
You don't need to set an index variable or delayed expansion, if you let Find do the work for you:
#Echo Off
Set "FFPath=C:\Scripts - Backup Server\DKXpress_bkp"
Set "NewPath=C:\DKServer"
Echo Recursively searching %FFPath%
Echo=
For /F "Delims==" %%A In ('"Set File[ 2>Nul"') Do Set "%%A="
For /F "Tokens=1* Delims=]" %%A In (
'"Dir /B/S/A-D-S-L "%FFPath%\*.txt" 2>Nul|Find /N /V """') Do (
Echo %%A] %%B
Set "File%%A]=%%B"
)
Echo=
Set /P "#=Select file by number: "
Echo=
For /F "Tokens=1* Delims==" %%A In ('"Set File[%#%] 2>Nul"') Do (
Echo Copying %%B to %NewPath%&Echo=
Copy /Y "%%B" "%NewPath%"
GoTo :End
)
Echo Invalid number selected
:End
Echo=
Pause
You need to use delayed expansion to get the file name assigned to the variable correctly.
SET NewFile=!file%selection%!
Remove the setlocal to disable delayed expansion.
You can try something like that :
#ECHO OFF
:Main
cls
SET index=1
SETLOCAL ENABLEDELAYEDEXPANSION
SET FFPath="C:\Scripts - Backup Server\DKXpress_bkp"
SET "NewPath=C:\DKServer"
ECHO Recursively searching %FFPath%
echo.
FOR /F "delims=" %%f in ('DIR %FFPath%\*.txt /a:-d /s /b') DO (
SET filepath[!index!]=%%f
ECHO [!index!] - %%~nxf - %%f
SET /A index=!index!+1
)
echo(
echo select file by number :
set /p Input=""
For /L %%i in (1,1,%index%) Do (
If "%INPUT%" EQU "%%i" (
ECHO Copying "!filepath[%%i]!" to "!NewPath!"
COPY /Y "!filepath[%%i]!" "!NewPath!"
)
)
echo Copying another file ? (Y = Yes or N = No) ?
set /p input2=""
If /I "!input2!"=="Y" (
goto :Main
) else (
goto :eof
)

Fill backup drive with newest files

I have about 12TB (and growing) library, distributed over 3 HDDs, of video files and I would like to back them up to an external harddrive. I am using Windows 10 Pro.
My backup drive has only 8TB and I would like to always backup the newest 8TB of video files. So far I have tried about 10 sync tools but none of them allowed me to copy files according to creation date.
Also with robocopy I haven't found a way to copy only the latest 8TB of files.
Any suggestions?
I have 2 batch scripts for you that do what you have asked for. The main difference between them is, that the 1st script is using where to locate all the files which will use the timestamp of the last change. To use another timestamp e.g. last access or time of creation you have to use the 2nd script I attached which uses dir.
1.
Batch script using where to locate files:
It takes minimum 2 arguments:
Usage: batch.bat <dst> <src_1> [<src_...> <src_n>]
It uses the where /r <src_n> * /t command which will build a list of all files in all subdirectories with a timestamp of the last change in the following format:
<size> <date> <time> <file name>
5397 11.07.2017 14:32:09 C:\Users\...\foo.txt
10860 12.07.2017 11:25:15 C:\Users\...\bar.log
The timestamp is of last change if you need the time of the creation or last access take the 2nd batch script below which is using dir as there is the possibility to choose between different timestamps.
This output will be written (without the column size) into a temporary file under the temp dir %TEMP% (will be deleted automatically after script) for every source that is passed via the argument list. The complete temporary file is sorted by the date and time, newest first.
This sorted output will be used to copy it into the destination folder.
Example:
Current directory in cmd is C:\...\Desktop):
batch.bat "backup_folder" "F:\folder" "F:\folder with space"
Current directory somewhere:
batch.bat "C:\...\Desktop\backup_folder" "F:\folder" "F:\folder with space"
The C:\...\Desktop\backup_folder will contain 2 folders folder and folder with space which contain all files of these source folders after the scripts operation.
In your case the batch script would copy only 8 TB of the newest files because then the drive will be full and the batch script will exit because it recognizes copy errors.
The batch script:
#echo off
setlocal enabledelayedexpansion
rem Check if at least 2 arguments are passed
set INVARGS=0
if [%1] == [] set INVARGS=1
if [%2] == [] set INVARGS=1
if %INVARGS% == 1 (
echo Usage: %0 ^<dst^> ^<src_1^> ^<src_...^> ^<src_n^>
goto :EOF
)
rem Store Carriage return character in CR (used for spinner function, see below)
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
rem Set temp file name
set "uniqueFile=%TEMP%\%0_%RANDOM%.tmp"
rem Set destination path and shift to next argument
set "dstpath=%~1"
shift
rem Store src_1 to src_n arguments into src array
set idx=0
:again
rem If %1 is blank, we are finished
if not [%1] == [] (
if not exist "%~1" (
echo The following source folder doesn't exist:
echo "%~1"!
echo The program will terminate!
goto :end
)
pushd "%~1"
set "src[%idx%]=!cd!"
if [!src[%idx%]:~-1!] == [\] (
set src[%idx%]=!src[%idx%]:~0,-1!
)
set /a idx=%idx%+1
popd
rem Shift the arguments and examine %1 again
shift
goto :again
)
rem Build command string:
rem where /r "src_1" * /t ^& where /r "src_..." * /t ^& where /r "src_n" * /t ^& break"
set "command="
for /F "tokens=2 delims==" %%s in ('set src[') do (
set "command=!command!where /r "%%s" * /t ^& "
)
set "command=!command!break"
echo "Command: ^<!command!^>"
rem Clear temp file and write files to copy in it
break>"%uniqueFile%"
for /f "tokens=2,3,4,* delims= " %%F in ('!command!') do (
call :spinner
echo %%F %%G %%H %%I>>"%uniqueFile%"
)
rem Open the built file list
echo File list will be opened...
%uniqueFile%
rem Ask user if copying should start
echo Should this files copied into %dstpath%? (Y/N)
set INPUT=
set /P INPUT=Answer?:%=%
if not [%INPUT%] == [y] (
if not [%INPUT%] == [Y] (
goto :end
)
)
set "dstpathPart="
rem Sort files newest first (last changed timestamp)
for /f "tokens=3,* delims= " %%F in ('type "%uniqueFile%" ^| sort /r') do (
rem Build destination part from source folder names
call :buildDestinationPath dstpathPart "%%F %%G"
rem Prepend the destination folder
set "dstFile=!dstpath!\!dstpathPart!"
rem Make directories that doesn't exists
for %%F in ("!dstFile!") do set "directory=%%~dpF"
if not exist "!directory!" ( mkdir "!directory!" )
rem Copy files and echo it
echo copy /y "!file!" "!dstFile!"
copy /y "!file!" "!dstFile!"
echo.
rem If copying failed exit program
if errorlevel 1 (
echo Copying failed... Maybe there is no more space on the disk!
echo The program will terminate!
goto :end
)
)
goto :end
rem Function definitions
:buildDestinationPath
for /F "tokens=2 delims==" %%s in ('set src[') do (
rem Go into folder e.g.: C:\src_1\ --> C:\
pushd "%%s"
cd ..
rem file contains full path of the where command
set "file=%~2"
rem Remove trailing space
if "!file:~-1!" == " " (
call set "file=%%file:~0,-1%%"
)
rem remove src folder from file to make it relative
rem e.g. C:\src_1\foo\bar\file1.txt --> src_1\foo\bar\file1.txt
call set "dstpathPart_temp=%%file:!cd!=%%"
rem Switch back to origin folder
popd
rem If the folder name changed the substring taken was right so take next
if not [!dstpathPart_temp!] == [!file!] (
set "%~1=!dstpathPart_temp!"
goto :next
)
)
:next
goto :EOF
:spinner
set /a "spinner=(spinner + 1) %% 4"
set "spinChars=\|/-"
<nul set /p ".=Building file list... !spinChars:~%spinner%,1!!CR!"
goto :EOF
:end
del "%uniqueFile%"
goto :EOF
2.
Batch script using dir to locate files:
It takes one more argument so that you need minimum 3 arguments:
Usage: batch.bat <timeordering> <dst> <src_1> [<src_...> <src_n>]
It will generate the same list as explained above but with the help of the dir command. The dir command takes the following parameter which is the <timeordering> parameter of the script:
/tc Creation
/ta Last access
/tw Last written
The batch script:
#echo off
setlocal enabledelayedexpansion
rem Check if at least 2 arguments are passed
set INVARGS=0
if [%1] == [] set INVARGS=1
if [%2] == [] set INVARGS=1
if [%3] == [] set INVARGS=1
if %INVARGS% == 1 (
echo Usage: %0 ^<timeordering^> ^<dst^> ^<src_1^> ^<src_...^> ^<src_n^>
goto :EOF
)
rem Store Carriage return character in CR (used for spinner function, see below)
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
rem Set temp file name
set "uniqueFile=%TEMP%\%0_%RANDOM%.tmp"
rem Set timeordering and destination path and shift to next argument
set "timeordering=%~1"
shift
set "dstpath=%~1"
shift
rem Store src_1 to src_n arguments into src array
set idx=0
:again
rem If %1 is blank, we are finished
if not [%1] == [] (
if not exist "%~1" (
echo The following source folder doesn't exist:
echo "%~1"!
echo The program will terminate!
goto :end
)
pushd "%~1"
set "src[%idx%]=!cd!"
if [!src[%idx%]:~-1!] == [\] (
set src[%idx%]=!src[%idx%]:~0,-1!
)
set /a idx=%idx%+1
popd
rem Shift the arguments and examine %1 again
shift
goto :again
)
rem Clear temp file and write files to copy in it
break>"%uniqueFile%"
rem call commands with all sources:
rem call :getFileInformation /TC "src_1\*"
rem /TW
rem /TA
for /F "tokens=2 delims==" %%s in ('set src[') do (
call :getFileInformation %timeordering% "%%s\*" "%uniqueFile%""
)
rem Open the built file list
echo Unsorted file list will be opened...
%uniqueFile%
rem Ask user if copying should start
echo Should this files copied into %dstpath%? (Y/N)
set INPUT=
set /P INPUT=Answer?:%=%
if not [%INPUT%] == [y] (
if not [%INPUT%] == [Y] (
goto :end
)
)
set "dstpathPart="
rem Sort files newest first (last changed timestamp)
for /f "tokens=3,* delims= " %%F in ('type "%uniqueFile%" ^| sort /r') do (
rem Build destination part from source folder names
call :buildDestinationPath dstpathPart "%%F %%G"
rem Prepend the destination folder
set "dstFile=!dstpath!\!dstpathPart!"
rem Make directories that doesn't exists
for %%F in ("!dstFile!") do set "directory=%%~dpF"
if not exist "!directory!" ( mkdir "!directory!" )
rem Copy files and echo it
echo copy /y "!file!" "!dstFile!"
copy /y "!file!" "!dstFile!"
echo.
rem If copying failed exit program
if errorlevel 1 (
echo Copying failed... Maybe there is no more space on the disk!
echo The program will terminate!
goto :end
)
)
goto :end
rem Function definitions
:buildDestinationPath
for /F "tokens=2 delims==" %%s in ('set src[') do (
rem Go into folder e.g.: C:\src_1\ --> C:\
pushd "%%s"
cd ..
rem file contains full path of the where command
set "file=%~2"
rem Remove trailing space
if "!file:~-1!" == " " (
call set "file=%%file:~0,-1%%"
)
rem remove src folder from file to make it relative
rem e.g. C:\src_1\foo\bar\file1.txt --> src_1\foo\bar\file1.txt
call set "dstpathPart_temp=%%file:!cd!=%%"
rem Switch back to origin folder
popd
rem If the folder name changed the substring taken was right so take next
if not [!dstpathPart_temp!] == [!file!] (
set "%~1=!dstpathPart_temp!"
goto :next
)
)
:next
goto :EOF
:getFileInformation
for /f "delims=" %%a in ('dir /s /b /a-d %~1 "%~2"') do (
for /f "tokens=1,2 delims= " %%b in ('dir %~1 "%%a" ^| findstr /l /c:"%%~nxa"') do (
echo %%b %%c %%a>>"%~3"
call :spinner
)
)
goto :EOF
:spinner
set /a "spinner=(spinner + 1) %% 4"
set "spinChars=\|/-"
<nul set /p ".=Building file list... !spinChars:~%spinner%,1!!CR!"
goto :EOF
:end
del "%uniqueFile%"
goto :EOF

adding directory to path environment variable

My requirement is to add one of the directory to path environment variable in windows at the time of installing my application and remove the same from path environment variable at the time of uninstallation using batch file.
In one of the stackoverflow answer related to this suggested the following to add a directory to path environment variable.
setx path C:\Program Files (x86)\MyApp\
It is adding to path variable but when I try to add one more, it overwrites the existing value which I have added. How to avoid this?
How to remove the directory path which I have added from path environment variable?
You should be able to use the existing value of it like this:
setx PATH %PATH%;C:\Program Files (x86)\MyApp\
To remove it you could probably do something like this:
setx PATH=%PATH:;C:\Program Files (x86)\MyApp\=%
Which would substitute the path it was given with nothing to delete it.
You need to check if user's part of path variable is empty, e.g. for adding a directory as follows:
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "_apppath=C:\Program Files (x86)\MyApp\"
set "_keyBase=HKLM\SYSTEM\CurrentControlSet\Control\Session Manager" machine
set "_keyBase=HKCU" user
set "_dataTyp="
set "_dataOld="
for /F "tokens=2,*" %%G in ('
reg query "%_keyBase%\Environment" -V path ^| findstr /I "\<path\>"
') do (
set "_dataTyp=%%G"
set "_dataOld=%%H"
)
if defined _dataOld (
set "_dataNew=%_apppath%;%_dataOld%"
) else (
set "_dataNew=%_dataOld%"
set "_dataTyp=REG_SZ"
)
rem debugging output: show script variables
set _
if /I "%~1" EQU "write" (
reg add "%_keyBase%\Environment" -V path -T %_dataTyp% -d "%_dataNew%" -F
) else (
rem debugging output
ECHO reg add "%_keyBase%\Environment" -V path -T %_dataTyp% -d "%_dataNew%" -F
)
ENDLOCAL
goto :eof
Note that I use reg add instead of setx command. See also this Rojo's answer for exhaustive explanation.
Output.
d:\bat> D:\bat\SO\42140086.bat
_apppath=C:\Program Files (x86)\MyApp\
_dataNew=C:\Program Files (x86)\MyApp\;D:\bare!;D:\Remote
_dataOld=D:\bare!;D:\Remote
_dataTyp=REG_EXPAND_SZ
_keyBase=HKCU
reg add "HKCU\Environment" -V path -T REG_EXPAND_SZ -d "C:\Program Files (x86)\MyApp\;D:\bare!;D:\Remote" -F
d:\bat> D:\bat\SO\42140086.bat write
_apppath=C:\Program Files (x86)\MyApp\
_dataNew=C:\Program Files (x86)\MyApp\;D:\bare!;D:\Remote
_dataOld=D:\bare!;D:\Remote
_dataTyp=REG_EXPAND_SZ
_keyBase=HKCU
The operation completed successfully.
d:\bat> D:\bat\SO\42140086.bat
_apppath=C:\Program Files (x86)\MyApp\
_dataNew=C:\Program Files (x86)\MyApp\;C:\Program Files (x86)\MyApp\;D:\bare!;D:\Remote
_dataOld=C:\Program Files (x86)\MyApp\;D:\bare!;D:\Remote
_dataTyp=REG_EXPAND_SZ
_keyBase=HKCU
reg add "HKCU\Environment" -V path -T REG_EXPAND_SZ -d "C:\Program Files (x86)\MyApp\;C:\Program Files (x86)\MyApp\;D:\bare!;D:\Remote" -F
d:\bat>
Above output shows that the only check if a key is empty does not suffice as running it twice would add the same directory twice as well.
However, checking if a path key (user or machine-wide) contains a particular directory is not such simple task. For instance, some entries in path contain a trailing \ backslash while others don't. Moreover, some entries in a path registry value of REG_EXPAND_SZ could be tangled in other environment variables e.g. %ProgramFiles%\SomeApp instead of C:\Program Files\SomeApp etc.
The following complex script TestPath.bat could help to analyse Windows path environment variables (note that it could show incorrect values if a path contains an exclamation mark ! due to enabled delayed expansion):
#ECHO OFF
set "HkcuEnv=HKCU\Environment"
set "HklmEnv=HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
SETLOCAL enableextensions enabledelayedexpansion
echo --- %date% %time% %~nx0 %*
if /I "%~1" EQU "dir" (
set path
Call :printPath path "" dir %~2
echo/
echo tested using the following findstr regex:
echo "%pathext:;=$ %$"
ENDLOCAL
goto :eof
)
set pathext
Call :duplicity pathext
Call :printPath path ""
Call :duplicity path
set "HKCU_type="
set "HKCU_path="
for /F "tokens=2*" %%G in (
'reg query HKCU\Environment /v Path 2^>NUL ^|findstr /I "path"'
) do (
set "HKCU_type=%%G"
set "HKCU_path=%%H"
)
Call :printPath HKCU_path %HKCU_type%
if /I "%HKCU_type%"=="REG_EXPAND_SZ" Call :printPath HKCU_path %HKCU_type% Expanded
set "HKLM_type="
set "HKLM_path="
set "qqqq=HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
for /F "tokens=2*" %%G in ('reg query "%qqqq%" /v Path^|findstr /I "path"'
) do (
set "HKLM_type=%%G"
set "HKLM_path=%%H"
)
Call :printPath HKLM_path %HKLM_type%
if /I "%HKLM_type%"=="REG_EXPAND_SZ" Call :printPath HKLM_path %HKLM_type% Expanded
echo/
pause
REM echo/
REM set HK
echo/
echo/Usage: %~nx0
echo/ %~nx0 dir
echo/ %~nx0 dir all
ENDLOCAL
goto :eof
:printPath
echo/
echo %~0 %~1 %~2 %~3 %~4
if "!%~1!" NEQ "" (
set "ggg="!%~1:;=" "!""
rem set "ggg=!ggg:\"="!"
for %%G in (!ggg!) do (
if /I "%~3" NEQ "expanded" (
if /I "%~3" EQU "dir" (
set "_partpath=%%~G"
if not "%~4"=="" (
echo/
echo "%%~G"
if /I "!_partpath:%SystemRoot%=!" EQU "%%~G" (
dir /B /A:-D "%%~G" | findstr /I "%pathext:;=$ %$"
echo errorlevel !errorlevel!
if errorlevel 1 pause
rem timeout /T 3 /NOBREAK >NUL
) else (
>NUL (dir /B /A:-D "%%~G" | findstr /I "%pathext:;=$ %$")
echo errorlevel !errorlevel! system default
if errorlevel 1 pause
)
) else (
if NOT "%%~G"=="" (
for /F %%g in ('
2^>NUL dir /B /A:-D "%%~G" ^| findstr /I "%pathext:;=$ %$" ^| find "." /C
') do echo "%%~G" %%g file(s^)
) else (
echo "%%~G" ? file(s^)
)
)
) else (
echo "%%~G"
)
) else (
call echo "%%~G"
)
)
)
goto :eof
:duplicity
echo/
echo %~0 %~1 %~2
set /A "ii=0"
set "ggg="!%~1:;=" "!""
set "ggg=!ggg:\"="!"
for %%G in (!ggg!) do (
set /A "ii+=1"
set /A "jj=0"
for %%g in (!ggg!) do (
set /A "jj+=1"
if /I "%%~G"=="%%~g" if !ii! LSS !jj! echo !ii!, !jj!: %%~g
)
)
goto :eof
REM TODO: unfinished procedure / incorrect output
:deflatePath
echo/
echo %~0 %~1 %~2
set "ggg="!%~1:;=" "!""
rem set "ggg=!ggg:\"="!"
set "NewPath="
for %%G in (!ggg!) do (
set "item=%%~G"
set "meti="
call :deflateItem "ProgramFiles(x86)"
if defined meti (
rem echo # !item!
) else (
call :deflateItem "ProgramFiles"
if defined meti (
rem echo # !item!
) else (
call :deflateItem "SystemRoot"
if defined meti (
rem echo # !item!
) else (
rem echo = !item:%%=%%%%!
)
)
)
if defined NewPath (
set "NewPath=!NewPath!;!item!"
) else (
set "NewPath=!item!"
)
)
echo !NewPath!
rem reg delete HKCU\Environment /v NewPath /f
rem setx NewPath "!NewPath!"
rem WARNING: The data being saved is truncated to 1024 characters.
rem reg query HKCU\Environment /v NewPath|findstr /I "NewPath"
goto :eof
:deflateItem
set "meti=!%~1!"
if "!meti!"=="!item!" (
set "item=%%%~1%%"
) else (
set "meti=!item:%meti%\=!"
if "!meti!" == "!item!" (
set "meti="
) else (
set "item=%%%~1%%\!meti!"
)
)
goto :eof

find multiple files paths with single string

I tried to write a batch script that find all the paths of files that have the same name as the input string. right now it can find only the first file found, and i cant think of a way to make it list multiple files locations. I am not very experienced and I need some help.
this is part of the script code:
:start
cls
echo Enter file name with extension:
set /p filename=
echo Searching...
for %%a in (C D E F G H U W) do (
for /f "tokens=*" %%b in ('dir /s /b "%%a:\%filename%"') do (
set file=%%~nxb
set datapath=%%~dpb\
::the path of the file without the filename included "C:\folder\folder\"
set fullpath=%%b
::the path of the file with the filename included "C:\folder\folder\file"
goto break
)
)
:notfound
cls
echo Enter file name with extension:
echo %filename%
echo File Not Found!
ping localhost -n 4 >nul
goto start
:break
if "%datapath:~-1%"=="\" set datapath=%datapath:~,-1%
cls
echo 3 %filename% found
echo %fullpath1%
echo %fullpath2%
echo %fullpath3%
--- || ---
I want the script to search the computer and list every encountered files with the same name and I want to be able to put those files' paths into different variables.
For example, if readme.txt is the input, then I want the list of all the paths of all the files with that specific name (readme.txt) and I want to set variable for each path so I can use it after that.
input:
readme.txt
output:
3 files found
C:\folder\folder\readme.txt
C:\folder\folder\folder\readme.txt
D:\folder\readme.txt
#echo off
set filename=readme.txt
for %%a in (C D E F G H U W) do (
for /f "tokens=*" %%b in ('dir /s /b "%%a:\%filename%"') do (
echo you can do something here with %%~nxb in %%~dpb
echo full name: %%b
)
)
I see no need to set the filenames to variables, as you can process them inside your loop. But if you really need them (for some reason) in variables:
#echo off
setlocal enabledelayedexpansion
set filename=readme.txt
set count=0
for %%a in (C D E F G H U W) do (
for /f "tokens=*" %%b in ('dir /s /b "%%a:\%filename%" 2^>nul') do (
set /a count+=1
set _file[!count!]=%%b
)
)
set _file
You can try with this code :
#echo off
Title Searching for the path with the same file name
Mode con cols=80 lines=3 & Color 9E
SET /a Count=0
set /a cnt=1
set "FileName=Readme.txt"
set "Report=%~dp0Report.txt"
set "Folder2Copy=%~dp0Readme_Folder"
set "Result2Copy=%~dp0Result2Copy.txt
If exist %Folder2Copy% RD /S /Q %Folder2Copy%
If Exist %Report% Del %Report%
If Exist %Result2Copy% Del %Result2Copy%
echo(
Echo Searching for the path with the same file name
Rem Looking for fixed drives and store them into variables
SETLOCAL enabledelayedexpansion
For /f "skip=1" %%a IN ('wmic LOGICALDISK where driveType^=3 get deviceID') DO (
for /f "delims=" %%b in ("%%a") do (
SET /a "Count+=1"
set "Drive[!Count!]=%%b"
)
)
:Display
for /L %%i in (1,1,%Count%) do (
cls
Title Please wait a while ... Searching for "%FileName%" on "!Drive[%%i]!\"
echo(
echo Please wait a while ... Searching for "%FileName%" on "!Drive[%%i]!\"
Call :FindPathFile !Drive[%%i]!\ %FileName% >> %Report%
)
Start "" %Report%
Goto :AskQuestion
::***************************************************************************************
:FindPathFile <Location> <FileName>
Where.exe /r %1 %2
Goto :eof
::***************************************************************************************
:AskQuestion
cls & Mode con cols=100 lines=5
echo(
echo Did you want to make copy of all files found as name "%FileName%"
echo saved on "%Report%" ? (Y/N) ?
set /p "Input="
If /I "%INPUT%"=="Y" (
for /f "delims=" %%i in ('Type "%Report%"') do (
Call :MakeCopy "%%~i" "%Folder2Copy%\"
)
)
Call :Explorer "%Folder2Copy%\" & exit
If /I "%INPUT%"=="N" (
Exit
)
Goto :eof
::***************************************************************************************
:MakeCopy <Source> <Target>
If Not Exist "%~2\" MD "%~2\" (
if not exist "%2\%~n1" (
echo copying "%~1" to "%~2"
copy /N /B "%~1" "%~2" >>%Result2Copy% 2>&1
) else (
call :loop "%~1" "%~2"
)
)
::***************************************************************************************
:loop
set "fname=%2\%~n1(%cnt%)%~x1"
if exist "%fname%" set /a cnt+=1 && goto :loop
copy "%~1" "%fname%"
exit /b
::***************************************************************************************
:Explorer <file>
explorer.exe /e,/select,"%~1"
Goto :EOF
::***************************************************************************************

Find string in multiple .txt files

I have a folder with many .txt files. I would like to find string "X" in all of these files then I would like to copy the found strings into .txt files into a different folder.
So far I have tried :
#echo on
findstr /m "X" "%userprofile%\Desktop\New_Folder\New_Folder\*.txt"
if %errorlevel%==0 do (
for %%c in (*.txt) do (
type %%c >> "%UserProfile%\Desktop\New_Folder\%%~nc.txt"
pause
I do not understand the output %%~nc.txt part it's suppost to copy the changed .txt files to a new folder with the same name.
I would like to point out that string "X" is found in different places in the .txt file.
This batch file can did the trick (-_°)
So, just give a try : ScanfilesWordSearch_X.bat
#ECHO OFF
::******************************************************************************************
Title Scan a folder and store all files names in an array variables
SET "ROOT=%userprofile%\Desktop"
Set "NewFolder2Copy=%userprofile%\Desktop\NewCopyTxtFiles"
SET "EXT=txt"
SET "Count=0"
Set "LogFile=%~dp0%~n0.txt"
set "Word2Search=X"
SETLOCAL enabledelayedexpansion
REM Iterates throw the files on this current folder and its subfolders.
REM And Populate the array with existent files in this folder and its subfolders
For %%a in (%EXT%) Do (
Call :Scanning "%Word2Search%" "*.%%a"
FOR /f "delims=" %%f IN ('dir /b /s "%ROOT%\*.%%a"') DO (
( find /I "%Word2Search%" "%%f" >nul 2>&1 ) && (
SET /a "Count+=1"
set "list[!Count!]=%%~nxf"
set "listpath[!Count!]=%%~dpFf"
)
) || (
( Call :Scanning "%Word2Search%" "%%~nxf")
)
)
::***************************************************************
:Display_Results
cls & color 0B
echo wscript.echo Len("%ROOT%"^) + 20 >"%tmp%\length.vbs"
for /f %%a in ('Cscript /nologo "%tmp%\length.vbs"') do ( set "cols=%%a")
If %cols% LSS 50 set /a cols=%cols% + 20
set /a lines=%Count% + 10
Mode con cols=%cols% lines=%lines%
ECHO **********************************************************
ECHO Folder:"%ROOT%"
ECHO **********************************************************
If Exist "%LogFile%" Del "%LogFile%"
rem Display array elements and save results into the LogFile
for /L %%i in (1,1,%Count%) do (
echo [%%i] : !list[%%i]!
echo [%%i] : !list[%%i]! -- "!listpath[%%i]!" >> "%LogFile%"
)
(
ECHO.
ECHO Total of [%EXT%] files(s^) : %Count% file(s^) that contains the string "%Word2Search%"
)>> "%LogFile%"
ECHO(
ECHO Total of [%EXT%] files(s) : %Count% file(s)
echo(
echo Type the number of file that you want to explore
echo(
echo To save those files just hit 'S'
set /p "Input="
For /L %%i in (1,1,%Count%) Do (
If "%INPUT%" EQU "%%i" (
Call :Explorer "!listpath[%%i]!"
)
IF /I "%INPUT%"=="S" (
Call :CopyFiles
)
)
Goto:Display_Results
::**************************************************************
:Scanning <Word> <file>
mode con cols=75 lines=3
Cls & Color 0E
echo(
echo Scanning for the string "%~1" on "%~2" ...
goto :eof
::*************************************************************
:Explorer <file>
explorer.exe /e,/select,"%~1"
Goto :EOF
::*************************************************************
:MakeCopy <Source> <Target>
If Not Exist "%~2\" MD "%~2\"
Copy /Y "%~1" "%~2\"
goto :eof
::*************************************************************
:CopyFiles
cls
mode con cols=80 lines=20
for /L %%i in (1,1,%Count%) do (
echo Copying "!list[%%i]!" "%NewFolder2Copy%\"
Call :MakeCopy "!listpath[%%i]!" "%NewFolder2Copy%">nul 2>&1
)
Call :Explorer "%NewFolder2Copy%\"
Goto:Display_Results
::*************************************************************
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "mystring=x"
FOR %%a IN ("%sourcedir%\*.txt") DO FINDSTR "%mystring%" "%%a">nul&IF NOT ERRORLEVEL 1 FINDSTR "%mystring%" "%%a">"%destdir%\%%~nxa"
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances and set mystring appropriately, noting that you may have to adjust the findstr switches to accomodate case, literal and space-in-target-string.
Naturally, you could code sourcedir etc. directly as literals, but doing it this way means that the relevant strings need only be changed in one place.
You are close, but checking the ErrorLevel of findstr does not make sense here as this reflects the overall result, that is, ErrorLevel is set to 0 in case any of the files contain the search string.
I would parse the output of findstr /M using a for /F loop and copy the returned files in the body:
for /F "eol=| delims=" %%F in ('
findstr /M /I /C:"X" "%USERPROFILE%\Desktop\New_Folder\New_Folder\*.txt"
') do (
copy "%%F" "%USERPROFILE%\Desktop\New_Folder\"
)
This copies all those files which contain the literal search string (in a case-insensitive manner).

Resources