PSGetInternal.psm1

$script:ModuleRoot = $PSScriptRoot

function Get-RepoCredential {
    <#
    .SYNOPSIS
    Function to get the credential file.
     
    .DESCRIPTION
    Function to get the credential file.
     
    .EXAMPLE
    PS C:\> Get-RepoCredential
 
    Function to get the credential file from the configuration path of the module.
    #>

    [OutputType([pscredential])]
    [CmdletBinding()]
    param()

    $credFilePath = Join-Path $Script:ConfigPath "RepoCred.clixml"

    Import-Clixml $credFilePath
}

function Find-GIModule {
    <#
    .SYNOPSIS
    Will search all modules in configured Company-Internal repository.
     
    .DESCRIPTION
    Will search all modules in configured Company-Internal repository.
     
    .PARAMETER Name
    Name of the module.
     
    .PARAMETER Credential
    Credential to get access to the configured Company-Internal repository.
     
    .EXAMPLE
    PS C:\> Find-GIModule
 
    Will list all modules in the configured Company-Internal repository.
 
    .EXAMPLE
    PS C:\> Find-GIModule -Name "Company-Module"
 
    Will search the module "Company-Module" in the configured Company-Internal repository.
    #>

    [CmdletBinding()]
    Param (
        [string]
        $Name = "*",

        [pscredential]
        $Credential = (Get-RepoCredential)
    )
    begin{
        if(-not $Script:Config){
            throw "Internal PSGallery not configured! Use Set-GIRepository to set up an internal Repository."
        }
    }
    process {
        Find-Module -Repository $Script:Config.Name -Name $Name -Credential $Credential
    }
}

function Install-GIModule {
    <#
    .SYNOPSIS
    Install a module from configured Company-Internal repository.
     
    .DESCRIPTION
    Install a module from configured Company-Internal repository.
     
    .PARAMETER Name
    Name of the module.
     
    .PARAMETER Credential
    Credential to get access to the configured Company-Internal repository.
 
    .PARAMETER Force
    Installs a module and overrides warning messages about module installation conflicts.
    If a module with the same name already exists on the computer, Force allows for multiple versions to be installed.
    If there is an existing module with the same name and version, Force overwrites that version.
 
    .PARAMETER AllowClobber
    Overrides warning messages about installation conflicts about existing commands on a computer.
 
    .PARAMETER AllowPrerelease
    Allows you to install a module marked as a pre-release.
 
    .PARAMETER MinimumVersion
    Specifies the minimum version of a single module to install. The version installed must be greater than or equal to MinimumVersion.
    If there is a newer version of the module available, the newer version is installed.
    If you want to install multiple modules, you can't use MinimumVersion.
    MinimumVersion and RequiredVersion can't be used in the same Install-GIModule command.
 
    .PARAMETER MaximumVersion
    Specifies the maximum version of a single module to install. The version installed must be less than or equal to MaximumVersion.
    If you want to install multiple modules, you can't use MaximumVersion.
    MaximumVersion and RequiredVersion can't be used in the same Install-GIModule command.
 
    .PARAMETER RequiredVersion
    Specifies the exact version of a single module to install.
    If there is no match in the repository for the specified version, an error is displayed.
    If you want to install multiple modules, you can't use RequiredVersion.
    RequiredVersion can't be used in the same Install-GIModule command as MinimumVersion or MaximumVersion.
     
    .PARAMETER Scope
    Specifies the installation scope of the module. The acceptable values for this parameter are AllUsers and CurrentUser.
 
    The AllUsers scope installs modules in a location that's accessible to all users of the computer:
 
    $env:ProgramFiles\PowerShell\Modules
 
    The CurrentUser installs modules in a location that's accessible only to the current user of the computer. For example:
 
    $HOME\Documents\PowerShell\Modules
 
    When no Scope is defined, the default is CurrentUser.
 
    .EXAMPLE
    PS C:\> Install-GIModule -Name "Company-Module"
 
    Will install the module "Company-Module" from the configured Company-Internal repository.
    #>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)]
        [string]
        $Name,

        [pscredential]
        $Credential = (Get-RepoCredential),

        [switch]
        $Force,

        [switch]
        $AllowClobber,

        [switch]
        $AllowPrerelease,

        [string]
        $MinimumVersion,

        [string]
        $MaximumVersion,

        [string]
        $RequiredVersion,

        [ValidateSet('AllUsers', 'CurrentUser')]
        [string]
        $Scope = 'CurrentUser'
    )
    begin {
        if (-not $Script:Config) {
            throw "Internal PSGallery not configured! Use Set-GIRepository to set up an internal Repository."
        }
        
        $param = @{
            Repository = $Script:Config.Name
            Name       = $Name
            Credential = $Credential
            Scope      = $Scope
        }
        if ($Force) { $param.Force = $Force }
        if ($AllowClobber) { $param.AllowClobber = $AllowClobber }
        if ($AllowPrerelease) { $param.AllowPrerelease = $AllowPrerelease }
        if ($MinimumVersion) { $param.MinimumVersion = $MinimumVersion }
        if ($MaximumVersion) { $param.MaximumVersion = $MaximumVersion }
        if ($RequiredVersion) { $param.RequiredVersion = $RequiredVersion }
    }
    process {
        Install-Module @param
    }
}

