Execute VBS from Batch on All Files in Directory - batch-file

How can I loop the following batch code on all files in a directory:
for /f "tokens=*" %%f in ('dir /b *.txt') do (
set OldFile=%cd%/%%f
set NewFile=%cd%/2%%f
echo. > "%NewFile%"
start far.vbs "%NewFile%" "%OldFile%"
)
where the far.vbs is as follows:
Set OldFile = CreateObject("Scripting.FileSystemObject")
Set rdOldFile = OldFile.OpenTextFile(WScript.Arguments(1), 1)
oContent = rdOldFile.ReadAll
rdOldFile.Close
Set lOldFile = CreateObject("Scripting.FileSystemObject")
Set lrdOldFile = OldFile.OpenTextFile(WScript.Arguments(1), 1)
oLen = Len(lrdOldFile.ReadAll)
lrdOldFile.Close
oData = oContent
oData = Right(oContent, oLen-1)
oData = Left(oData, oLen-2)
Set NewFile = CreateObject("Scripting.FileSystemObject")
Set fData = NewFile.OpenTextFile(WScript.Arguments(0), 2)
fData.WriteLine (oData)
fData.Close
Currently no file is generating and the vbs code does not seem to execute. The directory should contain a text file with some generic string and the far.vbs script with remove the first and last two characters.
The Purpose of this script is to delete the portions of unnecessary characters from multiple files in a folder.

Variable expansion in a for loop doesn't work the way you expect. The entire loop is read as one statement, and all %var% are expanded at that point. To make your code work you need to enable delayed expansion. You may also want to use cscript.exe instead of start.
setlocal EnableDelayedExpansion
for /f "tokens=*" %%f in ('dir /b *.txt') do (
set "OldFile=%cd%/%%f"
set "NewFile=%cd%/2%%f"
echo. > "!NewFile!"
cscript.exe //NoLogo far.vbs "!NewFile!" "!OldFile!"
)

Related

Parse specific strings (2 strings) from multiple text files from a folder

