Cygwin – How to Install with Chosen Packages from PowerShell

automationcygwinpowershellwindows

I'm working on a Powershell automation script that deploys various dependencies on a Windows Server box (as prep for creating an AMI from it) and one of the dependencies is Cygwin with various packages such as Python, Curl, etc.

Installing Cygwin with packages manually is a piece of cake, you just choose them from the vast selection available in one of the install wizard's steps. However, for a script this needs to be done via command-line.

Cygwin's FAQ specifies various command line arguments but I couldn't figure out:

  • Exactly which arguments I should use, such as whether --download is required
  • And most importantly how package names need to be specified with the --packages argument

From other posts on serverfault I did find out that it's a list of package names split with commas, but couldn't find a working example or a list of acceptable package names I could use.

An ideal solution for me would be a way to "export" or "migrate" the packages I've installed via the manual process to a script which I can run.

Best Answer

Eventually I figured out a solution that worked for me, and would like to share the detailed explanation that I couldn't find anywhere in hopes it will assist someone like me in the future.

Step 1: Export a list of installed packages in Cygwin

To export the list, open Cygwin and run this command: cygcheck -c -d | sed -e "1,2d" -e "s/ .*$//" | awk 'NR==1{printf $0}{printf ",%s", $0}'

This command consists of 3 different applications, cygcheck, sed and awk piping the results from one to the next, so lets break them down:

cygcheck is a utility bundled with Cygwin used to validate the Cygwin deployment. cygcheck -c -d means: -c to inspect packages and -d to only dump them without actually checking if they're OK. This command results in an ASCII table of correct package names and their versions.

sed is a command-line based, line by line text editor which here cleans up the input, so -e "1,2d" deletes the first 2 lines (that contain table headers) and -e "s/ .*$//" removes the spaces and version numbers, so you get a list of just package names.

Lastly awk is a text-processing programming language and here it helps to print the list out as one line separated by commas, so NR==1{printf $0} will just print the first line (first package name) and then {printf ",&s", $0} will print every subsequent package name with , before it.

The result then is a single line, comma-separated list of valid Cygwin packages which can be used for the command-line installer.

Step 2: Install using command-line

The arguments I found I need for a command-line installation are:

  • --quiet-mode to install in unattended mode
  • --root to define where Cygwin should be installed on the drive
    I chose c:\cygwin64
  • --site to define the mirror from which files should be downloaded
    I used http://cygwin.mirror.constant.com. You can use any mirror from the Cygwin Mirrors page, just make sure to include the http:// prefix!
  • --packages to define exactly which packages should be installed
    The list created in the previous step should be wrapped in double quotes (") and look like so: --packages "pkg1,pkg2,pkg3"

This results in the following command format: setup-x86_64.exe --quiet-mode --root c:\cygwin64 --site http://cygwin.mirror.constant.com --packages "curl,python,python-crypto"

Step 3: Running the installer as part of a Powershell script

In my ps1 script file, I used Start-Process to run the Cygwin installer and wait for it to finish before running the next command.

The final line of code looks like: Start-Process "$PSScriptRoot\assets\setup-x86_64.exe" -ArgumentList "--quiet-mode --root C:\Cygwin64 --site http://cygwin.mirror.constant.com --packages `"curl,python,python-crypto`"" -Wait -NoNewWindow;