PowerShell: Sorting Version Strings

Recently we had a large array of version strings we needed to sort. Like this, but way too long to sort by hand:

$Versions = @(
    '2.1.3',
    '1.2.3',
    '1.2.12'
)

Piping this array to Sort-Object changes the order, but not correctly.

$Versions | Sort-Object
1.2.12
1.2.3
2.1.3

It thinks 1.2.12 comes before 1.2.3. Comparing character-by-character, that’s true. 1 is less than 3. We need it to interpret everything after the period as one number. Then it’ll see that 3 is less than 12.

We can do this by casting the elements of the array to version before sorting.

[version[]]$Versions | Sort-Object

Major  Minor  Build  Revision
-----  -----  -----  --------
1      2      3      -1
1      2      12     -1
2      1      3      -1

The components are parsed out and stored individually as Major, Minor, and Build. Now that we’re sending versions instead of strings to Sort-Object, it compares the 3 build to the 12 build and gets the order right.

Of course, now we have version objects instead of the strings we started with. We can convert back with the ToString() method.

[version[]]$Versions | Sort-Object | foreach {$_.ToString()}
1.2.3
1.2.12
2.1.3

That one-liner is usually all that’s needed. The main limitation is the version class. It works with up to four integer components delimited by dots. That doesn’t handle some common conventions.

Versions are often prefixed with v, like v1.2.3. Fortunately, that doesn’t change the sorting. Just trim it out.

'v1.2.3'.TrimStart('v')
1.2.3

TrimStart() removes the v from the start of the string if it’s present, otherwise it’s a no-op. It’s safe to call on a mix of prefixed and non-prefixed strings. Run it on everything and sort like before.

Some of the patterns defined in the ubiquitous semver allow more characters and delimiters.

  • 1.0.0-alpha.1
  • 1.0.0+21AF26D3—-117B344092BD

One of these adds build metadata and semver doesn’t consider build metadata in precedence, so depending on your situation you might be able to just trim off the problem characters. If not, you’ll need a different parser.

Hope this helped!

Operating Ops

Need more than just this article? We’re available to consult.

You might also want to check out these related articles: