Tanzu CLI on Windows made easy

As the Tanzu ecosystem grows, the reliance on Tanzu CLI grows as well. While the CLI itself works very well cross platform, the main issue we consistently encounter is the pain of installing the Tanzu CLI on a windows machine.

The process which is documented by VMware in the TKG and TAP documentation, is a huge list of manual steps which many require administrative permissions, and is simply a really bad user experience.

In this blog post we will see a small POC i put together that can help solve this issue.

While this POC is based on the TAP version of the Tanzu CLI, it could easily be tweaked to work with the TKG version as well.

What options do we have

When trying to think about simplifying the installation process, my initial thought was to build a WinGet package which is then easily discoverable with the new WinGet exosystem or maybe to build a Chocolatey package.

While those 2 options are valid in many environments, some enterprises simply don’t allow these package managers, and also still today, the vast majority of machines don’t have them installed.

As i wanted to build a solution that would make the process better for as many people as possible, I had to find another option.

Another simple option would have been to just write a simple PowerShell script to do the installation. While this is an option and may be the right choice in some cases, I wanted to have a better experience and actually manage the Tanzu CLI as a package, which can have full lifecycle management from installation, through upgrades and finally uninstalling the CLI and of course cleaning up when uninstalling.

This all led me to the realization that the best option for what i was looking for was to build an MSI installer for the Tanzu CLI.

How to build an MSI

The first thing i needed to figure out was, how do i even build an MSI.

After some research I found 2 projects that seemed very interesting:

  1. Powershell Pro Tools
  2. Wix Toolset

When evaluating the 2 options, It was very clear that PowerShell Pro Tools was the right choice for a POC project, as it is much easier to get started with, and actually, the PowerShell Pro Tools uses the Wix mechanism under the hood but simply adds a simple abstraction layer above in PowerShell to make our lives much easier.

While the PowerShell Pro Tools module is great and can suffice many needs, i did end up having some issues with it, which led me to also utilize the wix toolset itself to patch the generated config for my needs.

How to build the initial config

The first step is to install the PowerShell Pro Tools module:

install-module PowerShellProTools

Once we have the module installed, we can start building our project.

You will need to download the Tanzu CLI zip file first as the MSI will need to contain these files.

Next we will need to generate a GUID which we need to save somewhere we will remember. This GUID is used as an ID of our MSI program which can be used later on when a new version comes out, so that the MSI can perform an upgrade.

$upgradeCode = ([guid]::NewGuid().ToString())        
write-host "Tanzu CLI MSI Upgrade Code: $upgradeCode"

Once we have the Tanzu CLI zip file on our machine we can begin defining some variables in PowerShell:

# This is the Directory where auto generated files and eventually our MSI will be placed
$outputDirName = "output"
# This is the TAP version we are building this package for
$tapVersion = "1.2.1"
# This is the name of the zip file we have downloaded already
$tanzuZipFileName = "tanzu-framework-windows-amd64.zip"
# This is your Companies name
$company = "TeraSky Israel"
# This is where you put the upgrade code from above
$upgradeCode = 'a8473e56-43ec-4665-9132-2ff94ac32b33'
# The name of the Product which in our case is TAP
$productName = "TAP"
# The current directory where all files will be located

Now that we have the needed variable set we need to create a few additional files:

  1. A script which performs the installation of the CLI and its plugins
  2. A script which uninstalls the CLI and its plugins
  3. An icon to be used for the program
  4. A file with VMware’s EULA for the Tanzu CLI

All of these files, as well as the final script that puts all of this solution together can be found in my GitHub repo .

Once we have those files locally in our current directory we can begin building our MSI itself.

A key feature that we are using in this MSI, is the ability to run scripts at specific hooks in the installation process. by default the MSI will simply copy files to a location we request, but we have a set of commands we need to run after the Tanzu CLI zip is copied over to the machine in order to install it as well as its plugins.

In order to define these actions we have a simple PowerShell command provided via the PowerShell Pro Tools module:

$installAction = New-InstallerCustomAction -FileId 'InstallPlugins' -CheckReturnValue -RunOnInstall   -arguments '-NoProfile -WindowStyle Normal -InputFormat None -ExecutionPolicy Bypass'