I am trying to parse multiple lines which starts with:
Procedure = xxxxx::xxxx
Description = xxxxxx
Also, I want to ignore SH Library Procedure = $(Stem)_test which has same word Procedure in the .txt file.
I want to search all *.txt files and accumulate date in output file which I will use to upload in req management tool.
Here is the sample of the file:
Harness Lib Greenhills BLD Add Excluded Files = FALSE
Harness Lib Template Project File =
Harness Lib Generated Project File =
Harness Lib Generate Compiler Project File = FALSE
SH Library Procedure = $(Stem)_test
Harness Lib Source Lists Add Excluded Files = FALSE
Harness Lib Substitute Unused Source Files = FALSE
Macro Standard 1 = Set TBRUN_MACRO_STANDARD_1 in Testbed.ini
Procedure = sander_class::sander_class
Member Of = 1
Creation Date = Jun 21 2019 14:36:44
Description = This test is to verify that constructor is called. Req Tested: 67060-SWINTR-73
I have tried below code, but it does not print Procedure and in specific format.
#echo off
(
for /f "tokens=1,*" %%a in ('find "Procedure =" ^< "TEST.txt"') do (
for /f "tokens=1,*" %%d in ('find "Description =" ^< "TEST.txt"') do (
for /f "tokens=1,2 delims=#" %%c in ("%%b") do (
echo(Procedure %%~nxc
echo(
echo(Procedure %%a
echo(
echo(Description %%d
echo(
echo(Path: %%~pb
echo(
)
)
)>"output file.txt"
pause
I need output in below format for all the files (.txt) in same folder:
File Name =
Procedure = sander_class::sander_class
Description = This test is to verify that constructor is called. Req Tested: 67060-SWINTR-73
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q57185510.txt"
SET "outfile=%destdir%\outfile.txt"
(
FOR /f "tokens=*" %%a IN (
'findstr /R /b /C:" *Procedure =" /c:" *Description =" "%filename1%" '
) DO ECHO %%a
)>"%outfile%"
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances. The listing uses a setting that suits my system.
I used a file named q57185510.txt containing your data for my testing.
Produces the file defined as %outfile%
I used the one specific file for testing; for all files then set filename1 to a filemask like *.txt.
The findstr looks in all files matching filename1 for lines that /b begin with /r regular-expressions /c:"regex-string" the "regex-string". "regex" here is a small subset of regular expressions, but the particular expressions of interest are for instance Space(any number of)ProcedureSpace= which matches the two lines in question.
The tokens=* suppresses the leading spaces, producing the required lines.
Okay, This should do it but I can't test at the moment.
#(
ECHO OFF
SETLOCAL EnableDelayedExpansion
SET "_FilePath=C:\Admin"
SET "_FileGlob=*.txt"
SET "_MatchRegex1=Procedure =.*::.*$"
SET "_MatchRegex2=Description = .*::.*$"
SET "_ExcludeRegex=^SH Library Procedure =.*$"
SET "_OutputFile=%Temp%\output file.txt"
)
FOR /F "Tokens=*" %%A IN ('
DIR /A-D /S /B "%_FilePath%\%_FileGlob%"
') DO (
SET "_FileName=%%~nxA"
SET "_CurrentFile=!_FileName: =_!"
FOR /F "Tokens=1*" %%a IN ('
FindStr /I /R
/C:"%_MatchRegex1%"
/C:"%_MatchRegex2%"
"%%A"
^| FindStr /I /R /V
/C:"%_ExcludeRegex%"
') DO (
IF NOT DEFINED !_CurrentFile! (
SET "!_CurrentFile!=Found"
ECHO.File Name: !_FileName!
)
ECHO.%%a %%b
)
)>> "_OutputFile"
PAUSE
I will have to come back through and write up exactly what is being done in more detail if needed.
Essentially I am just using a loop of a DIR command to find all of the .txt files in all directories and subdirectories under the given path.
Then I parse that pull out the file name portion and create a variable I can use to match if the file has already been parsed before so that we only print the file name once.
I don't want to print file names at all unless a match was made because I don't think you care to see long lists of files with no matches, but if you prefer that the logic to test if the file name was found previously can be removed and you can just spit out the file name in the first loop
The second loop is looping the results of running a FindStr command on the given file found in the first loop and matching the Regexes which should mean at least two entries per file more if there are more procedures.
FindStr allows sRegex Matches and /V means to exclude any string that matches and pass the rest.

Move file to other folder and send the folder URL on email attachment

Batch file:
#echo off
set source=D:\teste
set target=D:\trab
for /F "delims=" %%I in ('dir %source%\*.* /A:-D /O:D /B') do move %source%\%%I %target% & echo %%I %source%\%%I & goto :continue
:continue
set p/ AttachmentFullName=%target%\<<fileName.txt>>
cscript.exe //NoLogo "D:\partilhas\correo.vbs" %AttachmentFullName%
timeout 20
VBScript file:
Set objMail = CreateObject("CDO.Message")
Set objConf = CreateObject("CDO.Configuration")
Set objFlds = objConf.Fields
Dim attachmentFullName
attachmentFullName = WScript.Arguments.Named("%AttachmentFullName%")
objFlds.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2 'cdoSendUsingPort
objFlds.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mail.SMTP.com"
objFlds.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
'objFlds.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = "NAME"
'objFlds.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "PWS"
'objFlds.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1 'cdoBasic
objFlds.Update
objMail.Configuration = objConf
objMail.From = "EMAIL#EMAIL.com"
objMail.To = "EMAIL#EMAIL.com"
objMail.Subject = "Email Subject Text"
objMail.AddAttachment attachmentFullName
objMail.TextBody = "The message of the email..."
objMail.Send
Set objFlds = Nothing
Set objConf = Nothing
Set objMail = Nothing
What I want is to get the file from a folder oldest to newest one by one and send an email with each attached. As the file number to send the same mail number and move the same number of times. Someone help?
Your question isn't too clear about the problem you're having, but presumably it's your parameter passing.
The line
attachmentFullName = WScript.Arguments.Named("%AttachmentFullName%")
assigns the argument of a named parameter %AttachmentFullName% to the variable attachmentFullName. However, for that to work you'd have to actually call the VBScript with a named parameter of that name. Named parameters in VBScript work like this:
cscript.exe script.vbs /param:value
meaning that in your case the call would have to look like this:
cscript.exe script.vbs /^%AttachmentFullName^%:value
to actually get a parameter name beginning and ending with a % character.
More likely you want to pass the value of the batch variable %AttachmentFullName% to the VBScript as an unnamed argument. To do that change the statement
attachmentFullName = WScript.Arguments.Named("%AttachmentFullName%")
to this:
attachmentFullName = WScript.Arguments.Unnamed(0)
and call the VBScript like this:
cscript.exe //NoLogo "D:\partilhas\correo.vbs" "%AttachmentFullName%"
Note the double quotes around the variable, so your scripts don't break when a path contains spaces.
As for getting that batch variable assigned with a value in the first place, currently you seem to echo the filename in your for loop and prompt the user to enter it manually.
set p/ AttachmentFullName=%target%\<<fileName.txt>>
For one thing, the above statement is incorrect and would throw an error. But even if it actually worked you should assign the path to your variable inside the loop instead of requiring user interaction:
for /F "delims=" %%I in ('dir %source%\*.* /A:-D /O:D /B') do (
move "%source%\%%~I" "%target%"
set "AttachmentFullName=%target%\%%~I"
goto :continue
)
Edit: To add all copied files you need to remove the goto from the loop and append to the variable (requires delayed expansion). Add double quotes around each path inside the loop, and don't put double quotes around the attachments variable when passing it to the VBScript:
setlocal EnableDelayedExpansion
for /F "delims=" %%I in ('dir %source%\*.* /A:-D /O:D /B') do (
move "%source%\%%~I" "%target%"
set "Attachments=!Attachments! ^"%target%\%%~I^""
)
cscript.exe //NoLogo "D:\partilhas\correo.vbs" %Attachments%
Then have the VBScript iterate over the (unnamed) arguments and attach each of them to the mail:
For Each arg In WScript.Arguments.Unnamed
objMail.AddAttachment arg
Next

Batch File: Read path from text file and store every instance as new variable?

I'm trying to read the contents of a text file and store any paths found on each line into their own variable. There's just 1 path on each line and also on each line there's other text (double quotes, a number and a tab).
Is this even possible? I've spent around 6 hours scouring Bing and Google trying to find out if i can do this and i haven't found anything.
Here's an example of the text file:
"LibraryFolders"
{
"1" "D:\\Steam Games"
"2" "E:\\Steam Games"
}
The number of library folders listed and path of the library folder will be different for every user's computer.
#ECHO OFF
SETLOCAL
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
FOR /f "tokens=1*" %%a IN (q27630202.txt) DO (
IF "%%~b" neq "" SET "$%%~a=%%~b"
)
SET $
GOTO :EOF
I used a file named q27630202.txt containing your data for my testing.
You know, that data file looks almost like JSON. Just for grins and giggles, I decided to load it into JScript, massage it into valid JSON, create a JScript object from it, then output the object values back into the batch script. It's not as efficient as Magoo's solution, but it was an entertaining exercise nevertheless.
#if (#a==#b) #end /* Harmless hybrid line that begins a JScript comment
#echo off
setlocal
set "JSON=json.txt"
for /f "delims=" %%I in ('cscript /nologo /e:JScript "%~f0" "%JSON%"') do (
rem :: If you want to do stuff with each path returned,
rem :: change "delims=" to "tokens=2 delims==" above.
rem :: Then for each iteration of the loop, %%I will
rem :: contain a path from the text file.
set "%%I"
)
:: display all variables beginning with LibraryFolders
set LibraryFolders
goto :EOF
:: end batch / begin JScript */
var fso = new ActiveXObject('scripting.filesystemobject'),
JSONfile = fso.OpenTextFile(WSH.Arguments(0), 1);
var JSON = JSONfile.ReadAll().split(/\r?\n/);
JSONfile.close();
// massage the data into valid JSON
for (var i=0; i<JSON.length; i++) {
if (!i) JSON[i] += ':';
else if (/^\s*(\"[^\"]+\"\s*){2}$/.test(JSON[i])) {
JSON[i] = JSON[i].replace(/\"\s+\"/, '": "') + ',';
}
}
JSON = JSON.join('').replace(/,\s*\}/, '}');
// create new object from now valid JSON text
eval('var obj = {' + JSON + '}');
// dump "var=val" out to be captured by batch for /f loop
for (var i in obj.LibraryFolders) {
WSH.Echo('LibraryFolders['+i+']=' + obj.LibraryFolders[i]);
}

Script to remove special characters from filenames

I have a folder containing a large number of files. A lot of the filenames have '%' and/or '&' characters in them.
e.g. Test&doc.pdf
e.g Test%doc.doc
Is there a quick way I could remove the '%' and '&' characters using a windows batch file, vbscript or something similar?
All help will be greatly appreciated.
Thanks.
Here's how you can do it in batch (in case you're curious). The big limitation is that if you have filenames with more than one percent sign, it won't work because the shell expands it to a variable. I don't know immediately how to fix that.
It starts from whatever directory the script is in, and works recursively over all subdirectories.
#echo off
setlocal enabledelayedexpansion
for /f "usebackq delims=" %%N in (`dir /s /b`) do (
set var=%%~nN
set var=!var:^&= !
set var=!var:%%= !
if not "!var!"=="%%~nN" (
if not exist "%%~dpN!var!%%~xN" (
echo "%%N" --^> "!var!%%~xN"
ren "%%N" "!var!%%~xN"
) else (
echo File "!var!%%~xN" ^(from %%N^) already exists.
)
)
)
E.g., prints output like this:
C:\batch\schar>schar
"C:\batch\schar\Test%doc.doc" --> "Test doc.doc"
"C:\batch\schar\Test%doc.pdf" --> "Test doc.pdf"
File "Test doc.pdf" (from C:\batch\schar\Test&doc.pdf) already exists.
"C:\batch\schar\subdir\FILE%here" --> "FILE here"
#indiv
If someone can produce a batch solution without character limitations, I'll be massively impressed.
Ok, I'll try.
#echo off
setlocal DisableDelayedExpansion
for /f "usebackq delims=" %%N in (`dir /s /b`) do (
set var=%%~nxN
setlocal EnableDelayedExpansion
set "org=!var!"
set "var=!var:&= !"
set "var=!var:%%= !"
if not "!var!"=="!org!" (
if not exist "%%~dpN!var!" (
echo "!org!" --^> "!var!"
ren "!org!" "!var!"
) else (
echo File "!var!" ^(from !org!^) already exists.
)
)
endlocal
)
The trick is, to toggle the delayed expansion, because expanding of for-loop-vars (%%N) should be done without delayed expansion, else you lose the exclamation marks, and got problems with carets.
But to handle and modify the strings you should use delayed expansion.
But why? The answer is to understand the phases of the batch parser.
I tried to explain it here.
how-does-the-windows-command-interpreter-cmd-exe-parse-scripts
I've quickly thrown that together and didn't test it, but this VBScript should do the trick. Tell me if you need fancy stuff like folder recursive replacing etc.
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Your folder here
objStartFolder = "X:\MYFOLDER"
Set objFolder = objFSO.GetFolder(objStartFolder)
Set regEx = New RegExp
'Your pattern here
regEx.Pattern = "[&%]"
Set colFiles = objFolder.Files
For Each objFile in colFiles
objFile.Rename(regEx.Replace(objFile.Name, "")
Next

Batch: line & remove

I want a batch file which: removes a certain line [line number by %lnum%] in a txt file.
That sounds like a job for sed. On windows, you'd have to install a windows port and then call sed from within your batch file.
sed '<linenumber>d' filename > newfilename
To delete the 4th line:
sed '4d' filename > newfilename
If you are in windows and you want to do it in a batch file, you could do the following by brute force:
#echo off
setlocal ENABLEDELAYEDEXPANSION
SET lineNum=
SET filename=%1
SET targetLine=%2
SET targetFile=%filename%.tmp
DEL %targetFile%
FOR /F " tokens=1 delims=" %%i in (%filename%) do (
SET /a lineNum += 1
if NOT !lineNum! == !targetLine! ECHO %%i >> !targetFile!
)
REN %filename% %filename%.orig
REN %targetFile% %filename%
You pass into the batch the name of your target file and the line number you want removed. It creates a temporary file, pipes the 'good' lines from your original into the temp and then finishes up by renaming the files so that you keep your original and have the modified file in place.
Pure cmd?:
delline.cmd number filename
#echo off
setlocal ENABLEDELAYEDEXPANSION
set line=%~1
set file=%~nx2
set dSource=%~dp2
set i=0
for /F "delims=" %%l in (%dSource%%file%) do (
set /a i+=1
if not !i! EQU %line% call :BuildFile "%%l"
)
del /f "%dSource%%file%" >nul
for %%l in (%_file%) do echo %%~l>>"%dSource%%file%"
endlocal& exit /b 0
:BuildFile
set _file=%_file% %1
exit /b 0
___Notes_____
1: No checks for parameters. First need be a number, the second a file or path+file.
2: As with other answers, no temporary file either.
3: Using setlocal would allow you to integrate this code easy within a script by naming it :delline and using it like: call :delline number file
WARNING: Any blank line from the source file would be skipped/lost in the reading process (by the for..loop). A file with, says 10 lines from which 4 are blanks, would be read as 6 lines to be processed. The line number given would be applied (thus, deleted) from the 6 data lines, and not the starting 10.
Edit
Went a bit too fast, did not see akf's answer which looks real close to mine.
don't have to use any external command. you can use vbscript
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objArgs = WScript.Arguments
num = objArgs(0)
strFile = objArgs(1)
Set objFile = objFS.OpenTextFile(strFile)
Do Until objFile.AtEndOfLine
linenum = objFile.Line
If linenum = Int(num) Then
objFile.SkipLine
End If
strLine = objFile.ReadLine
WScript.Echo strLine
Loop
how to use:
C:\test>cscript /nologo removeline.vbs 4 file.txt > newfile.txt

Resources