Creating a Standalone Offline Chocolatey Installer
The Chocolatey install documentation includes a section about why there isn't an MSI to install Chocolatey. In case that you are still searching for an executable, this post outlines a way to create your own "setup" using a self extracting 7-zip archive. We'll need the following directory structure:
config.txt: A 7-zip configuration fileinstall.bat: A wrapper script to callinstall.ps1install.ps1: This script will perform the actual installation inside the 7-zip archivebuild.ps1: The script which will create our target fileoutput/chocolateySetup.exe
config.txt
We're using a rather simple configuration, which will:
- Show the user a "Do you want to install Chocolatey?" yes/no prompt
- Run
install.batafter extracting the archive
The 7-zip SFX documentation outlines all available format options of a
config.txt file.
;!@Install@!UTF-8! Title="Chocolatey" BeginPrompt="Do you want to install Chocolatey?" ExecuteFile="install.bat" ;!@InstallEnd@!
install.bat
install.bat is a simple wrapper script which calls install.ps1. I found this
to be more convenient than trying to let the 7-zip SFX module call PowerShell
directly.
@ECHO OFF PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'" PAUSE
install.ps1
This script performs the actual installation by calling Chocolatey's
chocolateyInstall.ps1.
if ($env:ChocolateyInstall) {
Write-Warning 'Chocolatey is already installed!'
return
}
$env:ChocolateyInstall = "$($env:ProgramData)\chocolatey"
$root = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Path $psISE.CurrentFile.FullPath }
& (Join-Path $root 'chocolatey\tools\chocolateyInstall.ps1')
build.ps1
This script does a few things for us. It will:
- Download Chocolatey (v0.10.13) and extract it in a
tempdirectory - Download and extract the 7-zip SFX module in a
tempdirectory - Create the 7-zip archive
output\chocolateySetup.7zcontaining Chocolatey,install.ps1andinstall.bat - And finally, create the executable
output/chocolateySetup.exeby combiningoutput/chocolateySetup.7z,config.txtand the 7-zip SFX module
All calls to 7-zip are wrapped in an exec function, which I've described in a
previous post.
You can tweak the $chocoUrl parameter to download a different version of
Chocolatey. Keep in mind that you might need to delete the temp directory to
remove all "cached" files.
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 'Latest'
function exec {
param(
[Parameter(Mandatory = $true)]
[scriptblock]$ScriptBlock,
[int[]]$ValidExitCodes = @(0)
)
$global:LASTEXITCODE = 0
& $ScriptBlock
if (-not ($global:LASTEXITCODE -in $ValidExitCodes)) {
throw "Invalid exit code: $($global:LASTEXITCODE)"
}
}
$root = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Path $psISE.CurrentFile.FullPath }
$configFile = Join-Path $root 'config.txt'
$chocoUrl = 'https://chocolatey.org/api/v2/package/chocolatey/0.10.13'
$lzmaUrl = 'https://www.7-zip.org/a/lzma1900.7z'
$outputDir = Join-Path $root 'output'
$tempDir = Join-Path $root 'temp'
$installerFile = Join-Path $outputDir 'chocolateySetup.exe'
if (Test-Path $outputDir) {
Remove-Item $outputDir -Recurse -Force
}
New-Item $outputDir -Type Directory -Force | Out-Null
New-Item $tempDir -Type Directory -Force | Out-Null
$chocoDir = Join-Path $tempDir 'chocolatey'
if (-not (Test-Path $chocoDir)) {
$chocoZipFile = Join-Path $tempDir 'chocolatey.zip'
Invoke-WebRequest -Uri $chocoUrl -OutFile $chocoZipFile
Expand-Archive -Path $chocoZipFile -DestinationPath $chocoDir
}
$sfxFileName = '7zS2.sfx'
$sfxFile = Join-Path $tempDir $sfxFileName
if (-not (Test-Path $sfxFile)) {
$lzmaFile = Join-Path $tempDir 'lzma.7z'
Invoke-WebRequest -Uri $lzmaUrl -OutFile $lzmaFile
exec { 7z e $lzmaFile $sfxFileName -r -o"$tempDir" }
}
$installerZipFile = Join-Path $outputDir 'chocolateySetup.7z'
exec { 7z a $installerZipFile (Resolve-Path $chocoDir) }
exec { 7z a $installerZipFile 'install.bat' }
exec { 7z a $installerZipFile 'install.ps1' }
Get-Content $sfxFile, $configFile, $installerZipFile -Encoding Byte -Read 512 | Set-Content $installerFile -Encoding Byte
Usage
Given the above files, call build.ps1 to create output\chocolateySetup.exe.
Run the setup file, confirm the UAC prompt and the "Do you want to install Chocolatey?"
dialog to start the install process.
There's currently only one drawback that I'm aware of: After running the installer, Windows might pop up a "This program might not have installed correctly" message, even if the overall installation might be successful. Others have reported similar problems on superuser and StackOverflow.