$uninstallAction = New-InstallerCustomAction -FileId 'UninstallPlugins' -RunOnUninstall -arguments '-NoProfile -WindowStyle Normal -InputFormat None -ExecutionPolicy Bypass'

Now that we have these actions defined in variables, we can run the command to build our MSI:

New-Installer -Productname $productName -Manufacturer $company -platform x64 -UpgradeCode $upgradeCode -Content {
  New-InstallerDirectory -PredefinedDirectory "ProgramFiles64Folder" -Content {
   New-InstallerDirectory -DirectoryName "tanzu" -Content {
      New-InstallerFile-Source .\$tanzuZipFileName -Id 'bundle'
     New-InstallerFile-Source .\install-plugins.ps1 -Id 'InstallPlugins'
     New-InstallerFile-Source .\uninstall-tanzu-cli.ps1 -Id 'UninstallPlugins'
     New-InstallerFile-Source .\EULA.rtf -Id 'EULA'
} -OutputDirectory (Join-Path$PSScriptRoot"$outputDirName") -RequiresElevation -version $tapVersion -CustomAction $installAction,$uninstallAction -AddRemoveProgramsIcon $DIR\tanzu-icon.ico

This command will generate a few configuration files as well as the initial MSI file, however we are going to delete the MSI file, tweak the configuration files and then regenerate the MSI.

The first change we need to make is to the way our scripts at installation and uninstall phases are run. As some of the changes we are making require administrative permissions, we need to make sure that the scripts run with elevated permissions.

This can be achieved via the following command:

((Get-Content -path $outputDirName\TAP.$tapVersion.x64.wxs -Raw) -replace '<CustomAction Id=','<CustomAction Impersonate="no" Id=') | Set-Content -Path $outputDirName\TAP.$tapVersion.x64.wxs

Basically, we need to add ‘Impersonate=”no”‘ to the custom action field in our XML config file.

The next change we need to make is to integrate a UI form which will have our EULA in it which should come up as part of the installation:

((Get-Content-path $outputDirName\TAP.$tapVersion.x64.wxs -Raw) -replace '</Product>','<UIRef Id="WixUI_Minimal" /><UIRef Id="WixUI_ErrorProgressText" /></Product>') | Set-Content -Path $outputDirName\TAP.$tapVersion.x64.wxs

Once these tweaks have been made, we can now delete the initial MSI and build the new one based on our modified configuration file.

As mentioned above, the Powershell Pro Tools module utilizes the Wix toolset under the hoods, which means we don’t need to install anything else in order to build our MSI as the tools are already present, we just need to find them:

$modulePath= (Get-Module -ListAvailable PowerShellProTools)[0].path
$modulePath = $modulePath.substring(0,$modulePath.LastIndexOf("\"))
$binPath = "$modulePath\Wix\bin"

With the variables set with the path to the needed tools, we can now rebuild our MSI using 2 simple commands:

& $binPath\candle.exe ".\TAP.$tapVersion.x64.wxs"
& $binPath\light.exe -dWixUILicenseRtf="$DIR\EULA.rtf" -ext WixUIExtension ".\TAP.$tapVersion.x64.wixobj" -o "TAP.$tapVersion.x64.msi"

Now that we have rebuilt our MSI, lets see what it looks like:

As we can see, we have a few configuration files, along with our MSI installer.

If we try to install the MSI via the UI:

Once we accept the EULA, we now get the UAC prompt as the installation requires admin permissions:

Once we accept the UAC prompt, the Tanzu CLI installation will begin and we should recieve about a minute later:

While the UI installation is nice, because this is an MSI, we can also perform the installation via automation using the msiexec.exe CLI tool for example:

# Must be run from ad elevated command prompt
msiexec /i TAP.1.2.1.x64.msi ACCEPT=YES /qr+


This was a pretty fun POC, and I think it proves that the experience of installating Tanzu CLI can be much better and more streamlined.

Hopefully, this is beneficial for those out there looking to simplify installation of Tanzu CLI or other tools that have similar experiences currently in terms of installation experience.

There are many things that would be needed to make something like this official, and production grade, but as a POC of about 1.5 hours overall, I think the results are pretty cool!

Leave a Reply

%d bloggers like this: