Public/Compare-Version.ps1

function Compare-Version {
  <#
    .SYNOPSIS
    Compare version numbers

    .DESCRIPTION
    Compare the specified version numbers

    .PARAMETER Version
    The version parameter corresponds to the version number to test.

    .PARAMETER Operator
    The operator parameter corresponds to the type of comparison to operate.

    .PARAMETER Reference
    The reference parameter corresponds to the reference version number to compare the specified version against.

    .PARAMETER Format
    The format parameter corresponds to the format of the numbering.

    .NOTES
    File name: Compare-Version.ps1
    Author: Florian Carrier
    Creation date: 2019-10-19
    Last modified: 2024-09-11
    WARNING In case of modified formatting, Compare-Version only checks the semantic versionned part

    .LINK
    https://semver.org/

    .LINK
    https://learn.microsoft.com/en-us/dotnet/api/system.version

    .LINK
    https://learn.microsoft.com/en-us/dotnet/api/system.version.compareto
  #>

  [CmdletBinding (
    SupportsShouldProcess = $true
  )]
  Param (
    [Parameter (
      Position    = 1,
      Mandatory   = $true,
      HelpMessage = "Version number to test"
    )]
    [ValidateNotNullOrEmpty()]
    [System.String]
    $Version,
    [Parameter (
      Position    = 2,
      Mandatory   = $true,
      HelpMessage = "Comparison operator"
    )]
    [ValidateSet (
      "eq", # Equals
      "ne", # Not equals
      "gt", # Greater than
      "ge", # Greater than or equal
      "lt", # Less than
      "le"  # Less than or equal
    )]
    [System.String]
    $Operator,
    [Parameter (
      Position    = 3,
      Mandatory   = $true,
      HelpMessage = "Reference version number to check against"
    )]
    [ValidateNotNullOrEmpty()]
    [System.String]
    $Reference,
    [Parameter (
      Position    = 4,
      Mandatory   = $false,
      HelpMessage = "Numbering format"
    )]
    [ValidateSet (
      "modified",
      "semantic"
    )]
    [System.String]
    $Format = "semantic"
  )
  Begin {
    # Get global preference vrariables
    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
  }
  Process {
    switch ($Format) {
      "semantic" {
        Write-Log -Type "DEBUG" -Message "Semantic version comparison"
        # Prepare version numbers for comparison
        try {
          $VersionNumber = [System.Version]::Parse($Version)
        } catch [FormatException] {
          Write-Log -Type "ERROR" -Object "The version number ""$Version"" does not match $Format numbering"
          return $false
        }
        try {
          $ReferenceNumber = [System.Version]::Parse($Reference)
        } catch [FormatException] {
          Write-Log -Type "ERROR" -Object "The version number ""$Reference"" does not match $Format numbering"
          return $false
        }
        # Compare versions
        $Compare = $VersionNumber.CompareTo($ReferenceNumber)
        if (($Operator -in ("eq", "ge", "le")) -And ($Compare -eq 0)) {
            return $True
        } elseif (($Operator -in ("ne", "ge", "gt")) -And ($Compare -eq 1)) {
            return $True
        } elseif (($Operator -in ("ne", "le", "lt")) -And ($Compare -eq -1)) {
            return $True
        } else {
            return $False
        }
      }
      "modified" {
        Write-Log -Type "DEBUG" -Message "String version comparison"
        if ($Operator -in ("eq", "ne")) {
          # Compare strings as-is
          $VersionNumber    = $Version
          $ReferenceNumber  = $Reference
        } else {
          # Parse version numbers
          $SemanticVersion = Select-String -InputObject $Version -Pattern '(\d+.\d+.\d+)(?=\D*)' | ForEach-Object { $PSItem.Matches.Value }
          try {
            $VersionNumber = [System.Version]::Parse($SemanticVersion)
          } catch [FormatException] {
            Write-Log -Type "ERROR" -Object "The version number ""$Version"" does not match semantic numbering"
            return $false
          }
          $SemanticReference = Select-String -InputObject $Reference -Pattern '(\d+.\d+.\d+)(?=\D*)' | ForEach-Object { $PSItem.Matches.Value }
          try {
            $ReferenceNumber = [System.Version]::Parse($SemanticReference)
          } catch [FormatException] {
            Write-Log -Type "ERROR" -Object "The version number ""$Reference"" does not match semantic numbering"
            return $false
          }
        }
        # Build comparison command
        $Command = """$VersionNumber"" -$Operator ""$ReferenceNumber"""
        Write-Log -Type "DEBUG" -Object $Command
        # Execute comparison
        $Result = Invoke-Expression -Command $Command
        # Return comparison result
        return $Result
      }
      default {
        Write-Log -Type "ERROR" -Object "The $Format versionning format is not yet supported"
        return $false
      }
    }
  }
}