Software Package Management for Windows with Scoop

Posted on March 13, 2023 by Adrian Wyssmann ‐ 5 min read

While installing software on Linux comes naturally with a package manager, this is not so natural in Windows. However there are options.

Chocolatey

While I first experienced with Chocolatey as package manager for Windows, I am not very happy with it. The mayor downsides, is, that you need admin permissions and that the packages are not self-contained. Both are a problem in corporate environments where you might not have admin permissions and if you want to fully rely on proxied repositories. For example if you have a look at the package source of “python” you will see that the package source always points to an external source

<packageSourceUrl>https://github.com/chocolatey-community/chocolatey-packages/tree/master/automatic/python</packageSourceUrl>

So even if you can setup a proxy repo for the chocolatey repository, you still end up that chocolate will try to pull the package from an external source, which may fail if your work computer is prohibited to download files from external sources. Looking for alternatives to potentially overcome the shortcommings, I found [scoop] and winget.

Winget

While winget seems to be officially the package manager of choice by Microsoft, it still has the same problem as we have seen with chocolatey:

When running winget without administrator privileges, some applications may require elevation to install. When the installer runs, Windows will prompt you to elevate. If you choose not to elevate, the application will fail to install.

Winget only executes an installer, but has no control over default location, creating registry keys, adding binaries and shortcuts etc.

Scoop

To overcome both issues issues, I found Chocolatey and Winget Comparison · ScoopInstaller/Scoop Wiki (github.com)

How is Scoop different to Chocolatey?

  • Eliminates permission popup windows
  • Hides GUI wizard-style installers
  • Prevents PATH pollution from installing lots of programs
  • Avoids unexpected side-effects from installing and uninstalling programs
  • Finds and installs dependencies automatically
  • Performs all the extra setup steps itself to get a working program

Scoop does not require admin privileges, as Scoop downloads and installs packages in your homde under ~\scoop. For clis, Scoop creates shims inside the ~\scoop\shims folder, which is accessible in the PATH. For graphical applications, Scoop creates program shortcuts in a dedicated Start menu folder, called ‘Scoop Apps’.

Packaging for scoop or can we proxy the scoop repos?

Scoop packages are just JSON manifests which do not only define the package source but also define how to install a package, this includes the possibility to run additional commands and add registry keys, etc. The following example shows the git.json:

{
    "version": "2.39.1.windows.1",
    "description": "Distributed version control system",
    "homepage": "https://gitforwindows.org",
    "license": "GPL-2.0-only",
    "notes": "Set Git Credential Manager Core by running: \"git config --global credential.helper manager\"",
    "architecture": {
        "64bit": {
            "url": "https://github.com/git-for-windows/git/releases/download/v2.39.1.windows.1/PortableGit-2.39.1-64-bit.7z.exe#/dl.7z",
            "hash": "b898306a44084b5fa13b9a52e06408d97234389d07ae41d9409bdf58cad3d227"
        },
        "32bit": {
            "url": "https://github.com/git-for-windows/git/releases/download/v2.39.1.windows.1/PortableGit-2.39.1-32-bit.7z.exe#/dl.7z",
            "hash": "2cb1a83f30f0c2948c97d3dc683c8b058c808f89b51bfb813de67253d17caa15"
        }
    },
    "bin": [
        "bin\\sh.exe",
        "bin\\bash.exe",
        "cmd\\git.exe",
        "cmd\\gitk.exe",
        "cmd\\git-gui.exe",
        "cmd\\scalar.exe",
        "usr\\bin\\tig.exe",
        "git-bash.exe"
    ],
    "shortcuts": [
        [
            "git-bash.exe",
            "Git Bash",
            "--cd-to-home"
        ],
        [
            "cmd\\git-gui.exe",
            "Git GUI"
        ]
    ],
    "env_set": {
        "GIT_INSTALL_ROOT": "$dir"
    },
    "checkver": {
        "github": "https://github.com/git-for-windows/git",
        "regex": "v([\\w.]+)/PortableGit-(?<full>[\\w.]+)-64-bit"
    },
    "autoupdate": {
        "architecture": {
            "64bit": {
                "url": "https://github.com/git-for-windows/git/releases/download/v$version/PortableGit-$matchFull-64-bit.7z.exe#/dl.7z"
            },
            "32bit": {
                "url": "https://github.com/git-for-windows/git/releases/download/v$version/PortableGit-$matchFull-32-bit.7z.exe#/dl.7z"
            }
        },
        "hash": {
            "url": "https://github.com/git-for-windows/git/releases/tag/v$version",
            "regex": "<td>$basename</td>\\s*<td>$sha256</td>"
        }
    }
}

