functions/Test-Version.ps1

function Test-WUVersion {
    <#
        .SYNOPSIS
        Test if a version is in the allowed range.
 
        .DESCRIPTION
        Specify the allowed version range with parameters `-MaximumVersion`, `-MinimumVersion` and `-RequiredVersion`.
 
        .EXAMPLE
        PS C:\>Test-WUVersion -Version '1.0' -RequiredVersion '1'
 
        Returns $true
 
        PS C:\>Test-WUVersion -Version '2.0' -MaximumVersion '5.0'
 
        Returns $true
 
        PS C:\>Test-WUVersion -Version '2.0' -MaximumVersion '5.0' -MinimumVersion '3.0'
 
        Returns $false
 
        PS C:\>Test-WUVersion 1.0 -ExclusiveMinimumVersion 1.0
 
        Returns $false
 
        PS C:\>Test-WUVersion 1.1 -VersionRangeNotation '[1.0,2.0)'
 
        Returns $true
    #>


    [CmdletBinding(DefaultParameterSetName = 'RequiredVersion')]
    param (
        # Specify the version you want to test.
        [Parameter(Mandatory,
            Position = 0,
            ValueFromPipeline,
            ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Version,

        # Specifies the maximum allowed version, inclusive.
        [Parameter(ParameterSetName = 'RangedVersion')]
        [Alias('InclusiveMaximumVersion')]
        [string]
        $MaximumVersion,

        # Specifies the minimum allowed version, inclusive.
        [Parameter(ParameterSetName = 'RangedVersion')]
        [Alias('InclusiveMinimumVersion')]
        [string]
        $MinimumVersion,

        # Specifies the minimum allowed version, exclusive.
        [Parameter(ParameterSetName = 'RangedVersion')]
        [string]
        $ExclusiveMaximumVersion,

        # Specifies the minimum allowed version, exclusive.
        [Parameter(ParameterSetName = 'RangedVersion')]
        [string]
        $ExclusiveMinimumVersion,

        # Specifies the exact allowed version.
        [Parameter(ParameterSetName = 'RequiredVersion')]
        [Alias('ExactVersion')]
        [string]
        $RequiredVersion,

        # Specifies interval notation for specifying version ranges.
        [Parameter(ParameterSetName = 'VersionRangeNotation')]
        [string]
        $VersionRangeNotation
    )

    begin {
        Set-StrictMode -Version 'Latest'
    }

    process {
        [string[]]$PSBoundParameters.Keys |
        Where-Object { $_ -in 'Version', 'MaximumVersion', 'MinimumVersion', 'RequiredVersion', 'ExclusiveMaximumVersion', 'ExclusiveMinimumVersion' } |
        ForEach-Object {
            $aVariableName = $_
            $aVersionString = Get-Variable -Name $aVariableName -ValueOnly
            if (!$aVersionString) {
                return
            }

            if (!($aVersionString -match '^[\d][\d\.]*$')) {
                Write-Error "The version string '$aVersionString' specified in parameter '-$aVariableName' is invalid."
                return
            }

            if ($aVersionString -match '^\d+$') {
                # Ex. '1' to '1.0'
                $newVersionString = '{0}.0' -f $aVersionString

                Set-Variable -Name $aVariableName -Value $newVersionString
                $aVersionString = Get-Variable -Name $aVariableName -ValueOnly
            }

            if (!($aVariableName -eq 'Version')) {
                $dotCountDifference = ($Version -replace '[^\.]').Length - ($aVersionString -replace '[^\.]').Length

                if (!($dotCountDifference -eq 0)) {
                    # Ex. '1.0' and '1.0.1' to '1.0.0' and '1.0.1'
                    $isDotCountDifferenceNegative = $dotCountDifference -lt 0
                    $dotCountDifferenceAbsoluteValue = [Math]::Abs($dotCountDifference)
                    for ($i = 0; $i -lt $dotCountDifferenceAbsoluteValue; $i++) {
                        if ($isDotCountDifferenceNegative) {
                            Set-Variable -Name 'Version' -Value ('{0}.0' -f $Version)
                        }
                        else {
                            Set-Variable -Name $aVariableName -Value ('{0}.0' -f $aVersionString)
                        }
                    }
                }
            }
        }

        $allowedVersion = $Version |
        Where-Object {
            if (!$MaximumVersion) {
                return $true
            }
            [version]$_ -le [version]$MaximumVersion
        } |
        Where-Object {
            if (!$MinimumVersion) {
                return $true
            }
            [version]$_ -ge [version]$MinimumVersion
        } |
        Where-Object {
            if (!$ExclusiveMaximumVersion) {
                return $true
            }
            [version]$_ -lt [version]$ExclusiveMaximumVersion
        } |
        Where-Object {
            if (!$ExclusiveMinimumVersion) {
                return $true
            }
            [version]$_ -gt [version]$ExclusiveMinimumVersion
        } |
        Where-Object {
            if (!$RequiredVersion) {
                return $true
            }
            [version]$_ -eq [version]$RequiredVersion
        } |
        Where-Object {
            if (!$VersionRangeNotation) {
                return $true
            }
            # https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges
            $versionRangeNotationRegex = @(
                '^(?<InclusiveMinimumVersion>[\d.]+)$'
                '^\((?<ExclusiveMinimumVersion>[\d.]+),\)$'
                '^\[(?<ExactVersion>[\d.]+)]$'
                '^\(,(?<InclusiveMaximumVersion>[\d.]+)]$'
                '^\(,(?<ExclusiveMaximumVersion>[\d.]+)\)$'
                '^\[(?<InclusiveMinimumVersion>[\d.]+),(?<InclusiveMaximumVersion>[\d.]+)]$'
                '^\((?<ExclusiveMinimumVersion>[\d.]+),(?<ExclusiveMaximumVersion>[\d.]+)\)$'
                '^\[(?<InclusiveMinimumVersion>[\d.]+),(?<ExclusiveMaximumVersion>[\d.]+)\)$'
                '^\((?<ExclusiveMinimumVersion>[\d.]+),(?<InclusiveMaximumVersion>[\d.]+)]$'
            ) -join '|'

            if (!($VersionRangeNotation -match $versionRangeNotationRegex)) {
                Write-Error "The interval notation '$VersionRangeNotation' for specifying version ranges is invalid."
                return $false
            }

            $params = @{}
            if ($Matches['ExactVersion']) {
                $params += @{ ExactVersion = $Matches['ExactVersion'] }
            }
            else {
                $params += @{
                    InclusiveMaximumVersion = $Matches['InclusiveMaximumVersion']
                    InclusiveMinimumVersion = $Matches['InclusiveMinimumVersion']
                    ExclusiveMaximumVersion = $Matches['ExclusiveMaximumVersion']
                    ExclusiveMinimumVersion = $Matches['ExclusiveMinimumVersion']
                }
            }
            Test-WUVersion -Version $_ @params
        }

        return [bool]$allowedVersion
    }
}