Compare Version Numbers with PowerShell

I recently needed to compare version numbers with PowerShell, so I could deduce which software was superseded by a later version.  But it turned out to be a little more complicated than anticipated!

In software versioning, I see 14.03.0.0 as being less than 14.1.0.56686.  I also see 14.1.0.6 being greater than 14.1.0.56686. Maybe I’m wrong?  Maybe it’s due to seeing software vendors wrongly version their software increments over the last 20 years and I’ve just got used to their logic?

Anyway, I ran some tests using the .Net [version] class and got the following:

$thisversion = "14.03.0.0"
$nextversion = "14.1.0.56686"

#test 1

switch (([version]$thisversion).CompareTo(([version]$nextversion))) {
    {$_ -lt 0} { write-host "$thisversion is less than $nextversion" }
    {$_ -gt 0} { write-host "$thisversion is greater than $nextversion" }
    {$_ -eq 0} { write-host "$thisversion is the same as $nextversion" }
}

#returns 14.03.0.0 is greater than 14.1.0.56686 - wrong?

$thisversion = "14.1.0.6"
$nextversion = "14.1.0.56686"

#test 2

switch (([version]$thisversion).CompareTo(([version]$nextversion))) {
    {$_ -lt 0} { write-host "$thisversion is less than $nextversion" } #returns this!  wrong!
    {$_ -gt 0} { write-host "$thisversion is greater than $nextversion" }
    {$_ -eq 0} { write-host "$thisversion is the same as $nextversion" }
}

#returns 14.1.0.6 is less than 14.1.0.56686 - wrong?

So in our first example, it seems like .Net versioning ignores the leading zero in ’03’ and deduces that 3 is greater than 1.  And in the second example, it deems that 56686 is greater than 6!  Logically this is probably correct when comparing integers!

However i think software vendors perhaps write versions based on significant figures.  So ’03’ is deemed as 3 (a unit), and the ‘1’ is deemed as ’10’ (a ten).  And  56686 is deemed as 56686, but the 6 is deemed as 60000!  Am i making any sense, or have I just made up my own versioning rules!!??

Either way, with help from others I contributed to writing a version comparison function that works….how software vendors work!

function CompareVersionStrings([string]$Version1, [string]$Version2) {

    $v1 = $Version1.Split('.') -replace '^0', '0.'
    $v2 = $Version2.Split('.') -replace '^0', '0.'   

    [Array]::Resize( [ref] $v1, 4 )
    [Array]::Resize( [ref] $v2, 4 )

     for ($i=0; $i-lt 4; $i++) {      
        switch (($v1[$i].length).CompareTo(($v2[$i].length))) {
            {$_ -lt 0} { $v1[$i] = $v1[$i].PadLeft($v2[$i].Length,'0') }
            {$_ -gt 0} { $v2[$i] = $v2[$i].PadLeft($v1[$i].Length,'0') }
        }
     }
     
     $v1f = $v1 | % {[float]$_}
     $v2f = $v2 | % {[float]$_}

    return [Collections.StructuralComparisons]::StructuralComparer.Compare( $v1f, $v2f )  

    #function returns
    #<0 "$Version1 is less than $Version2"
    #>0 "$Version1 is greater than $Version2"
    #0 "$Version1 is the same as $Version2"
}

#test 1
$thisversion = "14.03.0.0"
$nextversion = "14.1.0.56686"

switch (CompareVersionStrings $thisversion $nextversion) {
    {$_ -lt 0} { write-host "$thisversion is less than $nextversion" }
    {$_ -gt 0} { write-host "$thisversion is greater than $nextversion" } #returns this!  wrong!
    {$_ -eq 0} { write-host "$thisversion is the same as $nextversion" }
}

#returns 14.03.0.0 is less than 14.1.0.56686 - right!

#test 2

$thisversion = "14.1.0.6"
$nextversion = "14.1.0.56686"

switch (CompareVersionStrings $thisversion $nextversion) {
    {$_ -lt 0} { write-host "$thisversion is less than $nextversion" } #returns this!  wrong!
    {$_ -gt 0} { write-host "$thisversion is greater than $nextversion" }
    {$_ -eq 0} { write-host "$thisversion is the same as $nextversion" }
}

#returns 14.1.0.6 is greater than 14.1.0.56686 - right!