Recently, I faced the challenge of moving a project with an InstallShield installer output from one of our local machines to an Azure DevOps build definition. Of course, since DevOps build definitions run on virtual machines created ad-hoc for the build task, one of the first ideas that sparked into my mind was using a docker container. As a matter of fact, in December 2019 Flexera, the company behind InstallShield, released its 2019 R3 version of InstallShield, announcing docker support for its standalone installer.
Although the original guide on setting up a docker image covers pretty much all the basics for a simple docker image that works with the R3 version, much of the potential versatility of the container is put aside and left as an exercise for the reader: for example, our project needed to update the GUID codes needed to perform updates from an old version to the latest one, and I didn’t want to include the license file as part of the container, but rather pass it through other means during the container run.
What I’m presenting you is the way I implemented my docker image, and the escamotages I rely upon to make it more flexible and able to run on Azure DevOps. By no means this is an optimal docker image, but it serves its purpose and it serves it well for our current needs.
IMPORTANT: I assume your project is written with Visual Studio in a windows environment, with its InstallShield project already set up and running (meaning you have access to the standalone installer and have an active InstallShield license)
Step 1: Get the boilerplate!
I made a GitHub repository for my project so that you have the initial setup ready. Clone or fork the repository from here.
A few words on how the repository is structured:
- The image in the FROM clause in the dockerfile points to the windows server 2019 image which is currently (at the time of writing) supported as cached image on Azure DevOps: this avoids the need of downloading several GB of windows server image every time a build is launched; the latest-tag image should work as well if you intend to not run this image on Azure DevOps.
- The InstallerBuildFiles folder contains another folder called SetupPrerequisites. For our installer, we had to use some prerequisites in order to build it, so I added support for them through this folder. Simply copy any file you need from the original InstallShield machine in your prerequisites folder into this one.
- Disclaimer: the PowerShell file responsible for launching the build process is not optimal, I know, but I was in a hurry and it covers our needs. If you feel like contributing to the repository, feel free to submit your changes.
Step 2: Create your docker image.
Since this image requires R3 standalone builder version, I cannot provide it to you, because it can only be downloaded from the Flexera site by logging in. Chances are if you are reading this, you already have access to the installer. Put the installer .exe in the Docker folder of your cloned repository and rename it as:
Now you’re ready to build your docker image by opening a PowerShell, cd to the Docker folder of the repository on your local machine, and input the following command:
docker build -t installshield-standalone .
This will create a new docker image tagged as installshield-standalone (don’t worry: if you then need to push this image to your private repository you can tag it whatever you like in a second moment!). If everything went well, congrats! You have built an Installshield standalone docker image! Otherwise, check your steps carefully, you might have missed a crucial step.
Step 3: Copy your build artifacts and other needed files.
All your build files from your output folder along with the .ism file from your InstallShield project go in the folder called InstallerBuildFiles.
If you have additional prerequisites for your project, as stated before, copy the needed files from your build machine to the folder called SetupPrerequisites in the InstallerBuildFiles folder.
Step 4: Setup your docker run command.
Now you are ready to build your installer with the docker image. The image is run by the docker run command, with several additional parameters. The base command (do not run yet!) is:
docker run installshield-standalone
….but first, you’ll need to set up the environment variables before you can succeed in building your installer:
- Mount docker volumes: to pass the installer data to the docker image, you must mount the InstallerBuildFiles folder as a docker volume and mirror it to an image internal folder:
- MAC Address: You will need to set the MAC address of your container the same as the machine where you activated InstallShield on. Fortunately, with Docker, this is a pretty easy task: just pass the address in the format XX:XX:XX:XX:XX:XX like this:
- License: I chose to not include the license file in the docker image (as suggested by the original guide) but to pass it through a docker env variable. I prefer to pass data this way instead of hammering files into the image for many reasons: security – meaning that my image won’t contain a private license; convenience – meaning that I can pass my license as a string and set it as I prefer in my DevOps builds. For submitting your license as env variable, add the InstallShieldLicense env variable to the command and initialize it as your license string.
IMPORTANT: your license string must be on a single line, with the quote signs escaped. Also, keep the escape symbols you find in the license file and finally enclose everything in single quotes. You should end up with something like this example:
-env InstallShieldLicense='INCREMENT XXX.XXX.XXX mvsn XX.0 permanent uncounted \ VENDOR_STRING=Instance=X HOSTID=XXXXXX ISSUER=\"Flexera \ Software, Inc.\" ISSUED=29-mar-2020 SN=XXXXXXX-XXX-XXXXXXX\ TS_OK SIGN=\"XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX \ XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX \ XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX\"'
- Updatable installer: if you have an installer that performs updates, you know that you need to update the product code and package code of InstallShield any time you release a new version. By setting IsInstallerUpdatable env variable to true, the docker image will create new GUID codes for both product and package code.
- Installer file version: If you need to update the installer file version use the InstallerFileVersion env variable:
If you followed everything, you should end up with a command like this one:
docker run --mac-address XX:XX:XX:XX:XX:XX -v "C:\Users\GMPrazzoli\Desktop\InstallerBuildFiles:C:\InstallerBuildFiles" --env InstallShieldLicense='INCREMENT XXX.XXX.XXX mvsn XX.0 permanent uncounted \ VENDOR_STRING=Instance=X HOSTID=XXXXXX ISSUER=\"Flexera \ Software, Inc.\" ISSUED=29-mar-2020 SN=XXXXXXX-XXX-XXXXXXX\ TS_OK SIGN=\"XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX \ XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX \ XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX\"' --env IsInstallerUpdatable=true --env InstallerFileVersion=X.X.X.X installshield-standalone
Now, you just need to hit the enter key and if you did everything correctly, this should build your installer.
Some things might need to be tweaked a little to accommodate your projects, but you should have all the needed tools in your belt to edit this project. Happy coding!