2

I am automating RSA soft token conversion and passing the conversion string over to Outlook. I realize I cannot make the string into a URL using a batch to outlook command line, however that is not my issue. My issue is converting the pesky equal sign over to it's URL encoded equivalent, "%3D".

@echo off
setlocal enableDelayedExpansion

set /p fname=Enter the Filename:
set /p pss=Enter the encryption pass:

IF NOT EXIST "%fname%".sdtid (
echo File Not Found!  Closing...
PING 1.1.1.1 -n 4 >NUL
exit
)

echo File Found! starting process...

REM tokenconverter %fname%.sdtid -iphone >> temp_batch.txt
tokenconverter %fname%.sdtid -p %pss% -iphone >> temp_batch.txt

set /p result= < temp_batch.txt
DEL temp_batch.txt
REM %result% | clip

set "stringclean1=!result:?=%%3F!"
set "stringclean2=!stringclean1::=%%3A!"
set "stringclean3=!stringclean2:/=%%2F!"

The following line fails to encode the equal sign:

 set "stringclean4=!stringclean3:==%%3D!"

I've tried:

 set "stringclean4=!stringclean3:=^=%%3D!"
 set "stringclean4=!stringclean3:=%=%%3D!"

However the equal sign remains unencoded.

echo Piping over to outlook..
REM passing stringclean3 since stringclean4 no worky.
pushd "C:\Program Files\Microsoft Office\Office12"
outlook.exe /c ipm.note /m "&subject=TEsT&body=%stringclean3%"

What is the proper way to URL encode the equal sign using delayed variable expansion?

Any assistance is appreciated. Thanks in advance.

Justin
  • 569
  • 2
  • 5
  • 8

3 Answers3

3

Sorry, a simple solution for replacing = in batch simply does not exist :-(

About the best you can do using pure batch is to loop through the string, character by character, and replace as needed.

Here is a brute force solution that has some room for more optimization. But it is good enough. It first checks to see if = exists before taking the time to encode =.

:: test if string contains =
:: only take the time to encode = if it exists
set "test=a!stringClean3!"
for /f "delims=" %%S in ("!test!") do if /i "!test:%%S=%%S!" neq "!test!" (

  :: compute length of string - 1
  set end=0
  for /l %%A in (12,-1,0) do (
    set /a "end|=1<<%%A"
    for %%B in (!end!) do if "!stringClean3:~%%B,1!"=="" set /a "end&=~1<<%%A"
  )

  :: replace = with %3D
  for /l %%N in (0 1 !end!) do (
    if "!stringClean3:~%%N,1!" equ "=" (
      set "stringClean4=!stringClean4!%%3D"
    ) else (
      set "stringClean4=!stringClean4!!stringClean3:~%%N,1!"
    )
  )

) else set stringClean4=!stringClean3!


EDIT

Here is another completely different approach that uses CERTUTIL to encode and decode the string as hex. It is a simple matter to encode the hex string. I don't think CERTUTIL is delivered with XP. I can't remember, but the CERTUTIL syntax may change slightly depending on the version of Windows. I developed and tested this on Vista.

set "tempFile=%temp%\replaceEqual%random%"

(>"%tempFile%.before" echo(!stringClean3!)
certutil -encodehex "%tempFile%.before" "%tempFile%.hex" >nul
>"%tempFile%.hex2" (
  for /f "usebackq tokens=1*" %%A in ("%tempFile%.hex") do (
    set ln=%%B
    set "ln=!ln:~0,48!"
    (echo !ln:3d=25 33 44!)
  )
)
certutil -decodehex "%tempFile%.hex2" "%tempFile%.after" >nul
<"%tempFile%.after" set /p "stringClean4="
del "%tempFile%.*"

The use of SET /P to read the result leads to the following limitations:

  • the string must be less than or equal to 1021 characters long.
  • the string must not end with a control character (trailing control chars are stripped)
  • the string must not contain line feeds

The result could be read using FOR /F, but then the delayed expansion will corrupt any ! when the FOR variable is expanded.

dbenham
  • 127,446
  • 28
  • 251
  • 390
  • +1 effective, but I bet this would be a good cause for a batch + JScript / VBScript hybrid solution. Regexp replacement might be more efficient than character-by-character check and replace. You know you want to. :) – rojo Mar 07 '13 at 03:02
  • @rojo - yep, I almost threw that solution in. But even better would be a JScript solution (perhaps hybrid JScript/Batch) that uses encodeURIComponent() to handle all aspects of the encoding. – dbenham Mar 07 '13 at 03:11
3

dbenham had a good idea about using JScript's encodeURIComponent method. Here it is, stuffed into the OP's example script:

@echo off
setlocal

set /p fname=Enter the Filename:
set /p pss=Enter the encryption pass:

IF NOT EXIST "%fname%".sdtid (
    echo File Not Found!  Closing...
    PING 1.1.1.1 -n 4 >NUL
    exit
)

echo File Found! starting process...

echo WScript.Stdout.WriteLine(encodeURIComponent(WScript.StdIn.ReadLine()));>uri.js
for /f "delims=" %%I in (
    'tokenconverter %fname%.sdtid -p %pss% -iphone ^| cscript /nologo uri.js'
) do set "result=%%I"
del uri.js
rojo
  • 24,000
  • 5
  • 55
  • 101
  • Nice, but you should disable delayed expansion, at least before `set "result=%%I"` else you lose exclamation marks and carets – jeb Mar 07 '13 at 13:36
  • Good idea. There's nothing in the script requiring `enabledelayedexpansion` anyway, so now it's gone. – rojo Mar 07 '13 at 13:42
0
SET result=qm?colon:slash/equal=qm?colon:slash/equal=end
set "stringclean0=!result!"
:loop3D
FOR /f "tokens=1,2*delims==" %%i IN ('SET stringclean0') DO (
  IF NOT "%%k"=="" set stringclean0=%%j%%3D%%k&GOTO loop3D
)
set "stringclean1=!stringclean0:?=%%3F!"
set "stringclean2=!stringclean1::=%%3A!"
set "stringclean3=!stringclean2:/=%%2F!"

SET stri
Magoo
  • 77,302
  • 8
  • 62
  • 84
  • This algorithm fails if there are consecutive `=`, and the problem cannot be fixed. It also fails if `stringclean0X` exists, but that problem can be solved. – dbenham Mar 07 '13 at 05:48