1

I made this batch script to separate emails and passwords in two separate files and save them from a ComboBox.txt list example this one :

Delimiters can be ":,;"

My problem is that the exclamation point "!" in a password is ignored by SetLocal EnableDelayedExpansion

So I can get all the speciaux characters except that one "!"

ComboBox.txt

hackoo@hackoo.com,&azerty123><*
someone@gmail.com;He>llo123*!
andrew@yahoo.com:mommy!845
Cooker124@gmail.com:my!love1547
blue@hotmail:something!b010
hello@gmail.com:something!6655

Extract_Email_Password.bat

@echo off
>nul chcp 65001
Title Extraire les emails et les passwords dans deux fichiers séparés de type ComboBox ".txt" by Hackoo 2019
Mode 85,3 & color 0A
Set "InputFile=%1"
Set "OutPutFile_Emails=%~dp0Emails_Extracted.txt"
Set "OutPutFile_Passwords=%~dp0Passwords_Extracted.txt"
If Exist "%OutPutFile_Emails%" Del "%OutPutFile_Emails%"
If Exist "%OutPutFile_Passwords%" Del "%OutPutFile_Passwords%"
If [%InputFile%] EQU [] goto :Aide
echo(
echo     Patientez un peu... extraction des emails et les mots passes sont en cours ...
SetLocal EnableDelayedExpansion
@for /f "delims=:;, tokens=1,2" %%a in ('Type "%InputFile%"') do (
    Set "Email=%%a"
    Set "Password=%%b"
    If defined Email echo !Email!>>"%OutPutFile_Emails%"
    If defined Password echo !Password!>>"%OutPutFile_Passwords%"
)
EndLocal
If Exist "%OutPutFile_Emails%" Start "" "%OutPutFile_Emails%"
If Exist "%OutPutFile_Passwords%" Start "" "%OutPutFile_Passwords%"
Exit 
::********************************************************************************
:Aide
Mode 90,5 & Color 0C
echo(
echo          Glisser et déposer le fichier texte sur,ce script "%~nx0" 
echo          Pour extraire les emails et les passwords dans deux fichiers séparés !
Timeout /T 10 /NoBreak>nul
Exit
::********************************************************************************
Hackoo
  • 15,943
  • 3
  • 28
  • 59
  • Simplest idea would be to perform substring expansion and replacement, escaping any `!` with a `^`. – Compo Oct 06 '19 at 05:59
  • 2
    While accessing the `FOR` variables, if there is a chance that the variables may contain `!` then the delayed expansion must be turned of during the access. You have to move both `SetLocal EnableDelayedExpansion` and `endlocal` to the `FOR`'s body and enable delayed expansion just after reading the `FOR` variables. – sst Oct 06 '19 at 06:20
  • 1
    Or, since you don't need the variables out side of the `FOR` loop, and also you are not modifying the contents, You could keep the delayed expansion off and directly save the `FOR` variables to the files. – sst Oct 06 '19 at 06:36

2 Answers2

2

I'm not sure why you're even setting variables named Email and Password, when you could just use the metavariables directly:

Echo(
Echo     Patientez un peu... extraction des emails et les mots passes sont en cours ...
If Not Exist "%InputFile%" Exit /B
For /F "UseBackQ Tokens=1-2 Delims=:;," %%A In ("%InputFile%") Do If Not "%%B"=="" (
    >>"%OutPutFile_Emails%" Echo(%%A

Do not enable delayed exansion in your script, this code replaces your lines 10-20.

Compo
  • 30,301
  • 4
  • 20
  • 32
  • What's the point of using `set /P` to echo without new-line, followed by `echo(` to echo a new-line? – aschipfl Oct 06 '19 at 12:07
  • @aschipfl: avoiding variable expansion. – Stephan Oct 06 '19 at 12:14
  • My assumption, @aschipfl, is that `>>"%OutPutFile_Emails%" echo %%a`, and `>>"%OutPutFile_Passwords%" echo %%b` would fail trying to echo some of the characters in the passwords. If I didn't add the trailing `echo(` they'd all be `echo`ed to the same line, which I assume wasn't the intention. – Compo Oct 06 '19 at 12:22
  • 1
    `echo(%%a` is just as safe as `echo(!VAR!` since both `for` meta-variable and delayed variables are expanded after recognition of special characters; or did I misunderstand you both, @Stephan and @Compo? – aschipfl Oct 06 '19 at 15:39
  • Thanks for the correction @aschipfl, I have modified my answer to incorporate your knowledge. – Compo Oct 07 '19 at 11:27
2

The problem in your code is that you have got delayed expansion enabled during expansion of for meta-variables, because delayed expansion happens as last, as described here: How does the Windows Command Interpreter (CMD.EXE) parse scripts, hence any exclamation marks that are expanded during earlier phases become then consumed by delayed expansion. To avoid that, enable delayed expansion only when needed and disable it else (so during expansion of for meta-variables and also of %-expansion):

for /F "delims=:;, tokens=1,*" %%a in ('type "%InputFile%"') do (
    set "Email=%%a"
    set "Password=%%b"
    setlocal EnableDelayedExpansion
    >> "!OutPutFile_Emails!" if defined Email echo(!Email!
    >> "!OutPutFile_Passwords!" if defined Password echo(!Password!
    endlocal
)

Since there is actually no need to assign any environment variables you could avoid delayed expansion at all:

for /F "delims=:;, tokens=1,*" %%a in ('type "%InputFile%"') do (
    >> "!OutPutFile_Emails!" if not "%%a"=="" echo(%%a
    >> "!OutPutFile_Passwords!" if not "%%b"=="" echo(%%b
)

But there is still another problem: a password may even begin with one of the separators ,, ;, :, so you cannot use for /F "delims=,;:", because it treats multiple adjacent delimiters as a single one.

The following code safely handles passwords with arbitrary characters (see all the explanatory rem-remarks):

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_INFILE=%~dp0ComboBox.txt"
set "_OUTFILE1=%~dp0Email_Extracted.txt"
set "_OUTFILE2=%~dp0Passwords_Extracted.txt"

rem // Write to output files:
9> "%_OUTFILE1%" 8> "%_OUTFILE2%" (
    rem // Loop over lines of text file (ignoring empty lines):
    for /F usebackq^ delims^=^ eol^= %%L in ("%_INFILE%") do (
        rem // Store current line in a variable:
        set "LINE=%%L"
        rem // Split off everything beginning at first separator:
        for /F "delims=,;:" %%K in ("%%L") do (
            rem // Store current address in a variable:
            set "ADDR=%%K"
            rem // Loop over separator characters:
            setlocal EnableDelayedExpansion
            for %%S in ("," ";" ":") do (
                rem /* Rebuild current line based on currently iterated separator and
                rem    compare it with the original line; that way a password may even
                rem    begin with a separator; the condition is only fulfilled once: */
                if "!ADDR!%%~S!LINE:*%%~S=!"=="!LINE!" (
                    >&9 echo(!ADDR!
                    >&8 echo(!LINE:*%%~S=!
                )
            )
            endlocal
        )
    )
)

endlocal
exit /B

So with this code the following passwords are handled correctly:

me@dummy.nil,;&"&":
me@dummy.nil;,comma^.
me@dummy.nil::excl^mark!?
me@dummy.nil:bla,bla"%
aschipfl
  • 28,946
  • 10
  • 45
  • 77