Tuesday, October 29, 2013

Automating software installs

This is my favourite software development topic: automating installs.

I'm a lazy programmer, in the sense that Larry Wall talks about when he says laziness is one the three great virtues of a programmer: that means I hate doing things manually over and over again. I'd rather spend an hour writing a script to download and install a utility, then doing it manually many times on multiple machines. Automating the installation of tools also has some other benefits: (a) it ensures the consistent replication of environments and (b) it serves as documentation of exactly what was done for future reference.

Nowadays I make a lot of use of virtual machines (mostly using Hyper-V recently) for my development on Windows. This allows me to easily delete VMs and start over as often as I like. It also means I can keep my development environments separate: e.g. one VM for Java/Eclipse, one for an older version of Visual Studio, one for playing with Ubuntu, etc.

When you install a lot of development environments over and over, you need to be aware of the different tools available to help automate things. In the Linux world, automated/unattended installs are the norm (using things like apt-get), but in Windows it takes a bit more effort to automate the installation of applications.

Here's a few ideas for installing utilities/tools from the command-line (i.e. from scripts):
  • Chocolatey - very cool tool to install lots of popular applications with a simple command like: cinst notepadplusplus
  • Ninite - Pick the applications you want to install and it generates a single installer to package them all.
  • DISM.exe - a Windows tool to Enable/Disable Windows Features from the command-line. Use this to enable things like IIS or Hyper-V from a script.
  • WebPICmd.exe - Microsoft Web Platform Installer - install certain products like SQL Server Express from the command-line.
  • In some cases it's easy enough to just write your own customer silent installer for a product. A lot of applications use InstallShield or other well-known installers and a lot of them behave the same way, so it's usually possible to figure out which command-line parameters to pass to the installer to do an unattend/silent install.
In addition to the above tools, you obviously need to be comfortable writing scripts of some sort. In the old days, I used to use Perl for all of my scripting needs. In recent years I've done more plain Batch files and some PowerShell. PowerShell is great because it's so ubiquitous on Windows systems, but it does have a steep learning curve in my opinion. I'm currently trying Python as my primary scripting language instead of plain old Batch files.

Using Chocolatey:

As an example of using Chocolatey on Windows, let's install the first two tools every developer needs on their machine: cURL and the 7-Zip Command Line tool for extracting archives from the command-line:

First, install Chocolatey itself (requires .NET Framework 4.0 to be installed) and then we use cinst to install curl and 7za:
C:\> powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin
C:\>
C:\> cinst 7zip.commandline
C:\> cinst curl
And that's it!

Using Web Platform Installer (webpicmd):

Let's install webpicmd with Chocolatey and then we'll install IIS Express using webpicmd:
C:\> cinst webpicmd
Now list all packages matching "IIS":
C:\> webpicmd /List /ListOption:Available | findstr "IIS"
From the above we see that we're looking for the package called just "IISExpress", so install it:
C:\> webpicmd /Install /Products:IISExpress /AcceptEula
Using PowerShell to install utilities:

Now, for contrast, let's say you've got a clean Windows 7 machine and Chocolatey won't work yet (because the .NET framework ins't installed), then it's easy enough to roll your own automated installs of 7-Zip and cURL using PowerShell. Once we have 7za and curl, this bootstraps everything: next we can easily script the download and install .NET Framework and Chocolatey...

To download 7-Zip command-line version (7za) and extract it using PowerShell:
function Unzip-File
{
    param ([string]$zipFile, [string]$destFolder)
    New-Item -ItemType Directory -Force -Path $destFolder
    $shell = New-Object -Com Shell.Application
    $zip = $shell.NameSpace($zipFile)
    $shell.NameSpace($destFolder).CopyHere($zip.Items(), 16)
}

Write-Host "Installing 7-Zip Command Line (7za)..."
$dest = "$env:ProgramFiles\7-Zip"
$destFile = "$env:ProgramFiles\7-Zip\7za.exe"
if (!(Test-Path $destFile))
{
    Write-Host "Downloading 7za..."
    $wc = New-Object Net.WebClient
    $url = 'http://downloads.sourceforge.net/sevenzip/7za920.zip'
    $file = "$env:TEMP\7za920.zip"
    $wc.DownloadFile($url,$file)
    Write-Host "Unzipping to: $dest"
    Unzip-File $file $dest
    Remove-Item $file
}
else
{
    Write-Host "7za already installed."
}
Next, let's download cURL and copy it into the Windows directory (because it's a single file and then it's already in the PATH for easy use):
function Unzip-File
{
    param ([string]$zipFile, [string]$destFolder)
    
    $7z = "$env:ProgramFiles\7-Zip\7za.exe"
    if (Test-Path $7z)
    {
        $info = New-Object Diagnostics.ProcessStartInfo
        $info.FileName = $7z
        $info.Arguments = "x -y -o""$destFolder"" ""$zipFile"""
        $info.Verb = "runas"
        $proc = [Diagnostics.Process]::Start($info)
        $proc.WaitForExit()
    }
    else
    {
        $shell = New-Object -Com Shell.Application
        $zip = $shell.NameSpace($zipFile)
        $shell.NameSpace($destFolder).CopyHere($zip.Items(), 16)
    }
}

Write-Host "Installing cURL..."
$wc = New-Object Net.WebClient
$url = "http://www.paehl.com/open_source/?download=curl_732_0_ssl.zip"
$file = "$env:TEMP\curl.zip"
$wc.DownloadFile($url,$file)
Write-Host "Unzipping to: $env:windir"
Unzip-File $file $env:windir
Remove-Item $file
Now download the .NET Framework 4.5.1 using cURL (of course you can download it with PowerShell as well, but I like to use cURL):
C:\temp> curl -L http://go.microsoft.com/fwlink/?LinkId=322116 -o c:\temp\NDP451-KB2858728-x86-x64-AllOS-ENU.exe
C:\temp> NDP451-KB2858728-x86-x64-AllOS-ENU /q
Resources:
Post a Comment