InstallHelpers.psm1

Write-Verbose 'Importing from [D:\a\1\s\InstallHelpers\private]'
Write-Verbose 'Importing from [D:\a\1\s\InstallHelpers\public]'
# .\InstallHelpers\public\Get-ExpandedVersion.ps1
function Get-ExpandedVersion
{
    <#
    .SYNOPSIS
    Expands a wildcard version number into SemVer compatible min/max version numbers
     
    .DESCRIPTION
    Expands a wildcard version number into SemVer compatible min/max version numbers
 
    .PARAMETER Version
    Version number to expand
     
    .EXAMPLE
    Get-RamExpandedVersion 1.0.5
 
    -------------------
    Name Value
    MinimumVersion 1.0.5
    MaximumVersion 1.0.5
     
    .EXAMPLE
    Get-RamExpandedVersion 1.*
 
    -------------------
    Name Value
    MinimumVersion 1.0
    MaximumVersion 1.9999.9999
 
    .EXAMPLE
    Get-RamExpandedVersion 1.*.0
 
    -------------------
    Name Value
    MinimumVersion 1.0.0
    MaximumVersion 1.9999.9999
     
    .EXAMPLE
    Get-RamExpandedVersion 1.1.*
 
    -------------------
    Name Value
    MinimumVersion 1.1.0
    MaximumVersion 1.1.9999
     
     
    .EXAMPLE
    Get-RamExpandedVersion 0.5.*
 
    -------------------
    Name Value
    MinimumVersion 0.5.0
    MaximumVersion 0.5.9999
     
    #>

    [CmdletBinding()]
    [OutputType([hashtable])]
    param(
        [Parameter(Mandatory)]
        [string] $Version
    )
    
    begin
    {
        Set-StrictMode -Version 'Latest'
        Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
        $callerEA = $ErrorActionPreference
        $ErrorActionPreference = 'Stop'

        function YieldSemVer {
            param([string[]] $Parts)

            $wildcardFound = $false
            foreach($num in $Parts) {
                if ($wildcardFound -and $num -ne 0) {
                    throw "Version number not supported $($Parts -join '.')"
                }
                if ($num -eq '*' -or $wildcardFound) {
                    $wildcardFound = $true
                    9999
                } else {
                    $num
                }
            }
        }
    }
    
    process
    {
        try
        {
            if ($Version -match '\*')
            {
                [version] $minVersion = $Version.Replace('*', '0')


                $versionParts = $Version -split '\.'
                if ($versionParts.Length -lt 2) {
                    $versionParts += 0
                }
                if ($versionParts.Length -lt 3) {
                    $versionParts += 0
                }

                $semVerParts = YieldSemVer $versionParts
                [version] $maxVersion = [version]::new($semVerParts[0], $semVerParts[1], $semVerParts[2])
                @{
                    MinimumVersion = $minVersion
                    MaximumVersion = $maxVersion
                }    
            }
            else
            {
                [version] $versionObj = $Version
                @{
                    MinimumVersion = $versionObj
                    MaximumVersion = $versionObj
                }   
            }
        }
        catch
        {
            Write-Error -ErrorRecord $_ -EA $callerEA
        }
    }
}
# .\InstallHelpers\public\Get-ModuleSemVerInfo.ps1
function Get-ModuleSemVerInfo
{
    <#
    .SYNOPSIS
    Return semantic version information for the supplied module
     
    .DESCRIPTION
    Return semantic version information for the supplied module
 
    .PARAMETER InputObject
    The module to inspect
     
    .EXAMPLE
    Import-Module PSSeries5Dev -RequiredVersion 1.0.5
    Get-Module PSSeries5Dev | Get-ModuleSemVerInfo
 
    -----------------------
    AvailableVersion CurrentVersion InstalledVersion
    1.1.8 1.0.5 1.0.8
     
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        $InputObject
    )
    
    begin
    {
        Set-StrictMode -Version 'Latest'
        Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
        $callerEA = $ErrorActionPreference
        $ErrorActionPreference = 'Stop'
    }
    
    process
    {
        try
        {
            $moduleName = $InputObject.Name
            $versionRange = Get-SemVerRange ($InputObject.Version)
            $installed = Get-InstalledModule $moduleName @versionRange
            $repository = ($installed).Repository
            $availableVersion = Find-Module $moduleName -Repository $repository @versionRange -EA Ignore |
                Select-Object -Exp Version

            [PsCustomObject] @{
                AvailableVersion = $availableVersion
                CurrentVersion = $InputObject.Version
                InstalledVersion = ($installed).Version
            }
        }
        catch
        {
            Write-Error -ErrorRecord $_ -EA $callerEA
        }
    }
}
# .\InstallHelpers\public\Get-SemVerRange.ps1
function Get-SemVerRange
{
    <#
    .SYNOPSIS
    Return the range of version numbers that are compatible with the version number supplied
     
    .DESCRIPTION
    Return the range of version numbers that are compatible with the version number supplied
 
    Note: wildcard placeholder are supported
 
    .PARAMETER Version
    Version number to calculate a range for
     
    .EXAMPLE
    Get-RamSemVerRange 1.0.5
 
    -------------------
    Name Value
    MinimumVersion 1.0.5
    MaximumVersion 1.9999.9999
     
    .EXAMPLE
    Get-RamSemVerRange 1.1.4
 
    -------------------
    Name Value
    MinimumVersion 1.1.4
    MaximumVersion 1.9999.9999
 
    .EXAMPLE
    Get-RamExpandedVersion 0.2.6
 
    -------------------
    Name Value
    MinimumVersion 0.2.6
    MaximumVersion 0.2.9999
     
    .EXAMPLE
    Get-RamExpandedVersion 1.1.*
 
    -------------------
    Name Value
    MinimumVersion 1.1.0
    MaximumVersion 1.9999.9999
     
     
    .EXAMPLE
    Get-RamExpandedVersion 0.5.*
 
    -------------------
    Name Value
    MinimumVersion 0.5.0
    MaximumVersion 0.5.9999
     
    #>

    [CmdletBinding()]
    [OutputType([hashtable])]
    param(
        [Parameter(Mandatory)]
        [string] $Version
    )
    
    begin
    {
        Set-StrictMode -Version 'Latest'
        Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
        $callerEA = $ErrorActionPreference
        $ErrorActionPreference = 'Stop'
    }
    
    process
    {
        try
        {
            $expandedVersion = (Get-ExpandedVersion $Version)['MinimumVersion']

            $maxVersionNumber = if ($expandedVersion.Major -eq 0) {
                # still in beta: breaking changes cause minor version to bump
                [version]::new($expandedVersion.Major, $expandedVersion.Minor, 9999)
            } else {
                [version]::new($expandedVersion.Major, 9999, 9999)
            }
            @{
                MinimumVersion = [version]::new($expandedVersion.Major, $expandedVersion.Minor, $expandedVersion.Build)
                MaximumVersion = $maxVersionNumber
            } 
            
        }
        catch
        {
            Write-Error -ErrorRecord $_ -EA $callerEA
        }
    }
}
# .\InstallHelpers\public\Update-ModuleToLatestSemVer.ps1
function Update-ModuleToLatestSemVer
{
    <#
    .SYNOPSIS
    Find and install the highest semver compatible version update for the module supplied
     
    .DESCRIPTION
    Find and install the highest semver compatible version update for the module supplied
 
    .PARAMETER Name
    The name of the module to update
     
    .PARAMETER CurrentVersion
    The version of the module to check for semver compatible updates
     
    .PARAMETER InputObject
    The existing imported module to update
 
     
    .EXAMPLE
    Import-Module PSSeries5Dev -RequiredVersion 1.0.5
    Get-Module PSSeries5Dev | Update-RamModuleToLatestSemVer
     
    .EXAMPLE
    Update-RamModuleToLatestSemVer PSSeries5Dev -CurrentVersion 1.0.5
     
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory, ParameterSetName = 'Name', Position = 1)]
        [string] $Name,

        [Parameter(Mandatory, ParameterSetName = 'Name')]
        [version] $CurrentVersion,

        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Module', Position = 1)]
        [psmoduleinfo] $InputObject
    )
    
    begin
    {
        Set-StrictMode -Version 'Latest'
        Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
        $callerEA = $ErrorActionPreference
        $ErrorActionPreference = 'Stop'
    }
    
    process
    {
        try
        {
            $wasImported = $false
            if ($PSCmdlet.ParameterSetName -eq 'Name') {
                
                $modSpec = @{ModuleName = $Name; RequiredVersion = $CurrentVersion }
                $InputObject = Get-Module -FullyQualifiedName $modSpec

                if (!$InputObject) {
                    Import-Module -FullyQualifiedName $modSpec
                    $wasImported = $true
                    $InputObject = Get-Module -FullyQualifiedName $modSpec
                }
            }
            
            try {
                $moduleName = $InputObject.Name
                $moduleVersion = $InputObject.Version

                Write-Information "Check for updates to $moduleName v$moduleVersion"

                $version = $InputObject | Get-ModuleSemVerInfo
                
                Write-Verbose "Current version: $($version.CurrentVersion)"
                Write-Verbose "Installed compatible version: $($version.InstalledVersion)"
                Write-Verbose "Available compatible version: $($version.AvailableVersion)"
                
                if ($version.AvailableVersion -le $version.InstalledVersion) {
                    Write-Information " $moduleName already up to date"
                    return
                }

                Write-Information " Instal $moduleName v$($version.AvailableVersion)"
                $repository = (Get-InstalledModule $moduleName).Repository
                Install-Module $moduleName -Repository $repository -RequiredVersion ($version.AvailableVersion)
            }
            finally {
                if ($wasImported) {
                    Remove-Module -FullyQualifiedName $modSpec
                }
            }

            
        }
        catch
        {
            Write-Error -ErrorRecord $_ -EA $callerEA
        }
    }
}
Write-Verbose 'Importing from [D:\a\1\s\InstallHelpers\classes]'