View on GitHub

Patrickhuber.github.io

blogs

Creating Enterprise Versions of Public Chocolatey Packages

In this post I address the issue of Chocolatey packages containing external links to msi, exe and other files.

The Problems

Package Review

For a large enterprise, packages must go through a review process before installation. As part of this review process, external links are discouraged because they require external calls during install and can make restoration of service difficult when the links change.

External Dependencies

In order to effectively utilize Chocolatey in the enterprise, packages that contain external links need to be rewritten with the external dependencies linked to an internal folder share or embedded in the package. The approach taken will depend on the size of the installer and how frequently updates to the chocolatey package are needed. Because Chocolatey packages are immutable, special care should be taken to releasing frequent iterations with an embedded solution. A large installer of, say, 1GB embedded in a package will quickly eat up space in a storage medium. In these cases, it may be better to rewrite the package to utilize a internal link to the installer instead of embedding the installer.

The anatomy of a Chocolatey package

What is a .nupkg file?

A chocolatey package is nothing more than a zip file with a .nupkg extension. Using a tool like 7zip you can explore the file contents as you would any other zip file.

I’ll be using 7zip to explore the package contents, but you could easily use a tool like Nuget Package Explorer or rename the file with a .zip extension and use the built in windows explorer zip support. If you are looking for a pure powershell option and have .NET 4.5 and Powershell 3, look here. The powershell community extensions (pscx) also has an option that you can install via chocolatey here

Examining the internals of a Chocolatey package

For this post, I’ll be taking the chocolatey package for Debug Diag and updating it to be both a self contained package and a package with an internal location for the installer. The link for the Debug Diag chocolatey package is located here:

debug diag

Using 7z.exe on the Command Line

In order to run 7z.exe runs 7zip from the command line, you may have to add the install directory to the environment variable path before 7z will execute on the command prompt.

PS > 7z l .\debugdiagnostic.2.1.0.7.nupkg

7-Zip [64] 9.22 beta  Copyright (c) 1999-2011 Igor Pavlov  2011-04-18

Listing archive: .\debugdiagnostic.2.1.0.7.nupkg

--
Path = .\debugdiagnostic.2.1.0.7.nupkg
Type = zip
Physical Size = 3931

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2015-01-20 10:14:24 .....          500          500  _rels\.rels
2015-01-20 10:14:24 .....         1830          786  debugdiagnostic.nuspec
2015-01-20 10:14:24 .....          265          156  tools\chocolateyInstall.ps1
2015-01-20 10:14:24 .....         1179         1179  package\services\metadata\core-properties\2838bbf8051044378d3fbfab8a2ea205.psmdcp
2015-01-20 10:14:24 .....          448          448  [Content_Types].xml
------------------- ----- ------------ ------------  ------------------------
                                  4222         3069  5 files, 0 folders

The “_rels” and “package” directories are created by chocolatey when using the choco pack operation.

Creating a New Download Location

We will be updating the tools\chocolateyInstall.ps1 file in order to update the installer download location.

Extracting

Extracting the contents of the nupkg file using 7zip we have the following command.

7z x debugdiagnostic.2.1.0.7.nupkg -odebugdiagnostic.2.1.0.7 * -r

This command will extract the package to a folder called “debugdiagnostic.2.1.0.7” to the file system. We can see the files produced by running the DIR command on the debugdiagnostic.2.1.0.7 directory.

PS \debugdiagnostic.2.1.0.7> dir

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         3/24/2015   9:53 AM            package
d----         3/24/2015   9:56 AM            tools
d----         3/24/2015   9:53 AM            _rels
-----         1/20/2015   9:14 AM       1830 debugdiagnostic.nuspec
-----         1/20/2015   9:14 AM        448 [Content_Types].xml

Opening the tools\chocolateyInstall.ps1 file we see the following contents

Install-ChocolateyPackage 'debugdiagnostic' 'msi' '/quiet' 'http://download.microsoft.com/download/B/4/6/B46E9984-5DF2-4B56-AE32-D60A88C2A6D8/DebugDiagx86.msi' 'http://download.microsoft.com/download/B/4/6/B46E9984-5DF2-4B56-AE32-D60A88C2A6D8/DebugDiagx64.msi'

We expand this script to several lines so that it is easier to see what is going on.

$packageName = 'debugdiagnostic'
$fileType = 'msi'
$silentArgs = '/quiet'
$url = 'http://download.microsoft.com/download/B/4/6/B46E9984-5DF2-4B56-AE32-D60A88C2A6D8/DebugDiagx86.msi'
$url64bit = 'http://download.microsoft.com/download/B/4/6/B46E9984-5DF2-4B56-AE32-D60A88C2A6D8/DebugDiagx64.msi'
Install-ChocolateyPackage $packageName $fileType $silentArgs $url $url64bit

Given this information, we now see that the chocolatey package is pulling the installer from two Microsoft hosted links. Lets change these links to be a UNC share on our local network.

Rewrite

Open the extracted ChocolateyInstall.ps1 and paste the locations to the UNC shares of http urls of the installers. Save the file and close the text editor.

