command line SET in nested IF/ELSE - command-line

I need to initialize multiple env vars only on certain conditions, I cannot use anything but command line.
For the example of my problem I am going to take a symple case of initializing an alphabet.
First cmd script is :
#echo OFF
set PATH=%PATH%;"%~dp0"
IF "%_ALPHABET%"=="" (
echo "DEFINE"
call setEnvA
call set "_ALPHABET=%_ALPHABET%;b"
) ELSE (
echo "ALREADY DEFINE"
set _ALPHABET=
set A_ADDED=
)
setEnvA cmd is :
IF "%A_ADDED%"=="" (
set A_ADDED=OK
set _ALPHABET=%_ALPHABET%;a
)
I was expecing
;a;b
as a result, but I get only
;b
I tried to throw random delayedexpansion but without any result. I am starting to think that this is not possible and I should do some dirty goto.

The contents of environment variable _ALPHABET is being substituted within the parenthesis before the call to setEnvA is performed. You need to do something like:
#echo OFF
set PATH=%PATH%;"%~dp0"
IF "%_ALPHABET%"=="" (
echo "DEFINE"
call setEnvA
call :set_ALPHABET
) ELSE (
echo "ALREADY DEFINE"
set _ALPHABET=
set A_ADDED=
)
exit /b
:set_ALPHABET
set "_ALPHABET=%_ALPHABET%;b"

Related

Batch to encrypt and decrypt passwords using vbscript and powershell with symmetric encryption

I want to integrate a vbscript that use a function with a symmetric encryption function into a batch file that ask user to enter its password using powershell to mask the input text :
#echo off
set "psCommand=powershell -Command "$pword = read-host 'Enter Password' -AsSecureString ; ^
$BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pword); ^
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)""
for /f "usebackq delims=" %%p in (`%psCommand%`) do set password=%%p
echo %password%
pause
Vbscript code :
Encrypted_String = Crypt("123456789")
wscript.echo Encrypted_String
Decrypted_String = Crypt(Encrypted_String)
wscript.echo Decrypted_String
'***************************************************************************
Function Crypt(text)
Dim i,a
For i = 1 to len(text)
a = i mod len(255)
if a = 0 then a = len(255)
Crypt = Crypt & chr(asc(mid(255,a,1)) XOR asc(mid(text,i,1)))
Next
End Function
'***************************************************************************
So, i'm trying to combine those codes into a batch file like that :
The combined Batch-File :
#echo off & Setlocal EnableDelayedExpansion
Title %~n0 - Encrypt_Decrypt passwords by Hackoo 2016
Mode 60,5 & Color 0E
:Main
Call :Clean
Call :InputPassword "Please choose your password" MyPass
Call :Crypt_Decrypt !MyPass! >%tmp%\MyCryptedPass.txt
(set /p CryptPass=)<%tmp%\MyCryptedPass.txt
echo The encrypted password is :!CryptPass!
pause
cls
Call :Crypt_Decrypt !CryptPass!>%tmp%\MyPlaintextPass.txt
(set /P MyPlaintextPass=)<%tmp%\MyPlaintextPass.txt
echo The password in plain text is : !MyPlaintextPass!
pause
Goto :Main
::********************************************************************************
:InputPassword
Cls
echo.
set "psCommand=powershell -Command "$pword = read-host '%1' -AsSecureString ; ^
$BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pword); ^
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)""
for /f "usebackq delims=" %%p in (`%psCommand%`) do set %2=%%p
Goto :eof
::********************************************************************************
:Crypt_Decrypt
Call :Clean
(
echo StringEnCrypted = Crypt("%~1"^)
echo wscript.echo StringEnCrypted
echo '****************************************************************************
echo Function Crypt(text^)
echo Dim i,a
echo For i = 1 to len(text^)
echo a = i mod len(255^)
echo if a = 0 then a = len(255^)
echo Crypt = Crypt ^& chr(asc(mid(255,a,1^)^) XOR asc(mid(text,i,1^)^)^)
echo Next
echo End Function
echo '****************************************************************************
)>%tmp%\Crypt_Decrypt.vbs
cscript /nologo %tmp%\Crypt_Decrypt.vbs
goto :eof
::********************************************************************************
:Clean
If Exist %tmp%\Crypt_Decrypt.vbs Del %tmp%\Crypt_Decrypt.vbs
goto :eof
::********************************************************************************
So, this last Batch script can encrypt and dercypt strings; but when i enter only numbers or something like this it didn't work ???
For example if enter :
123456789 as password ==> Not Ok
hackoo123 as password ==> Not Ok
Thank you for your help !
Your encryption can produce null (ascii decimal 0), carriage return (ascii decimal 13), and newline (ascii decimal 10) bytes, all of which will wreak havoc when you write the value to a file and then try to read it back in again. It is possible to work with carriage return and newline within environment variables, but null is an absolute no go.
Well, almost end of story. Batch can use FC in binary mode to read a binary file, byte by byte, outputting each byte in hex notation. (see HEXDUMP.BAT) But I don't think you want to go there.
If you want to deal with encrypted values within batch environment variables, then I suggest you come up with a new encryption scheme that avoids the troublesome bytes. At a minimum you must avoid null bytes.
Another option would be to abandon symmetric encryption, and let VBS convert the encrypted form into hex notation before you write it to disk.
Which leads me to another concern - Why are you writing a password to disk? That does not sound like a good idea.
Final note - Passing arbitrary strings on the command line is fraught with peril. You are better off passing the name of an environment variable that contains the value, and then let the called routine get the value from the variable. Certainly VBS can read an environment variable given the variable name.

