22

In PowerShell, if I have a list of strings containing versions, "3.0.1.1", "3.2.1.1", etc., how can I sort it the way System.Version would sort it in C#?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
maxfridbe
  • 5,872
  • 10
  • 58
  • 80

5 Answers5

33
PS C:\> $ver="3.0.1.1","3.2.1.1"
PS C:\> $ver|%{[System.Version]$_}|sort

Major  Minor  Build  Revision
-----  -----  -----  --------
3      0      1      1
3      2      1      1
James Pogran
  • 4,279
  • 2
  • 31
  • 23
12

Just convert it to a Version and sort that way:

$list = "3.0.1.1","3.2.1.1" 
$sorted = $list | %{ new-object System.Version ($_) } | sort
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
6

A version string can be cast to a Version object, and sort-object can be passed a script block and sort on the result.

PS C:\Users\me> "3.11.0.1", "3.0.1.1", "3.2.1.1" | sort
3.0.1.1
3.11.0.1
3.2.1.1

PS C:\Users\me> "3.11.0.1", "3.0.1.1", "3.2.1.1" | sort {[version] $_}
3.0.1.1
3.2.1.1
3.11.0.1

(Added an extra version string to make the example actually meaningful.)

Nicolas Melay
  • 1,612
  • 1
  • 13
  • 12
2
# I needed to sort historical versions (Octopus) with varying decimal formats.
# Try # this (it is easy to add to a more complex expression sort)
# Special Case "3.00.1.10.1.10" and "3.0.1.10.1.10" required the double sort
# to work correctly
    $vers = @()`enter code here`
    $vers +=  @( "3.1.60",      "3.1.52","3.1.51")
    $vers +=  @( "3.00.46",     "3.00.36","3.50.2145.11")
    $vers +=  @( "3.50.2145.10","3.50.2145.9")
    $vers +=  @( "3.50.2145.8", "3.50.2145.7")
    $vers +=  @( "3.50.2145.6", "3.50.2145.5")
    $vers +=  @( "3.50.2145.4", "3.50.2145.3")
    $vers +=  @( "3.50.2145.2", "3.50.2145.1")
    $vers +=  @( "3.50.2145",   "3.50.2143")
    $vers +=  @( "3.50.2141",    "3.50.2135")    
    $vers +=  @( "3.0.1.10.1.1", "3.00.1.10.1.10")
    $vers +=  @( "2.1.3.4",      "3.0","3.")
    $vers +=  @( "3.0.1.10.1.100","3.0.1.10.1.10")
    $mySortAsc = @{Expression={ [regex]::Replace($_ ,'\d+', { $args[0].Value.PadLeft(20,'0') }) };Descending=$false}
    $mySortDesc = @{Expression={ [regex]::Replace($_ ,'\d+', { $args[0].Value.PadLeft(20,'0') }) };Descending=$true}    
    $nl = [Environment]::NewLine
    Write-Output ($nl + "Ascending Sort" + $nl);
    $vers | Sort-Object | Sort-Object $mySortAsc
    Write-Output ($nl + "Descending Sort" + $nl);
    $vers | Sort-Object -Descending | Sort-Object $mySortDesc
<# Result
Ascending Sort

2.1.3.4
3.
3.0
3.0.1.10.1.1
3.0.1.10.1.10
3.00.1.10.1.10
3.0.1.10.1.100
3.00.36
3.00.46
3.1.51
3.1.52
3.1.60
3.50.2135
3.50.2141
3.50.2143
3.50.2145
3.50.2145.1
3.50.2145.2
3.50.2145.3
3.50.2145.4
3.50.2145.5
3.50.2145.6
3.50.2145.7
3.50.2145.8
3.50.2145.9
3.50.2145.10
3.50.2145.11

Descending Sort

3.50.2145.11
3.50.2145.10
3.50.2145.9
3.50.2145.8
3.50.2145.7
3.50.2145.6
3.50.2145.5
3.50.2145.4
3.50.2145.3
3.50.2145.2
3.50.2145.1
3.50.2145
3.50.2143
3.50.2141
3.50.2135
3.1.60
3.1.52
3.1.51
3.00.46
3.00.36
3.0.1.10.1.100
3.00.1.10.1.10
3.0.1.10.1.10
3.0.1.10.1.1
3.0
3.
2.1.3.4
#>
phil
  • 21
  • 1
  • 2
    While this code may answer the question, providing additional context regarding **how** and **why** it solves the problem would improve the answer's long-term value. – Alexander May 10 '18 at 03:32
  • This works really well! I dont have proper System.Versions as my version names include a "V" before the numbers. The Regex does not seem to care about that. Nice! – Master Azazel Dec 06 '18 at 09:44
1

Just to add another corner case: powershell treats this single digit kind of version '2' as invalid. Have to add '.0' to the end to create the version object before sorting:

if($version  -match '^\d$')
{
  $version = $version + '.0'
}
New-Object System.Version $version
skypjack
  • 49,335
  • 19
  • 95
  • 187
Summer
  • 259
  • 3
  • 3