Search code examples
windowsbatch-filecalltrim

"call" or <str> in batch script unfortunately removes certain characters from a variable


I don't understand why the following batch :

REM echo off
setlocal
set u64=aDI0NDcxOQ==
set p64=SGZzemxwNzc3
call :atob usr "%u64%"
call :atob pwd "%p64%"
schtasks /Run /S aaa.bbb.ccc.ddd /U %usr% /P %pwd% /TN "My Scheduler Task Name"
goto :EOF

:atob <var_to_set> <str>
for /f "delims=" %%I in (
   'powershell "[Text.Encoding]::UTF8.GetString([convert]::FromBase64String(\"%~2\"))"'
) do set %~1=%%I
goto :EOF

removes the last 2 '=' characters of u64 as you can see with the following result :

C:\Users\lambda>REM echo off
C:\Users\lambda>setlocal
C:\Users\lambda>set u64=aDI0NDcxOQ==
C:\Users\lambda>set p64=SGZzemxwNzc3
C:\Users\lambda>call :atob usr "aDI0NDcxOQ=="
C:\Users\lambda>for /F "delims=" %I in ('powershell "[Text.Encoding]::UTF8.GetString([convert]::FromBase64String(\"aDI0NDcxOQ \"))"') do set usr=%I
C:\Users\lambda>set usr=Exception calling "FromBase64String" with "1" argument(s): "Longueur non
C:\Users\lambda>set usr=valide pour un tableau de caractères Base 64 ou une chaîne."
C:\Users\lambda>set usr=At line:1 char:1
C:\Users\lambda>set usr=+ [Text.Encoding]::UTF8.GetString([convert]::FromBase64String("aDI0NDcxOQ "))
C:\Users\lambda>set usr=+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\lambda>set usr=    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
C:\Users\lambda>set usr=    + FullyQualifiedErrorId : FormatException
C:\Users\lambda>set usr=
C:\Users\lambda>goto :EOF
C:\Users\lambda>call :atob pwd "SGZzemxwNzc3"
C:\Users\lambda>for /F "delims=" %I in ('powershell "[Text.Encoding]::UTF8.GetString([convert]::FromBase64String(\"SGZzemxwNzc3\"))"') do set pwd=%I
C:\Users\lambda>set pwd=Hfszlp777
C:\Users\lambda>goto :EOF
C:\Users\lambda>schtasks /Run /S aaa.bbb.ccc.ddd /U   /P Hfszlp777 /TN "My Scheduler Task Name"
Erreur : Syntaxe incorrecte. Valeur attendue pour '/U'.
Entrez "SCHTASKS /RUN /?" pour afficher la syntaxe.
C:\Users\lambda>goto :EOF

Without the last 2 '=' characters, the number of character of my Base54 value u64 is not a multiple of 4, therefore it cannot be decoded. We can see in the output that it is working fine with p64. usr only stores a space... And I want to stick with a .bat file for now, not a .ps1 script please. Thanks for your help. I have tried several combinations of surrounding with "", but so far with same result.


Solution

  • Changing FromBase64String(\"%~2\") to FromBase64String('%~2') also fixes the problem in my testing. I can't say why the equal signs are being converted to a space, but I can say that in PowerShell, single-quoted strings are treated as literals, whereas double-quoted strings allow evaluation of the string's contents.

    From a cmd prompt, try

    powershell "\"$null\""
    

    then try

    powershell "'$null'"
    

    and observe the different behavior.

    Alternatively, you could assign a variable to %~2 in your batch subroutine, then refer to it in the env: scope within PowerShell.

    :atob <var_to_set> <str>
    set "str=%~2"
    for /f "delims=" %%I in (
       'powershell "[Text.Encoding]::UTF8.GetString([convert]::FromBase64String($env:str))"'
    ) do set "%~1=%%I"
    goto :EOF