Updating apps with PowerShell 5.0 and Chocolatey

An introduction to the PackageManagement module

If you are using Windows 10 or if you have installed the Windows Management Framework 5.0 production Preview (available here), you may have noticed a PowerShell module named PackageManagement.

This is the new name for what was called “OneGet” in previous versions of the WMF 5.0.
It contains 10 cmdlets :

Module PackageManagement

So, what is this ?
This is a package manager manager. No, you are not seeing double. It really is a manager of package managers, in other words, a framework to integrate multiple package managers.
These package managers are called “PackageProviders” in OneGet terminology :

PS C:\> Get-PackageProvider

Name                     Version          DynamicOptions
----                     -------          --------------
msi                      10.0.10514.6     {AdditionalArguments}
msu                      10.0.10514.6     {}
Programs                 10.0.10514.6     {IncludeWindowsInstaller, IncludeSystemComponent}
NuGet                  {Destination, SkipDependencies, ContinueOnFailure, Excl...
Chocolatey             {SkipDependencies, ContinueOnFailure, ExcludeVersion, F...
PSModule                 {PackageManagementProvider, Location, InstallUpdate, In...

One of these awesome package managers is Chocolatey. Chocolatey is very popular and using its provider for PackageManagement gives us access to a software catalog of almost 3000 packages !

In the Production Preview of WMF 5.0 (from August), the Chocolatey provider is not installed by default. Fear not : it can be installed by just answering “Y” to the following prompt :

PS C:\> Find-Package -ProviderName chocolatey

The provider 'chocolatey v2.8.5.130' is not installed.
chocolatey may be manually downloaded from https://oneget.org/ChocolateyPrototype- and installed.
Would you like PackageManagement to automatically download and install 'chocolatey' now?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"):

Now, let’s install stuff !
We can search in the Chocolatey gallery using the cmdlet Find-Package , like so :

PS C:\> Find-Package -Source chocolatey -Name sublimetext2 -AllVersions

Name                           Version          Source           Summary
----                           -------          ------           -------
sublimetext2                   2.0.1            chocolatey       Sublime Text 2 is a sophisticate...
sublimetext2                   chocolatey       Sublime Text 2 is a sophisticate...
sublimetext2                chocolatey       Sublime Text 2 is a sophisticate...
sublimetext2                   2.0.2139         chocolatey       Sublime Text 2 (beta) is a sophi...
sublimetext2                   2.0.2165         chocolatey       Sublime Text 2 (beta) is a sophi...
sublimetext2                   2.0.2181         chocolatey       Sublime Text 2 (beta) is a sophi...
sublimetext2                   2.0.2210         chocolatey       Sublime Text 2 (beta) is a sophi...
sublimetext2                   2.0.22101        chocolatey       Sublime Text 2 is a sophisticate...

We see above that there are different versions for this package but we don’t have to worry about this, unless we want a specific version of a package. Without the parameter -AllVersions, this gets only the latest stable version of any given package.

Now, we install the latest stable version of Sublime Text :


So, we can manage the installation of one or multiple software packages right from PowerShell. This is nice, but how do we keep them up-to-date ?

As we have seen at the beginning of the post, there is a Install-Package cmdlet, a Uninstall-Package cmdlet, but there is no Update-Package cmdlet. According to this issue in the project page, this may be coming relatively soon.
In the meantime, let’s roll on own.

Updating Chocolatey packages with PowerShell

Let’s say we have a bunch of apps which were installed from Chocolatey with Install-Package, and if they are not up-to-date, we want to update them to the latest stable version available in the Chocolatey gallery.

Here is what we currently have :

PS C:\> Get-Package -ProviderName chocolatey

Name                           Version          Source           Summary
----                           -------          ------           -------
7zip                  C:\Chocolatey... 7-Zip is a file archiver with a...
7zip.install          C:\Chocolatey... 7-Zip is a file archiver with a...
autohotkey.portable          C:\Chocolatey... AutoHotkey is a free, open sour...
DotNet4.5                      4.5.20120822     C:\Chocolatey... The Microsoft .NET Framework 4.5
filezilla                      3.14.1           C:\Chocolatey... FileZilla – The free FTP solution
foxitreader                 C:\Chocolatey... Foxit Reader: The Best PDF Reader
github                         C:\Chocolatey... Git client for GitHub.com proje...
Recuva                         1.51.1063        C:\Chocolatey... Recuva recovers files deleted f...
SublimeText2                C:\Chocolatey... Sublime Text 2 is a sophisticat...
vlc                            2.2.0            C:\Chocolatey... VLC Media Player

The first thing we need to do is compare the currently installed version with the latest stable version in the Chocolatey gallery for each package :
Compare-Object Packages Version

As you can see above, Compare-Object is not going to help us very much. It is only telling us when a version number from one side is not found on the other side. What we want to know is : for each installed package, is the version number lower than the version number of the latest version in the Chocolatey gallery ?

To simplify our experimentations, we are going to work on a single package. When we are done, we’ll be able to use a foreach loop extend the logic to multiple packages, so it’s not a big deal. Let’s take VLC Media Player :

VLC Package Versions

Here, we see that our currently installed version of VLC is not the latest version available. Now, how can we programmatically and reliably determine that ?

We also see that on both sides the value of the Version property is a string. How do we compare strings ? With regular expressions, woohoo !!
Did you feel the irony in the “woohoo” ? I thought so.

Comparing version numbers reliably and taking into account all the possible versioning schemes using regex is feasible but very painful. As I said before, if you are parsing text in PowerShell, there is probably a better way.

The better way in this case, is to cast our miserable strings to powerful objects of the type Version :

PS C:\> [Version]$($CurrentPackage.Version)

Major  Minor  Build  Revision
-----  -----  -----  --------
2      2      0      -1

PS C:\> [Version]$($LatestPackage.Version)

Major  Minor  Build  Revision
-----  -----  -----  --------
2      2      1      20150630

PS C:\> [Version]$($CurrentPackage.Version) -lt [Version]$($LatestPackage.Version)

Thanks to the .NET Framework class System.Version, we can simply use a comparison operator (-lt, here) to reliably tell if the currently installed package has a lower version number than the latest version in the Chocolatey gallery.

If this is true (meaning if the installed package is not up-to-date), we update it from the Chocolatey gallery :

C:\> If ([Version]$($CurrentPackage.Version) -lt [Version]$($LatestPackage.Version)) {
    Install-Package -InputObject $LatestPackage } Else {
    Write-Output "$($CurrentPackage.Name) is up-to-date" }

Name                           Version          Source           Summary
----                           -------          ------           -------
vlc                     chocolatey       VLC Media Player

C:\> $CurrentPackage = Get-Package -ProviderName chocolatey -Name vlc
C:\> If ([Version]$($CurrentPackage.Version) -lt [Version]$($LatestPackage.Version)) {
    Install-Package -InputObject $LatestPackage } Else {
    Write-Output "$($CurrentPackage.Name) is up-to-date" }
vlc is up-to-date

The first if statement evaluates to True so it installs the latest version.
Following the update of the vlc package, we refresh the value of $CurrentPackage. Then, when we run the if statement again, it evaluates to False (as expected) so this doesn’t trigger a download and install.

That’s it.
I have encapsulated the same logic in a function called Update-ChocolateyPackage which can update all the Chocolatey packages, or only the package(s) specified with a -Name parameter. You can grab it here.

Also, it can be used to check the Chocolatey packages for updates, without actually updating anything. This can be done by adding the parameter -WhatIf.
The output “What if” information is only in the case where a package is not up-to-date, so no output means that all packages are up-to-date.

Leave a Reply

Your email address will not be published. Required fields are marked *