So we can easily create our own collection of applications or bucket as they call it. Ultimately it’s only a simple git repository containing JSON app manifests. We would maintain our own manifests, whereas the url points to the proxy repos for the respective binaries in our local artifact repository e.g. Artifactory. For example, let’s assume we proxy https://github.com/git-for-windows under the handleremote-generic-github-git, then url in our `git.json? would then point to https://artifactory.intra/remote-generic-github-git/git-for-windows/git/….) as follows:

{
    ...
    "architecture": {
        "64bit": {
            "url": "https://artifactory.intra/artifactory/remote-generic-github/git-for-windows/git/releases/download/v2.39.2.windows.1/PortableGit-2.39.2-64-bit.7z.exe",
            "hash": "20e3959d4e310a79b5cf4138797aa247d473d1f7b077a6c433cbfc4ddc5486f1"
        },
    ...
}

I addition you might also need to update the checkver properties, so scoop can properly check for newer versions. If you are using Artifactory this might look like that:

    "checkver": {
        "url": "https://artifactory.intra/artifactory/remote-generic-github/git-for-windows/git/releases/download/",
        "regex": "v([\\d.]+.windows.[\\d]+)"
    },

My first bucket

My first repo will contain git and 7zip, as latter is a pre-requirement for git. I basically copy the bin-folder from the main repo, as well as scripts and the respective json-files, which will lead me to a structure like this

├── bin
│   ├── auto-pr.ps1
│   ├── checkhashes.ps1
│   ├── checkurls.ps1
│   ├── checkver.ps1
│   ├── formatjson.ps1
│   ├── missing-checkver.ps1
│   └── test.ps1
├── bucket
│   ├── 7zip.json
│   └── git.json
└── scripts
    └── 7-zip
        ├── install-context.reg
        └── uninstall-context.reg

I would then go and adjust 7zip.json and git.json as described above:

  • update url’s to point to internal artifact repository
  • update checkver to work with internal artifact repository

In order to install scoop with going trough the company artifact repository, I will provide our own install script in an internal repository, by adjusting

  • path to the scoop package
  • path to the internal bucket

I do this by modifying these two parameters, assuming we use Artifactory:

$SCOOP_PACKAGE_REPO = "https://artifactory.intra/artifactory/api/vcs/downloadBranch/remote-vcs-github/scoopinstaller/scoop/master?ext=zip"
$SCOOP_MAIN_BUCKET_REPO = "https://bitbucket.intra/rest/api/latest/projects/PLAT/repos/scoop-sc/archive?format=zip"

This then allows me to install scoop and our internal scoop repo as main-bucket by executing

iwr -useb https://bitbucket.intra/projects/SCOOP/repos/installer/raw/install.ps1?at=refsr%2Fheads%2Fmain | iex

Once this is done, I can start installing packages like git

PS D:\workspace\papanito\scoop> scoop install git
Installing '7zip' (22.01) [64bit] from main bucket
7z2201-x64.msi (1.8 MB) [=====================================================================================] 100%
Checking hash of 7z2201-x64.msi ... ok.
Extracting 7z2201-x64.msi ... done.
Linking ~\scoop\apps\7zip\current => ~\scoop\apps\7zip\22.01
Creating shim for '7z'.
Creating shim for '7zFM'.
Creating shim for '7zG'.
Creating shortcut for 7-Zip (7zFM.exe)
Persisting Codecs
Persisting Formats
Running post_install script...
'7zip' (22.01) was installed successfully!
Notes
-----
Add 7-Zip as a context menu option by running: "C:\Users\papanitoas\scoop\apps\7zip\current\install-context.reg"
Installing 'git' (2.39.2.windows.1) [64bit] from main bucket
PortableGit-2.39.2-64-bit.7z.exe (46.1 MB) [==================================================================] 100%
Checking hash of PortableGit-2.39.2-64-bit.7z.exe ... ok.
Extracting PortableGit-2.39.2-64-bit.7z.exe ... done.
Linking ~\scoop\apps\git\current => ~\scoop\apps\git\2.39.2.windows.1
Creating shim for 'sh'.
Creating shim for 'bash'.
Creating shim for 'git'.
Creating shim for 'gitk'.
Creating shim for 'git-gui'.
Creating shim for 'scalar'.
Creating shim for 'tig'.
Creating shim for 'git-bash'.
Creating shortcut for Git Bash (git-bash.exe)
Creating shortcut for Git GUI (git-gui.exe)
'git' (2.39.2.windows.1) was installed successfully!
Notes
-----
Set Git Credential Manager Core by running: "git config --global credential.helper manager"

Conclusion

Scoop is a really nice way to install packages for windows and it overcomes two major shorcommings I see useful in a corporate environment

  • no admin permissions required to install software
  • fully on-prem repositories by downloading software from internal artifact repositories

However, you may keep one thing in mind: If the computer where you use scoop, is used by multiple users, then you might end up with multuple installations of the same software for each user (in the users home directory).