function Save-GIModule {
    <#
    .SYNOPSIS
    Save a module from configured Company-Internal repository to a specific path.
     
    .DESCRIPTION
    Save a module from configured Company-Internal repository to a specific path.
     
    .PARAMETER Name
    Name of the module.
     
    .PARAMETER Path
    Path where the module should be saved.
     
    .PARAMETER Credential
    Credential to get access to the configured Company-Internal repository.
     
    .EXAMPLE
    PS C:\> Save-GIModule -Name "Company-Module" -Path .
 
    Will save the module "Company-Module" from the configured Company-Internal repository to the current path.
    #>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory)]
        [string]
        $Name,

        [Parameter(Mandatory)]
        [string]
        $Path,

        [pscredential]
        $Credential = (Get-RepoCredential)
    )
    process {
        Save-Module -Repository $Script:Config.Name -Name $Name -Credential $Credential -Path $Path
    }
}

function Set-GIRepository {
    <#
    .SYNOPSIS
    This function will register a repository and create config and credential file.
     
    .DESCRIPTION
    This function will register a repository and create config and credential file.
     
    .PARAMETER Name
    Name of repository which should be registered.
     
    .PARAMETER SourceLocation
    URL of the repository, which should be registered.
     
    .PARAMETER Credential
    Credentials to get access to Company-Internal repository.
     
    .PARAMETER InstallationPolicy
    Parameter to trust or untrust the source of the repository.
     
    .EXAMPLE
    PS C:\> Set-GIRepository -Name "Contoso-Repository" -SourceLocation "https://pkgs.dev.azure.com/contosoINF/_packaging/InfernalAccounting/nuget/v2" -InstallationPolicy Trusted -Credential $cred
     
    Will register the trusted repository "Contoso-Repository" with SourceLocation "https://pkgs.dev.azure.com/contosoINF/_packaging/InfernalAccounting/nuget/v2".
    And will generate a config and credential file.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions','')]
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory)]
        [string]
        $Name,

        [Parameter(Mandatory)]
        [uri]
        $SourceLocation,

        [Parameter(Mandatory)]
        [pscredential]
        $Credential,

        [ValidateSet('Trusted', 'Untrusted')]
        [string]
        $InstallationPolicy = 'Trusted'
    )
    process {
        $existingRepo = Get-PSRepository -Name $Name -ErrorAction Ignore
        if (-not $existingRepo) {
            try {
                Register-PSRepository -Name $Name -SourceLocation $SourceLocation -InstallationPolicy $InstallationPolicy -Credential $Credential -ErrorAction Stop
            }
            catch {
                Write-Warning -Message "Error register Company-Internal Repository: $_"
                return
            }
        }else{
            if (($existingRepo.SourceLocation -ne $SourceLocation) -or ($existingRepo.InstallationPolicy -ne $InstallationPolicy)) {
                try {
                    Set-PSRepository -Name $Name -SourceLocation $SourceLocation -InstallationPolicy $InstallationPolicy -Credential $Credential -ErrorAction Stop
                }
                catch {
                    Write-Warning -Message "Error setting up Company-Internal Repository: $_"
                    return
                }
            }
        }
        
        $credFile = Join-Path $Script:configPath "RepoCred.clixml"
        $Credential | Export-Clixml -Path $credFile -Force

        $repository = [PSCustomObject]@{
            Name               = $Name
            SourceLocation     = $SourceLocation
            InstallationPolicy = $InstallationPolicy
        }
        $repoFile = Join-Path $Script:configPath "config.clixml"
        $repository | Export-Clixml -Path $repoFile -Force
        $Script:Config = $repository
    }
}

$Script:ConfigPath = Join-Path $env:LOCALAPPDATA "PowerShell\PSGetInternal"
$packagePath = Join-Path $env:LOCALAPPDATA "PackageManagement\ProviderAssemblies\nuget\2.8.5.208\Microsoft.PackageManagement.NuGetProvider.dll"

if(-not (Test-Path -Path $packagePath)){
    $null = New-Item -ItemType Directory -Path (Split-Path $packagePath) -Force
    Copy-Item -Path "$Script:ModuleRoot\bin\Microsoft.PackageManagement.NuGetProvider.dll" -Destination $packagePath -Force -Recurse
}

if(-not (Test-Path -Path $Script:ConfigPath)){
    $null = New-Item -ItemType Directory -Path $Script:ConfigPath -Force
}
if(Test-Path -Path (Join-Path $Script:ConfigPath 'config.clixml')){
    $script:config = Import-Clixml -Path (Join-Path $Script:ConfigPath 'config.clixml') -ErrorAction Ignore
}