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.

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

+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 - 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.
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

2 Comments

Nice, but you should disable delayed expansion, at least before set "result=%%I" else you lose exclamation marks and carets
Good idea. There's nothing in the script requiring enabledelayedexpansion anyway, so now it's gone.
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

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.