95

I am trying to make an installer using batch. Of course, an installer needs to consist of files that will be installed, so I'm thinking of encoding the files in base64, and simply decode them and write them to their destination.

Of course, my work would be very easy if Windows had something like the base64 tool that Linux boxes contain. However, since it's simply not there, is there any way to decode base64 content completely using batch files? And how would I accomplish this?

Any help is appreciated.

(It's just an experiment, so I'm not worried about inefficiency and the like.)

kenorb
  • 155,785
  • 88
  • 678
  • 743

2 Answers2

183

Actually Windows does have a utility that encodes and decodes base64 - CERTUTIL

I'm not sure what version of Windows introduced this command.

To encode a file:

certutil -encode inputFileName encodedOutputFileName

To decode a file:

certutil -decode encodedInputFileName decodedOutputFileName

There are a number of available verbs and options available to CERTUTIL.

To get a list of nearly all available verbs:

certutil -?

To get help on a particular verb (-encode for example):

certutil -encode -?

To get complete help for nearly all verbs:

certutil -v -?

Mysteriously, the -encodehex verb is not listed with certutil -? or certutil -v -?. But it is described using certutil -encodehex -?. It is another handy function :-)

Update

Regarding David Morales' comment, there is a poorly documented type option to the -encodehex verb that allows creation of base64 strings without header or footer lines.

certutil [Options] -encodehex inFile outFile [type]

A type of 1 will yield base64 without the header or footer lines.

See https://www.dostips.com/forum/viewtopic.php?f=3&t=8521#p56536 for a brief listing of the available type formats. And for a more in depth look at the available formats, see https://www.dostips.com/forum/viewtopic.php?f=3&t=8521#p57918.

Not investigated, but the -decodehex verb also has an optional trailing type argument.

Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • 8
    [Certutil](http://technet.microsoft.com/library/cc732443.aspx) has been around since at least [Windows Server 2003](http://msdn.microsoft.com/en-us/subscriptions/cc773087.aspx). – David Ruhmann Jun 05 '13 at 18:00
  • 38
    I would have given some good odds that "base64 in batch" was the most desperate thing I ever entered in a search engine – nik.shornikov Aug 16 '13 at 03:36
  • 1
    @DavidRuhmann - Indeed, however, FWIW, the [2003 binary could be installed and used on Windows 2000](https://support.microsoft.com/en-us/kb/842210) – Greenonline Dec 26 '15 at 07:30
  • 4
    running `certutil -encode inputFileName encodedOutputFileName` generates a base64 string enclosed by "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" so you can't directly decode the file after it is produced. – David Morales Jan 21 '16 at 01:19
  • 2
    @DavidMorales - Not true! Did you try it? The -DECODE command works just fine with the header and footer in place. I'm not sure about the exact rules, but CERTUTIL -DECODE is very forgiving about the format of the encoded source. – dbenham Jan 21 '16 at 01:26
  • 1
    @dbenham I didn't try to decode using certutil but other decoders will fail with incorrect padding errors because of those 2 lines (which I did try). – David Morales Jan 21 '16 at 01:54
  • Fair enough, but I should think an installer for Windows should use native WIndows tools - ie CERTUTIL. But it is good that people understand there is extra info in the -ENCODE output. It is very easy to eliminate the header and footer lines, if desired, via `findstr /v /c:- certutilOutput.txt >cleanOutput.txt`. – dbenham Jan 21 '16 at 02:11
  • IMHO certutil is broken. In my case it works for small files but I have tried it with 90MB files and the result is: CertUtil: -encodehex command FAILED: 0x80070216 (WIN32: 534) CertUtil: Arithmetic result exceeded 32 bits – Andrzej Martyna Aug 29 '16 at 09:33
  • 4
    @AndrzejMartyna - it's not that it's broken, but there is a maximum input file size of 74472684 bytes. – SomethingDark Oct 03 '16 at 16:37
  • @SomethingDark, thanks! this is a valuable information but I wonder where have you find this limit? I will stick with my opinion that certutil is broken because (1) the limitation should be documented clearly to the user or (2) there should be no limitation. – Andrzej Martyna Oct 04 '16 at 06:16
  • 1
    @AndrzejMartyna - I agree that there should be no limit :) I was stress-testing a script I wrote that included a file converted to base64, and I needed to know how big the file could be, so I used good old-fashioned brute force to test progressively larger files until the script broke. – SomethingDark Oct 04 '16 at 06:18
  • @SomethingDark, I highly appreciate your approach! It is the only way to be sure how sth works. Saying "broken" I have also meant that you cannot trust such tool - you start using this but one day or another the limitation will hunt you and you are left without an alternative :( – Andrzej Martyna Oct 04 '16 at 06:25
  • 1
    Cool. Now I can transfer self-extracting .exe-files over the clipboard via Citrix, at least in chunks of 70 Megabytes ;) – Stefan Steiger Mar 30 '17 at 13:40
  • 1
    @RadagasttheBrown - No. It only processes files. – dbenham Nov 21 '18 at 15:24
  • Is there a way to store the resulting base64 to the clipboard instead of generating the file? – Archie G. Quiñones Jun 10 '19 at 01:54
  • @ArchieG.Quiñones - No, CERTUTIL cannot work directly with stdin or stdout, so there is no built in way to pipe the result to CLIP. But you can write a batch script that writes to a temporary file, TYPE the temp file and pipe the output to CLIP, and then delete the temp file. – dbenham Jun 10 '19 at 10:51
5

Here's a batch file, called base64encode.bat, that encodes base64.

@echo off
if not "%1" == "" goto :arg1exists
echo usage: base64encode input-file [output-file]
goto :eof
:arg1exists
set base64out=%2
if "%base64out%" == "" set base64out=con 
(
  set base64tmp=base64.tmp
  certutil -encode "%1" %base64tmp% > nul
  findstr /v /c:- %base64tmp%
  erase %base64tmp%
) > %base64out%
BSalita
  • 8,420
  • 10
  • 51
  • 68
  • 4
    This script will work better if you add `setlocal enabledelayedexpansion` and use `!base64tmp!` inside the `(...)`. Otherwise the value is determined when the `(...)` sequence is read in, not when it is executed. – Jesse Chisholm Nov 18 '18 at 03:45
  • 2
    a much simpler solution, without having to deal with the headers: https://stackoverflow.com/a/60404255/12861751 – ScriptKidd Apr 11 '20 at 04:08