List files in one folder structure which aren't in another

Just got a new phone and have temporarily copied the old ones files onto my PC C:\OldPhone\
On my PC are all my photos, in various folders below D:\Photos.
I want some code to list all the .jpg files below C:\OldPhone\ which are not anywhere below D:\Photos\
Does that make sense? Just to stress, the folder structures are not identical and I don't mind where the file is, just as long as it's there. Filename comparison would do for starters, option to add size would be a bonus!
CMD, VBS or powershell would be good, but anything visual studio can cope with would be ok too.
try this:
for /r "D:\Photos" %%a in (*.jpg) do set "$%%~na=1"
for %%a in (C:\OldPhone\*.jpg) do if not defined $%%~na echo %%~a not in d:\photos
cmd has associative arrays, like awk. This doesn't work with file names containing =.
This should do the trick in PowerShell"
$ht=#{} # initialize empty hashtable
dir C:\OldPhone\*.jpg -r -file | Foreach {$ht["$($_.Name):$($_.Length)"] = $_.FullName}
dir D:\Photos\*.jpg -r file | Foreach {$ht.Remove("$($_.Name):$($_.Length)")}
$ht # dump remaining hashtable contents
This also takes into account the size of the file in case you have multiple files with the same name. Ideally, to really ensure their are the same, you would include the MD5 file hash instead of the file length as part of the hashtable $ht key for each file. Note that the -file parameter is new in PowerShell V3. You probably don't need it unless you have some folders with .jpg as part of their name.
For /R %%i In (newfiles\*.jpg) Do Call :Check "%%~fi"
GoTo :EOF
:Check
For /R %%i In (existingfiles\*.jpg) Do If /I "%%~nxi"=="%~nx1" GoTo :Found
Echo File %1 doesn't already exist!
GoTo :EOF
:Found
Echo File %1 already exists!
GoTo :EOF
Here's what I ended up with, based on Endoro's answer. I really should put the folder locations into variables, but it works now, so that's all I need! I should also put the setlocal ... endlocal lines into a subroutine too.
Now I look at it, OLDFOLDER is a daft name too. This is poor coding!
It copies any missing .jpg or .mp4 files into a folder for ease of copying.
echo off
set OLDFOLDER=C:\OldPhone
cls
echo Checking for files in %OLDFOLDER% which aren't in D:\Pictures
del /f /q "D:\Documents\MissingFiles\*"
setlocal
for /r "D:\Photos" %%a in (*.jpg) do set "$%%~nxa=1"
for /r "%OLDFOLDER%" %%a in (*.jpg) do if not defined $%%~nxa copy "%%~a" "D:\Documents\MissingFiles\"
endlocal
setlocal
for /r "D:\Photos" %%a in (*.mp4) do set "$%%~nxa=1"
for /r "%OLDFOLDER%" %%a in (*.mp4) do if not defined $%%~nxa copy "%%~a" "D:\Documents\MissingFiles\"
endlocal
if exist "D:\Documents\MissingFiles\*.*p*" (
echo Files missing from D:\Photos copied to D:\Documents\MissingFiles\
) else (
echo There are no files in %OLDFOLDER% which aren't in D:\Photos
)
pause
Use fciv (and grep):
fciv .\old -r | grep jpg > old.txt
fciv .\new -r | grep jpg > new.txt
To get
old.txt
6d5f1279d4deccbaeef5d074b13ed2f4 .\old\b\100_1608.jpg
d95e29e2c0172dea438b12c418b09fd3 .\old\b\100_1610.jpg
19f9cda002c951f7a9f870ce74fb1224 .\old\b\100_1601.jpg
32b154f796303a8e9caff0c9d55ba713 .\old\b\100_1600.jpg
26ff43419c4f30764fb015f6d7c869c1 .\old\b\100_1609.jpg
d95e29e2c0172dea438b12c418b09fd3 .\old\a\100_1610.jpg
19f9cda002c951f7a9f870ce74fb1224 .\old\a\100_1601.jpg
32b154f796303a8e9caff0c9d55ba713 .\old\a\100_1600.jpg
new.txt
545b2121a3af2a8e5aa3c5946b450e87 .\new\c\100_1605.jpg
02a1638739302f3c17253beaa3fe9c1b .\new\c\100_1603.jpg
d95e29e2c0172dea438b12c418b09fd3 .\new\c\100_1610.jpg
19f9cda002c951f7a9f870ce74fb1224 .\new\c\100_1601.jpg
32b154f796303a8e9caff0c9d55ba713 .\new\a\100_1600.jpg
use a schema.ini file:
[old.txt]
Format=Delimited( )
ColNameHeader=False
Col1=MD5 CHAR
Col2=PATH CHAR
[new.txt]
Format=Delimited( )
ColNameHeader=False
Col1=MD5 CHAR
Col2=PATH CHAR
and VBScript:
Option Explicit
Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject")
Dim oDb : Set oDb = CreateObject("ADODB.Connection")
Dim sCS : sCS = Join(Array(_
"Provider=MSDASQL" _
, "Driver={Microsoft Text Driver (*.txt; *.csv)}" _
, "DBQ=" & goFS.GetAbsolutePathName("..\data") _
), ";")
Dim sSQL : sSQL = "SELECT O.* FROM [old.txt] O LEFT JOIN [new.txt] N ON O.MD5 = N.MD5 WHERE N.MD5 IS NULL"
oDb.Open sCS
Dim oRS : Set oRS = oDb.Execute(sSQL)
If Not oRS.EOF Then WScript.Echo oRS.GetString(2, , "|", vbCrLf, "NULL")
oDB.Close
output:
6d5f1279d4deccbaeef5d074b13ed2f4|.\old\b\100_1608.jpg
26ff43419c4f30764fb015f6d7c869c1|.\old\b\100_1609.jpg
ADDED:
By using
Dim sSQL : sSQL = "SELECT O.*, N.PATH FROM [old.txt] O INNER JOIN [new.txt] N ON O.MD5 = N.MD5"
you could get the duplicates:
d95e29e2c0172dea438b12c418b09fd3|.\old\a\100_1610.jpg|.\new\c\100_1610.jpg
d95e29e2c0172dea438b12c418b09fd3|.\old\b\100_1610.jpg|.\new\c\100_1610.jpg
19f9cda002c951f7a9f870ce74fb1224|.\old\a\100_1601.jpg|.\new\c\100_1601.jpg
19f9cda002c951f7a9f870ce74fb1224|.\old\b\100_1601.jpg|.\new\c\100_1601.jpg
32b154f796303a8e9caff0c9d55ba713|.\old\a\100_1600.jpg|.\new\a\100_1600.jpg
32b154f796303a8e9caff0c9d55ba713|.\old\b\100_1600.jpg|.\new\a\100_1600.jpg
(cf. same approach, similar problem)

