Software Packaging

In our packer template we used chocolatey to install apps from their repository and now we are going to build our own scripts from the installers we uploaded into the Azure blob. We are doing this because not all software is packaged in choco, some companies might not like using chocolatey so as a first step you can create your own “repo” and slowly make the case for a local choco repo and later from choco public.

We are now talking about the steps highlighted in our packer template below:

The green square are scripts we will use to install software and to apply configurations.

The first step is to download the installer at build. We break the url from our installer so that we can replicate this step with other software. We uploaded tightVNC and got the following url

https://azmdfstorage.blob.core.windows.net/devopsartifacts/tightvnc-2.8.8-gpl-setup-64bit.msi

We can break this down in 2 parts:

You will most likely need to pass arguments and switches to the installer like /quiet so there is no user interaction. In the example below I use the Citrix VDA since there are multiple switches to use at installation:

$filename = "VDAWorkstationSetup_2009.exe"
$url = "https://azmdfstorage.blob.core.windows.net/devopsartifacts/"
$UnattendedArgs = "/quiet /optimize /components vda /controllers 'ctxconn01.acme.com' /noreboot /noresume /masterimage"
$filepath = "C:\Installers\"

Invoke-WebRequest -Uri ($url + $filename) -OutFile "$filepath\$filename" -Verbose -UseBasicParsing

I like to add a file path so I can download all the installers to a specific location. The directory is created in the packer template, a step before the custom installers.

Create a directory to place installers in a specific folder

Then, if using powershell, you can use the invoke-webrequest cmdlet to download the file and place it in the directory you instructed

Invoke-WebRequest -Uri ($url + $filename) -OutFile "$filepath\$filename" -Verbose -UseBasicParsing

Then you write a condition so that you can see if the program is already installed and exit codes so you know if the install ended successfully, needs a reboot or failed.

if (Test-Path ("C:\ProgramData\Citrix\XenDesktopSetup\XenDesktopVdaSetup.exe"))
{
	Write-Host "File already exists. Resuming install"
	$exit = (Start-Process ("C:\ProgramData\Citrix\XenDesktopSetup\XenDesktopVdaSetup.exe") -Wait -Verbose -Passthru).ExitCode
}
else
{
	#Write-Host "Downloading $filename"
	#Invoke-WebRequest -Uri ($url + $filename) -OutFile "$filepath\$filename" -Verbose -UseBasicParsing
	Write-Host "Installing VDA..."
	$exit = (Start-Process ("$filepath\$filename") $UnattendedArgs -Wait -Verbose -Passthru).ExitCode
}

#Track the exit codes.
if ($exit -eq 0)
{
	Write-Host "VDA INSTALL COMPLETED!"
}
elseif ($exit -eq 3)
{
	Write-Host "REBOOT NEEDED!"
}
elseif ($exit -eq 1)
{
	#dump log
	Get-Content "C:\Windows\Temp\VDA\Citrix\XenDesktop Installer\XenDesktop Installation.log"
	throw "Install FAILED! Check Log"
}

What I do to confirm and test the script is to run it on VM that has access to the internet or the Azure Blob and track the progress of the installation and exit codes. Some executables might not have standard exit codes, in these cases you can take out the lines for the exit codes and use the -Wait command to have powershell exit after the install process ends.

Start-Process ("$filepath\$filename") $UnattendedArgs -Wait -Verbose -Passthru

You can use this as a template to install other programs. I recommend testing the scripts individually before running the pipeline in case you have to debug. You can find a sample script in this git repo: https://git

Next we will show how to apply configurations.