Functions/Install-PsModuleFast.ps1

<#
.SYNOPSIS
   Installs and Imports a module
.DESCRIPTION
    Encapsulates the logic to ensure the required version is installed and loaded into the session.
    If not installed the module is downloaded to the CurrentUser scope.
    If a version that isn't compatible is loaded it will be removed
    If the version required isn't loaded it will be imported
    You can specify, ```-MinimumVersion```, ```-MaximumVersion``` in which case an appropriate version is loaded if installed. It will not go
    and install a later version even if one exists in the repository unless `-latest` is used
    If required version is specified only that version will be installed and imported .
.EXAMPLE
    none
.OUTPUTS
    none
.NOTES
    none
#>

Function Install-PsModuleFast {
    [CmdletBinding()]
    param([string]
        #Name of the module to install
          $module
        , #Minimum version to install and import
         [version] $version
         #Maximumversion to install and import
        , [version] $MaxVersion
        #The version that has to be found to install. Must be 3 part version number
        , [version] $RequiredVersion
        #Repository to look for modules
        , [string] $Repository
        #Will find the latest version within the Min and Max specified and install that
        ,[switch]$Latest)

    if ($requiredVersion.Build -eq -1) { throw "Required version has to be a 3 part version, " }

    Write-Verbose "Loading module $Module"

    Repair-PSModulePath;
    
    if ($Latest){ 
        $FindModuleArgs = @{Name=$Module}
        if ($version){$FindModuleArgs.Add("MinimumVersion",$version)}
        if ($MaxVersion){$FindModuleArgs.Add("MaximumVersion",$MaxVersion)}
        if ( $Repository){ $FindModuleArgs.Add("Repository",$Repository)}
            $RequiredVersion = (Find-Module @FindModuleArgs).Version
        }

    $InstallmoduleArgs = @{}
    if ($Repository) { $InstallmoduleArgs.Add("Repository", $Repository) }

    $VersionArgs = @{}
    if ($RequiredVersion) { $VersionArgs.Add("RequiredVersion", $RequiredVersion) }
    else{
        if ($Version) { $VersionArgs.Add("MinimumVersion", $Version) }
        if ($MaxVersion) { $VersionArgs.Add("MaximumVersion", $MaxVersion) }
    }
    if (Test-ShouldInstallModule -Module $Module @VersionArgs) {
        Write-Host " Installing module $module" -NoNewline
        install-module $module -force -AllowClobber -Scope CurrentUser -SkipPublisherCheck @InstallmoduleArgs @VersionArgs
        Write-Host " - installed $((get-module $module -ListAvailable).Version)"
    }

    if (Test-ShouldImportModule -module $module @VersionArgs) {
        Write-Host " importing module $module " -NoNewline
        get-Module $module | ForEach-Object{
            Write-Host " - removing $($_.version)" -NoNewline
            remove-module -Name $_.name -Verbose
        }
        import-module $module -force  @VersionArgs -Global -Verbose:$VerbosePreference
        Write-Host " - imported $((get-module $module).Version)"
    }
    
    Write-Host ("using module {0:-20} - {1}" -f $module, $($(Get-Module $module).version))
}

function Test-ShouldInstallModule() {
    [CmdletBinding()]
    [OutputType([Boolean])]
    param($module
        , [version]$RequiredVersion
        , [version]$MaximumVersion
        , [version]$MinimumVersion)
        
    $modulesInstalled = get-module $module -ListAvailable

    return Test-ShouldGetVersion -modules $modulesInstalled -RequiredVersion $RequiredVersion -MinimumVersion $MinimumVersion -MaximumVersion $MaximumVersion

}
function Test-ShouldImportModule() {
    [CmdletBinding()]
    [OutputType([Boolean])]
    param($module
        , [version]$RequiredVersion
        , [version]$MaximumVersion
        , [version]$MinimumVersion)
        
    $modulesLoaded = get-module $module 

    return Test-ShouldGetVersion -modules $modulesLoaded -RequiredVersion $RequiredVersion -MinimumVersion $MinimumVersion -MaximumVersion $MaximumVersion

}

function Test-ShouldGetVersion() {
    [CmdletBinding()]
    [OutputType([Boolean])]
    param($modules
         ,[version]$RequiredVersion
         ,[version]$MaximumVersion
         ,[version]$MinimumVersion)

    if ($null -ne $RequiredVersion ){

        write-Verbose "Required version"
        if ( -not ($modules.Version -eq $RequiredVersion)) {
            write-Verbose "Required version not found so have to install"
            return $true
        }
    }
    if ($null -ne $MinimumVersion -and -not ($modules.Version -ge $MinimumVersion)) {
        write-Verbose "Minimum version not found so have to install"
        return $true
    }
    if ($null -ne $MaximumVersion -and -not ($modules.Version -le $MaximumVersion)) {
        write-Verbose "Maximum version modules found so have to install"
        return $true
    }
    if (($null -ne $MinimumVersion) -and ($null -ne $MaximumVersion) ) {
        Write-Verbose "Min and Max"
        if (-not ($modules | Where-Object { $_.Version -ge $MinimumVersion -and $_.Version -le $MaximumVersion })) {
            write-Verbose "Minimum and Maximum version modules found so have to install"
            return $true
        }
    }
    if ($null -eq $modules ) {
        write-Verbose "No modules found so have to install"
        return $true
    }
    write-Verbose "All tests passed don't install - modules installed are $($modules.Version)"
    return $false;

}


# Function Install-PsModuleFast {
# [CmdletBinding()]
# param([string] $module
# , [version] $version
# , [parameter(Mandatory=$false)][string] $path)
#
# Repair-PSModulePath;
#
# Write-Verbose "Loading module $Module"
# if (-not (get-module $(join-path $path $module) -ListAvailable | Where-object Version -ge $version)) {
# Write-Output " Installing module $module"
# if ($null -eq $version) {
# install-module $module -path $path -force -AllowClobber -Scope CurrentUser -SkipPublisherCheck
# }
# else {
# install-module $module -path $path -force -AllowClobber -Scope CurrentUser -SkipPublisherCheck -MinimumVersion $version
# }
# }
#
# if (-not (get-module $module | Where-object Version -GE $version)) {
# Write-Output " importing module $module $version"
# if ($null -eq $version ) {
# import-module $module -force
# }
# else {
# import-module $module -force -MinimumVersion $version
# }
# }
# }

function Repair-PSModulePath {

    if ($PSVersionTable.PsEdition -eq "Core") {
        $mydocsPath = join-path ([System.Environment]::GetFolderPath("MyDocuments")) "PowerShell/Modules"
    }
    else {
        $mydocsPath = join-path ([System.Environment]::GetFolderPath("MyDocuments")) "WindowsPowerShell/Modules"
    }

    If ("$($env:PSModulePath)".Split([IO.Path]::PathSeparator) -notcontains $mydocsPath) {
        Write-Verbose "Adding LocalModule folder to PSModulePath"
        $env:PSModulePath = "$mydocsPath$([IO.Path]::PathSeparator)$($env:PSModulePath)"
    }
}

# $PSModules = @{Module = "Pester"; Version = "4.5" }, `
# @{Module = "Microsoft.PowerApps.PowerShell" }, `
# @{Module = "Microsoft.PowerApps.Administration.PowerShell" }, `
# @{Module = "VSSetup" }
# foreach ($Ps in $PSModules) {
#
# Install-PsModuleFast @PS
# }