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#?
5 Answers
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
1 Comment
Korne127
You can also use
$ver | %{ $_ -as [System.Version] } | sort. This one will filter out invalid version numbers (while the original one from the answer will throw an error when encountering an invalid version string.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.)
1 Comment
Daz
Perfect many thanks!
# 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
#>
3 Comments
Alexander
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.
Master Azazel
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!
CrookedJ
@MasterAzazel you can just
$verList | sort { [version]($_ -replace '^v') }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
1 Comment
Major Malfunction
The .NET System.Version class declares version numbers consist of two to four components: major.minor[.build[.revision]].