So I am trying to make a running batch file to create a new batch file which contains:
#setlocal enableextensions enabledelayedexpansion
#echo off
:remloop
set recfilepath=%pof%
set filename=%pof%
SET filename=%_filename:*\=%
if not x%pof:bcd=%==x%pof% goto remloop
endlocal
(Variable POF has already been declared in another file)
So I tried using echo command to make another batch file
echo #setlocal enableextensions enabledelayedexpansion > file2.bat
echo #echo off > file2.bat
echo :remloop >> file2.bat
echo set recfilepath=%pof% >> file2.bat
echo set filename=%pof% >> file2.bat
echo SET filename=%_filename:*\=% >> file2.bat
echo if not x%pof:bcd=%==x%pof% goto remloop >> file2.bat
echo endlocal >> file2.bat
but the result was unexpected, the results are:
#echo off
:remloop
set recfilepath=C:\Users\Palm2570Playz\Desktop\djfbjfbfbj.txt
set filename=C:\Users\Palm2570Playz\Desktop\djfbjfbfbj.txt
SET filename=*\=
if not xC:\Users\Palm2570Playz\Desktop\djfbjfbfbj.txt==xC:\Users\Palm2570Playz\Desktop\djfbjfbfbj.txt goto remloop
endlocal
The "SET filename=*= " lines was unexpected so the code cannot run correctly
Is there any command to fix this?
To show you what your question asks, without providing any fixes for any of the content of `file2.bat`:
#( Echo #setlocal enableextensions enabledelayedexpansion
Echo #echo off
Echo :remloop
Echo set recfilepath=%%pof%%
Echo set filename=%%pof%%
Echo SET filename=%%_filename:*\=%%
Echo if not x%%pof:bcd=%%==x%%pof%% goto remloop
Echo endlocal)>"file2.bat"
If you don't need escaping anything?!
The best and most efficient way to escape is to use no escape, use only the bat file itself to decode the second bat file with the content in Base64 itself:
Where it is possible to use CertUtil to decode File2.bat, taking advantage that it already comes with Windows.
Your code bat:
#(%__APPDIR__%CertUtil.exe -f -decode "%~f0" "%~dp0File2.bat" >nul & goto :EOF)
<-----BEGIN -----QGVjaG8gb2ZmICYmIHNldGxvY2FsIGVuYWJsZWRlbGF5ZWRleHBhbnNpb24NCj
psb29wDQpzZXQgInJlY2ZpbGVwYXRoPSVwb2YlIiAmJiBjbWQuZXhlIC92Om9uIC9jICJzZXQgImZpb
GVuYW1lPSFyZWNmaWxlcGF0aDoqXD0hIiAiDQplY2hvOyJ4IXBvZjpiY2Q9ISJ8ZmluZC9pIC92ICJ4
IXBvZiEiID5udWwgJiYgZ290byA6bG9vcCB8fCBlbmRsb2NhbCAmIGdvdG86RU9G-----END ----->
The File2.bat content result:
#echo off && setlocal enabledelayedexpansion
:loop
set "recfilepath=%pof%" && cmd.exe /v:on /c "set "filename=!recfilepath:*\=!" "
echo;"x!pof:bcd=!"|find/i /v "x!pof!" >nul && goto :loop || endlocal & goto:EOF
This code above has some suggestions, liable to (critical/not), so follow code use the same method using your current code without modifications:
#(%__APPDIR__%CertUtil.exe -f -decode "%~f0" "%~dp0File2.bat" >nul & goto :EOF)
<-----BEGIN CERTIFICATE----- QHNldGxvY2FsIGVuYWJsZWV4dGVuc2lvbnMgZW5hYmxlZGVsYX
llZGV4cGFuc2lvbg0KQGVjaG8gb2ZmDQo6cmVtbG9vcA0Kc2V0IHJlY2ZpbGVwYXRoPSVwb2YlDQpzZ
XQgZmlsZW5hbWU9JXBvZiUNClNFVCBmaWxlbmFtZT0lX2ZpbGVuYW1lOipcPSUNCmlmIG5vdCB4JXBv
ZjpiY2Q9JT09eCVwb2YlIGdvdG8gcmVtbG9vcA0KZW5kbG9jYWw= -----END CERTIFICATE----->
The File2.bat content result:
#setlocal enableextensions enabledelayedexpansion
#echo off
:remloop
set recfilepath=%pof%
set filename=%pof%
SET filename=%_filename:*\=%
if not x%pof:bcd=%==x%pof% goto remloop
endlocal
Some further reading:
[√] CertUtil -Decode
[√] CertUtil -Encode / -Decode
[√] CertUtil (Microsoft Documentation)
You can use FINDSTR / a FOR loop (eol&skip) / MORE on the batch file itself, and redirect it to file2.bat. That way no parsing is involved.
I made no edits/improvements as it's out of scope of the question.
#echo off
%__APPDIR__%findstr.exe /R "^;" "%~f0" >file2.bat
exit /b
<--- FILE2.BAT --->
;#setlocal enableextensions enabledelayedexpansion
;#echo off
;:remloop
;set recfilepath=%pof%
;set filename=%pof%
;SET filename=%_filename:*\=%
;if not x%pof:bcd=%==x%pof% goto remloop
;endlocal
Related
#echo off
#chcp 65001
setlocal enableextensions enabledelayedexpansion
set test=qwert
goto start
:IsStrInStrFunc
setlocal
call set check=%%1:%2=%
echo %check%
endlocal
exit /b
:start
call :IsStrInStrFunc %test%, q
pause
The "check" variable must contain "wert". What's wrong?.......
if you want to set %check% to be "wert"
set check=%%1:%2=%
should be
set check=%test:~1%
For more info check command help set in Command Prompt
Perhaps this example will assist you:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Delims==" %%G In ('"(Set _cp) 2> NUL"') Do Set "%%G="
For /F Tokens^=* %%G In ('"%SystemRoot%\System32\chcp.com"'
) Do For %%H In (%%G) Do Set "_cp=%%~nH"
If Not %_cp% Equ 65001 (Set "_cpc=TRUE"
"%SystemRoot%\System32\chcp.com" 65001 >NUL)
Set "test=qwert"
GoTo Start
:IsStrInStrFunc
Set "check=%~1"
Echo Before: %check%
SetLocal EnabledelayedExpansion
Set "check=!check:%~2=!"
EndLocal & Echo After: %check%
Exit /B
:Start
Call :IsStrInStrFunc "%test%" "q"
Pause
If Defined _cpc "%SystemRoot%\System32\chcp.com" %_cp% >NUL
GoTo :EOF
To do substring substitution on a variable, you need the variablename, not its value (see set /?), so your parameter in the call can't be %test% (which would pass the string quert), but must be test.
And as you are using delayed expansion anyway, why not using it?
#echo off
#chcp 65001
setlocal enableextensions enabledelayedexpansion
set "test=qwert"
goto start
:IsStrInStrFunc
setlocal
REM call set "check=%%%~1:%~2=%%"
set "check=!%~1:%~2=!"
echo %check%
endlocal
exit /b
:start
call :IsStrInStrFunc test q
PS: you don't need the ~ chars with your simple example, but they don't disturb either. Imagine you want to replace a string, you can simply do that with call :IsStrInStrFunc test "a string" (that's where the ~ are necessary. Good practice to include them anyway (just in case))
Years ago I saw some batch scripts that contain nothing relevant at a fist look, but with a lot of content. The content was base64 encoded, and when you run the scripts, they are just running the commands that are encoded there.
Something like
SET mypath=%~dp0
echo "%mypath%
will look similar with
some_base_64_decoding_function(
U0VUIG15cGF0aD0lfmRwMA0KIGVjaG8gIiVteXBhdGgl
)
I don't really remember how those file were, and I can't find anything relevant on the Internet, except this article: Convert PowerShell script into non-readable format
but this only refeer to PowerShell scripts, and I need it for .bat scripts.
Anyone to give me a hint?
This is a sample batch file for encoding files in Base 64 with Certutil utility.
How to use it?
Just save this code on your notepad or on notepad++ or on any text editor as :
Certutil_B64_Encoding_Files.bat and drag and drop any file over it to be encoded
#echo off
Title Encoding files with CERTUTIL utility by Hackoo 2017
color 0A & Mode 83,3
If "%~1"=="" (
color 0C & Mode 80,3
echo(
echo You must drag and drop a file over this batch script to be encoded !
Timeout /T 5 /nobreak>nul & exit /b
)
#for /f %%i in ("certutil.exe") do if not exist "%%~$path:i" (
echo CertUtil.exe not found.
pause
exit /b
)
set "TempFile=%Temp%\Temp_b64
set "OutputFile=%~nx1_encoded%~x0"
If exist "%OutputFile%" Del "%OutputFile%" >nul 2>&1
echo(
echo Please wait a while ... Encoding "%~nx1" is in progress ...
certutil.exe -f -encode "%~1" "%TempFile%" >nul 2>&1
(
echo #echo off
echo CERTUTIL -f -decode "%%~f0" "%%Temp%%\%~nx1" ^>nul 2^>^&1
echo Start "%~n1" "%%Temp%%\%~nx1"
echo Exit
)>> "%OutputFile%"
copy "%OutputFile%" /b + "%TempFile%" /b >nul 2>&1
If exist "%TempFile%" Del "%TempFile%" >nul 2>&1
Timeout /T 2 /NoBreak>nul & exit
Encoded HTA Example: CommandLine.hta_encoded.bat
This is a result of an encoded output of a HTA file of mine named as CommandLine.hta_encoded.bat
So, you should copy and paste this code as CommandLine.hta_encoded.bat and execute it by double click. And you will get something like this :
Encoded VBS Example : DJBuzzRadio.vbs_encoded.bat
#echo off
CERTUTIL -f -decode "%~f0" "%Temp%\DJBuzzRadio.vbs" >nul 2>&1
Start "DJBuzzRadio" "%Temp%\DJBuzzRadio.vbs"
Exit
-----BEGIN CERTIFICATE-----
UGxheSAiaHR0cDovL3d3dy5jaG9jcmFkaW9zLmNoL2RqYnV6enJhZGlvX3dpbmRv
d3MubXAzLmFzeCINClN1YiBQbGF5KFVSTCkNCiAgIERpbSBTb3VuZA0KICAgU2V0
IFNvdW5kID0gQ3JlYXRlT2JqZWN0KCJXTVBsYXllci5PQ1giKQ0KICAgU291bmQu
VVJMID0gVVJMDQogICBTb3VuZC5zZXR0aW5ncy52b2x1bWUgPSAxMDANCiAgIFNv
dW5kLkNvbnRyb2xzLnBsYXkNCiAgIGRvIHdoaWxlIFNvdW5kLmN1cnJlbnRtZWRp
YS5kdXJhdGlvbiA9IDANCiAgICAgICB3c2NyaXB0LnNsZWVwIDEwMA0KICAgbG9v
cA0KICAgd3NjcmlwdC5zbGVlcCAoaW50KFNvdW5kLmN1cnJlbnRtZWRpYS5kdXJh
dGlvbikrMSkqMTAwMA0KRW5kIFN1Yg0K
-----END CERTIFICATE-----
MACRO-b64decode.bat
#echo off
SETLOCAL DISABLEDELAYEDEXPANSION
::DEFINITIONS
( set LF=^
%= EMPTY =%
)
set ^"NL=^^^%LF%%LF%^%LF%%LF%^^"
set $MACRO.ForEntireLine=^^^^^^^"eol^^^^=^^^^^^^%LF%%LF%^%LF%%LF%^^^%LF%%LF%^%LF%%LF%^^^^ delims^^^^=^^^^^^^"
::MACRO
ENDLOCAL &^
set $MACRO.b64exec=FOR %%? in (args main) do if "%%?" == "main" (%NL%
FOR %%a in (!args!) do (%NL%
^>encoded.txt echo %%a%NL%
^>nul certutil -decodehex encoded.txt decoded.txt 1%NL%
FOR /F %$MACRO.ForEntireLine% %%x in (decoded.txt) do %%x%NL%
del /F /Q encoded.txt decoded.txt%NL%
)%NL%
) ELSE SETLOCAL ENABLEDELAYEDEXPANSION ^& set args=
To call the macro inside your batch file:
call MACRO-b64decode.bat
%$MACRO.b64exec% ZWNobyBoZWxsbywgd29ybGReIQ==
which will output:
hello, world!
Note: DELAYEDEXPANSION is enabled
I have a piece of code:
for /F "tokens=*" %%A in (myfile.txt) do (
echo echo %%A ^>^>myfile.txt>>myfile.bat
)
As some of you can see, this code reads myfile.txt, and creates myfile.bat, which when opened creates an exact copy of the original myfile.txt. The problem comes in when myfile.txt contains special characters, such as >. How can I escape the %%A variable?
any help is appreciated.
I have this idea : using Certutil command to encode your text file and generate it again like this batch script can do :
#echo off
set "MyTxtFile=myfile.txt"
for %%i in (%MyTxtFile%) do (
set "MyBatchFile=%%~ni.bat"
set "TempFile=%%~ni.B64"
Set "NewFile=%%~ni__%%~xi"
)
#for /f %%i in ("certutil.exe") do if not exist "%%~$path:i" (
echo CertUtil.exe not found.
pause
exit /b
)
Rem to encode your text file to a temporary file
Certutil -encode "%MyTxtFile%" "%TempFile%" >nul 2>&1
(
echo #echo off
echo Title Generate code of "%MyTxtFile%" to "%NewFile%"
echo CERTUTIL -f -decode "%%~f0" "%NewFile%" ^>nul 2^>^&1
echo Exit
)> "%MyBatchFile%"
#Copy "%MyBatchFile%" /b + "%TempFile%" /b >nul 2>&1
Del "%TempFile%" >nul 2>&1
Timeout /T 2 /NoBreak>nul & exit
EDIT
This code can generate what you want based on your last comment test >> Hello :
#echo off
Title Generate code of "myfile.txt" to "myfile__.txt"
CERTUTIL -f -decode "%~f0" "myfile__.txt" >nul 2>&1
Exit
-----BEGIN CERTIFICATE-----
dGVzdCA+PiBIZWxsbw0KDQo=
-----END CERTIFICATE-----
The following commented code snippet could help (see Variable Edit/Replace):
#ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion
rem silently create empty output files - just for testing
>NUL COPY /Y NUL myfile46134196.bat
>NUL COPY /Y NUL myfile46134196ou.txt
for /F "tokens=*" %%A in (myfile46134196in.txt) do (
set "_aux=%%A"
rem replace every `Greater Than` symbol with a properly escaped one
echo echo !_aux:^>=^^^>! ^>^>myfile46134196ou.txt>>myfile46134196.bat
rem ^> properly escape `Greater Than` symbol - input string
rem ^> -output string
rem ^^ add a caret (Circumflex Accent) to output string
)
rem debugging outputs
echo ON
type myfile46134196.bat
#ECHO OFF
rem test: run currently created .bat file
call myfile46134196.bat
rem test: and show result
echo ON
type myfile46134196in.txt
type myfile46134196ou.txt
#ECHO OFF
Output:
==> .\so\46134196.bat
==> type myfile46134196.bat
echo test^>^>hello >>myfile46134196ou.txt
==> type myfile46134196in.txt
test>>hello
==> type myfile46134196ou.txt
test>>hello
==>
Further resources (required reading, incomplete):
(command reference) An A-Z Index of the Windows CMD command line
(helpful particularities) Windows CMD Shell Command Line Syntax
(%A etc. special page) Command Line arguments (Parameters)
(special page) EnableDelayedExpansion
(> etc. special page) Redirection
(^ caret) Escape Characters, Delimiters and Quotes
This is my batch script:
#echo off
title
setlocal enabledelayedexpansion
:a
set /p a=
!d!
for %%G in (%a%) do (set /a b+=1
if !b! neq 1 (set c=!c!-%%G) else (set c=%%G))
echo wscript.createobject("sapi.spvoice").speak "!c!">a.vbs
start a.vbs
exit
For every time that this program runs, it overwrites the a.vbs file with the new code as variable c. Is it possible to have "wscript.createobject("sapi.spvoice").speak "!c!"" preexisting in a VBScript and simply have batch assign the variable and execute it instead of overwriting and then executing?
With the help of aphoria, I tweaked my scripts to this:
VBScript:
wscript.createobject("sapi.spvoice").speak wscript.arguments(0)
Batch Script:
#echo off
title
setlocal enabledelayedexpansion
set /p a=
for %%G in (!a!) do (set /a b+=1
if !b! neq 1 (set c=!c!-%%G) else (set c=%%G))
cscript //nologo b.vbs !c!
exit
May I suggest you another solution?
JScript language is similar to VBScript, but have an advantage in this case: the JScript code can be placed inside the Batch file itself via a very simple trick. This way, it is not necessary to create a separated file with the JScript code:
#if (#CodeSection == #Batch) #then
:: Previous line is:
:: - in Batch: a valid IF command that does nothing
:: - in JScript: a conditional compilation IF statement that is false
:: so the following code is omitted until the next atSign-end
#echo off
title
setlocal enabledelayedexpansion
set /p a=
for %%G in (!a!) do (set /a b+=1
if !b! neq 1 (set c=!c!-%%G) else (set c=%%G))
rem Execute this Batch file as a JScript one:
cscript //nologo //E:JScript "%~F0" !c!
exit
#end
WScript.CreateObject("sapi.spvoice").Speak(WScript.Arguments(0));
In this case the original VBScript code is so simple that the JScript translation is immediate; just note that the uppercase letters are needed in JScript. However, I am not entirely sure that spvoice execute the same in JScript than in VBScript; you must do a test...
Create a script file SpeakNumber.vbs (call it whatever you want).
Put this inside it:
Set args = Wscript.Arguments
WScript.CreateObject("sapi.spvoice").Speak args(0)
Then, change your batch file like this:
#echo off
title
setlocal enabledelayedexpansion
:a
set /p a=
!d!
for %%G in (%a%) do (set /a b+=1
if !b! neq 1 (set c=!c!-%%G) else (set c=%%G))
START SpeakNumber.vbs !c!
exit
This is my batch script:
#echo off title setlocal enabledelayedexpansion :a set /p a= !d!
for %%G in (%a%)
do (set /a b+=1
if !b! neq 1
(set c=!c!-%%G)
else
(set c=%%G))
echo wscript.createobject("sapi.spvoice").speak "!c!">a.vbs
start a.vbs
exit
You dont have use a hybrid as you can embed the vbs file inside the batch file.
#echo off
set /p "Voice= Enter what you would like to say : "
echo dim speechobject >> sapi.vbs
echo set speechobject=createobject("sapi.spvoice") >> sapi.vbs
echo speechobject.speak "%Voice%" >> sapi.vbs
start sapi.vbs
timeout /t 1 /nobreak
del sapi.vbs
This script tries to:
get an input from a txt file, which is a list of computer names,
check if a log file on a computer from the list is bigger than 1000 bytes,
create a txt report with the names of those computers where the log file is more than 1000 bytes,
create another txt report with the names of the computers where the file is less than 1000 bytes.
However, something goes wrong. Any help could be nice.
#echo off
for /f "tokens=*" %%I in (computernames.txt)do call :checksz %%I
goto :eof
:checksz
setlocal
set file="\\%1\c$\data\info.log"
set min=1000
FOR /F "usebackq" %%A IN ('%file%') DO set size=%%~zA
if %size% GTQ %min% (
echo. %1 >>logsizemin.txt
) ELSE (
echo. %1>>logsizemax.txt
)
Hello everyone,
thanks for your valuable support. I congratulate whith those who conceived and built this site is really well done and useful.
I made some modifications to the script that you have kindly suggested to incorporate other features, but something is not working as I would like .. as you can view I use editv32 in order to hide password in my batch, the principle is the same but as you can see after checking the size of the log, "maxlongsize.txt" is used in order to take the names of the PCs on which do the next activity. I wish that the activities were performed sequentially on all PCs in the file "logsizemax.txt" with only one authentication at the beginning. I noticed that, for some reason sometimes the file "logsizemin.txt" is not created but i don't understand why. The maximum would be to put in another file such as "computer unreachable" those PCs that are not reached on the network but I have absolutely no idea how implement it. I hope I have sufficiently explained. Sorry for bad English! I think you understand my intention :). Following the batch
#setlocal
#echo off
editv32 -p "Enter username:" USR
editv32 -m -p "Enter password:" PWD
for /f "tokens=1" %%I in (computernames.txt) do call :checksz %%I
endlocal
goto :eof
:checksz
setlocal
set file="\\%1\c$\data\data.log"
set min=1000
type NUL>logsizemax.txt
type NUL>logsizemin.txt
if not exist %file% goto :eof
FOR /F "usebackq delims=" %%A IN ('%file%') DO set size=%%~zA
if %size% GEQ %min% ( echo %1>>logsizemax.txt ) ELSE ( echo %1>>logsizemin.txt )
endlocal
#setlocal
for /f "tokens=1" %%I in (logsizemax.txt) do call :sw %%I
endlocal
goto :eof
:sw
echo.
echo *****************************************
echo * VBS & Deploy script *
echo *****************************************
echo.
echo Run VBS and deploy script .....
psexec \\%1 -u %USR% -p %PWD% cscript "\\rep\Reg.vbs"
psexec \\%1 -u %USR% -p %PWD% cmd /c "\\rep\deploy.cmd"
echo.
echo **************************
echo * EXE Run *
echo **************************
echo.
echo Running exe .....
psexec -u %USR% -p %PWD% \\%1 "c:\Program Files\test.exe"
echo.
echo ***********************************
echo * Exe application launched *
echo ***********************************
echo.
goto END
:END
exit
You can avoid using environment variables and using the second FOR alltogether. Try this simpler version of your bat, with a more generic :checksz routine.
#echo off
for /f "tokens=*" %%a in (computernames.txt) do (
call :checksz "\\%%a\c$\data\info.log" 1000 "%%a"
)
goto :eof
:checksz
if %~z1 GTR %2 (
echo %~3 >> logsizemin.txt
) ELSE (
echo %~3 >> logsizemax.txt
)
goto :eof
see HELP CALL for more information.
Changes: GTG->GEQ, don't surround variable with quotes twice, remove leading space from echo, and a little clean up.
#setlocal
#echo off
for /f "tokens=1" %%I in (computernames.txt) do call :checksz %%I
endlocal
goto :eof
:checksz
setlocal
set file=\\%1\c$\data\info.log
set min=1000
if not exist %file% endlocal && goto :eof
FOR /F "usebackq delims=" %%A IN ('%file%') DO set size=%%~zA
if %size% GEQ %min% ( echo %1>>logsizemin.txt ) ELSE ( echo %1>>logsizemax.txt )
endlocal
goto :eof
edit: updated per comments from PA and Andriy M - endlocal if the file doesn't exist, and remove \ update note.