Evaluating the First Character of a User Defined Variable is Uppercase

I have a template document that I want to convert to another file with a user defined name. The following is the code I have pieced together.
rem #echo off
setlocal enableDelayedExpansion
cls
:Check_Filename
set "_Filename="
set /p _Filename=Enter filename to be created:
if not defined _Filename echo You must enter a value. Try again.&goto Check_Filename
set "test=%_Filename:~0,1%"
for %%C in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do if defined test set "test=!test:%%C=!"
if defined test echo Invalid input. Try again.&goto Check_Filename
if not defined test echo %_Filename%
Set "errorlevel="
echo %_Filename% | findstr /i /R ".java" > nul
if %errorlevel% == 0 (
echo Java extention located
type f:\java\Template.txt > f:\java\%_Filename%
echo %errorlevel%
) else (
echo Java extention not located
echo %errorlevel%
type f:\java\Template.txt > f:\java\%_Filename%.java
)
)
It works but because the file is being used to create the backbone of Java script I want the FOR statement to evaluate the case of the first character which it does not presently do. I tried using HEX representation of these characters in the FOR statement as well, but without success.
Could someone please help me?
Thank you.
Try this:
#echo off & setlocal
:Check_Filename
set "_Filename="
set /p "_Filename=Enter filename to be created: "
if not defined _Filename echo You must enter a value. Try again.&goto:Check_Filename
echo(%_Filename:~0,1% | findstr /r "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]" || (echo Invalid input. Try again.&goto:Check_Filename)

Can option of delims in For / f be a string?

My code is as follows:
for /F "tokens=1,2 delims=%0.3%" %%i in ("double a = 0.3;") do (
set a=%%i
set b=%%j
)
I want a = "double a = " and b =";" but this code can not help.
Does anyone know how to solve this problem?
Your code as posted simply will not work at all.
for /F "tokens=1,2 delims=%0.3%" %%i in ("double a = 0.3;") do (
The %0 will be replaced by yourbatchfilename and since %" % has no value set in the environment, it will be replaced by [nothing] yielding
for /F "tokens=1,2 delims=yourbatchfilename.3i in ("double a = 0.3;") do (
which, unsurprisingly, is a syntax error.
#ECHO OFF
SETLOCAL
for /F "tokens=1,2 delims=3.0" %%i in ("double a = 0.3;") do (
set a=%%i
set b=%%j
)
ECHO first way :a=%a%+ b=%b%+
ENDLOCAL
SETLOCAL
SET "astring=double a = 0.3;"
SET "aseparator=0.3"
SET "arotorapes=3.0"
for /F "tokens=1,2 delims=%arotorapes%" %%i in ("double a = 0.3;") do (
SET a=%%i
)
CALL SET b=%%astring:*%aseparator%=%%
ECHO second way :a=%a%+ b=%b%+
ENDLOCAL
SETLOCAL
SET "astring=double a = 0.3;"
SET "aseparator=0.3"
CALL SET b=%%astring:*%aseparator%=%%
SET "c=%b%%aseparator%"
SET "a=%astring%"
:loop
IF DEFINED c SET c=%c:~0,-1%&SET a=%a:~0,-1%&GOTO loop
ECHO third way :a=%a%+ b=%b%+
In the first method, I've changed the sequence of the characters to deomstrate that any sequence of any of the characters between the = and " of a delims clause acts as a SINGLE delimiter. The code "works" by failing to fail.
In the second method, the setting of a works in the same way. Without further information, it's really not possible to tell whether this is adequate. b is set by specifically replacing all characters in the source string up to and including the separator with [nothing]
In the third method, the same operation establishes b, and then b and the separator are concatenated. Systematically lop off the characters at the end of a copy of the original original string and the concatenated string. When the concatenated version becomes empty, you've deleted the separator and the appendix from the original, leaving the portion of the original string up to the separator.

vbscript pass the current directory as named argument

I'm trying to pass the working directory to vbscript as a named argument. The system normally expands "." to the current path, but when I check the named argument I just get the string "."
Here's the command line:
cscript myscript.vbs /a:"first arg" /b:second /c:.
Here's the script:
dim args : set args = wscript.arguments.named
wscript.echo args.item("a")
wscript.echo args.item("b")
wscript.echo args.item("c")
Here's the output:
first arg
second
.
Set fso = CreateObject("Scripting.FileSystemObject")
WScript.Echo fso.GetAbsolutePathName(args("c"))
Or you could use /c:"%CD%" instead of /c:..
If you always want to know the current directory, you don't need to pass it as an argument, though. Simply use
cwd = CreateObject("WScript.Shell").CurrentDirectory