Noveris.ModuleMgmt.psm1

<#
#>


########
# Global settings
$InformationPreference = "Continue"
$ErrorActionPreference = "Stop"
Set-StrictMode -Version 2

<#
#>

Function Select-ModuleVersionMatches
{
    [OutputType("System.String")]
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [string]$Version,

        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [int]$Major = -1,

        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [int]$Minor = -1,

        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [int]$Patch = -1,

        [Parameter(Mandatory=$false)]
        [switch]$StrictParse = $false
    )

    process
    {
        try {
            Write-Verbose "Parsing version $Version"
            $parsed = [Version]::Parse($Version)

            if ($Major -ge 0 -and $parsed.Major -ne $Major)
            {
                return
            }

            if ($Minor -ge 0 -and $parsed.Minor -ne $Minor)
            {
                return
            }

            if ($Patch -ge 0 -and $parsed.Build -ne $Patch)
            {
                return
            }

            $Version
        } catch {
            if ($StrictParse)
            {
                Write-Error "Failed to parse version string: $Version"
            } else {
                Write-Warning "Failed to parse version string: $Version"
            }
        }
    }
}

<#
#>

Function Install-PSModuleWithSpec
{
    [CmdletBinding()]
    param(
        [Parameter(mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Name,

        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [int]$Major = -1,

        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [int]$Minor = -1,

        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [int]$Patch = -1,

        [Parameter(mandatory=$false)]
        [switch]$Offline = $false,

        [Parameter(Mandatory=$false)]
        [ValidateSet("CurrentUser", "AllUsers")]
        [string]$Scope = "CurrentUser"
    )

    process
    {
        # If not offline, install the latest version that matches the spec, if it doesn't exist locally
        if (!$Offline)
        {
            $target = $null
            try {
                # Get the modules available online and filter by version spec
                $target = Find-Module -AllVersions -Name $Name -EA Stop |
                    ForEach-Object { $_.Version.ToString() } |
                    Select-ModuleVersionMatches -Major $Major -Minor $Minor -Patch $Patch |
                    Select-Object -First 1
                Write-Verbose "Find module result: $target"
            } catch {
                Write-Warning "Failed to get online module info for $Name"
            }

            # Get the local modules
            $installed = Get-Module -ListAvailable -Name $Name | ForEach-Object { $_.Version.ToString() }
            Write-Verbose ("Found local modules: " + ($installed -join ","))

            # If we found a match online, check if it is installed locally
            if (![string]::IsNullOrEmpty($target) -and ($null -eq $installed -or $installed -notcontains $target))
            {
                Write-Verbose "Installing module $Name version $target"
                Install-Module -Name $Name -RequiredVersion $target -Force -SkipPublisherCheck -Scope $Scope
            }
        }

        # Get the local modules and filter by spec
        $target = Get-Module -ListAvailable -Name $Name |
            ForEach-Object { $_.Version.ToString() } |
            Select-ModuleVersionMatches -Major $Major -Minor $Minor -Patch $Patch |
            Select-Object -First 1

        if ($null -eq $target)
        {
            Write-Error "Could not find suitable installed version for $Name"
        } else {
            # Return matching target version
            Write-Verbose "Found local module to import: $target"
            $target
        }
    }
}