Example:

$packageName = 'debugdiagnostic'
$fileType = 'msi'
$silentArgs = '/quiet'
$url = '\\InstallerHost\Microsoft\DebugDiag\2.1.0.7\DebugDiagx86.msi'
$url64bit = '\\InstallerHost\Microsoft\DebugDiag\2.1.0.7\DebugDiagx64.msi'
Install-ChocolateyPackage $packageName $fileType $silentArgs $url $url64bit

Update

Now we need to recreate the original chocolatey package with the updated chocolateyInstall.ps1.

We can use the “choco pack” command to repackage the artifacts, but we first need to cleanup some of the directories generated during the zip process.

rmdir _rels \s \q
rmdir package \s \q
del [Content_Types].xml

The folder is ready to be packaged. I ran “choco pack” from the same directory that the .nuspec file exists.

choco pack

Chocolatey v0.9.9.1
Attempting to build package from 'debugdiagnostic.nuspec'.
Successfully created package 'debugdiagnostic.2.1.0.7.nupkg'

I now need to move the file to the repository directory.

move debugdiagnostic.2.1.0.7.nupkg c:\chocolatey\local-repo\

Summary

We can now take the debugdiagnostic.2.1.0.7.nupkg and post it to a internal repository.

Creating a Self Contained Package

We will be updating the tools\chocolateyInstall.ps1 file, pointing it to a self contained installer.

Extracting

Similar to the previous section, we first need to extract the contents of the nupkg file to a local folder.

Assume that we have downloaded the package directly from source without performing any modifications.

7z x debugdiagnostic.2.1.0.7.nupkg -odebugdiagnostic.2.1.0.7 * -r

Again, this command will extract the package to a folder called “debugdiagnostic.2.1.0.7” to the file system. We can see the files produced by running the DIR command on the directory where the .nupkg lives.

PS \debugdiagnostic.2.1.0.7> dir

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         3/24/2015   9:53 AM            package
d----         3/24/2015   9:56 AM            tools
d----         3/24/2015   9:53 AM            _rels
-----         1/20/2015   9:14 AM       1830 debugdiagnostic.nuspec
-----         1/20/2015   9:14 AM        448 [Content_Types].xml

Rewrite

We will go to the download locations in the tools\chocolateyInstall.ps1 and pull down the x86 and x64 installers.

Inspecting the chocolateyInstall.ps1 file, we see the following urls.

'http://download.microsoft.com/download/B/4/6/B46E9984-5DF2-4B56-AE32-D60A88C2A6D8/DebugDiagx86.msi'
'http://download.microsoft.com/download/B/4/6/B46E9984-5DF2-4B56-AE32-D60A88C2A6D8/DebugDiagx64.msi'

I’m going to place the installers in the debugdiagnostic.2.1.0.7 folder in the tools directory.

$url = 'http://download.microsoft.com/download/B/4/6/B46E9984-5DF2-4B56-AE32-D60A88C2A6D8/DebugDiagx86.msi'
$url64bit = 'http://download.microsoft.com/download/B/4/6/B46E9984-5DF2-4B56-AE32-D60A88C2A6D8/DebugDiagx64.msi'

Invoke-WebRequest $url -OutFile 'DebugDiagx86.msi'
Invoke-WebRequest $url64bit -OutFile 'DebuDiagx64.msi'

Running the DIR command on the tools directory we now see the following contents

PS \debugdiagnostic.2.1.0.7\tools> dir

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-----         1/20/2015   9:14 AM        265 chocolateyInstall.ps1
-a---         3/24/2015   9:56 AM   22421504 DebugDiagx64.msi
-a---         3/24/2015   9:56 AM   17412096 DebugDiagx86.msi

Now we can modify the tools\chocolateyInstall.ps1 file to use these local msi files instead of using the remote locations.

$directory = $PSScriptRoot
$packageName = 'debugdiagnostic'
$fileType = 'msi'
$silentArgs = '/quiet'
$url = Join-Path $directory 'DebugDiagx86.msi'
$url64bit = Join-Path $directory 'DebugDiagx64.msi'
Install-ChocolateyPackage $packageName $fileType $silentArgs $url $url64bit

Update

Similar to the previous example, we will cleanup the directory removing chocolatey artifacts from the base directory.

rmdir _rels \s \q
rmdir package \s \q
del [Content_Types].xml

The folder is ready to be packaged. Running “choco pack”

choco pack

Chocolatey v0.9.9.1
Attempting to build package from 'debugdiagnostic.nuspec'.
Successfully created package 'debugdiagnostic.2.1.0.7.nupkg'

Again we move the file to the local repository.

move debugdiagnostic.2.1.0.7.nupkg c:\chocolatey\local-repo\

Summary

Again the package is ready to be consumed by choco install.

choco install debugdiagnostic -source '"c:\chocolatey\local-repo\"'

Conclusions

We have explored two ways to modify public chocolatey packages to enable enterprise consumption. When consuming these packages you will want to make sure to use a local repository in your chocolatey script. Also, if dependencies are loaded as part of your chocolatey package, you will need to make sure and modify them as well.