Public/Install-PSModule.ps1

function Install-PSModule {
    <#
    .SYNOPSIS
    Installs a module from the PowerShell Gallery.
    .DESCRIPTION
    Installs a module with confirmation by default. Shows module details,
    version, scope, and dependency information before installing.
    .PARAMETER Name
    The module name.
    .PARAMETER Version
    Specific version to install. If not specified, installs latest.
    .PARAMETER Scope
    Installation scope: CurrentUser or AllUsers. Default is CurrentUser.
    .PARAMETER Repository
    The repository. Default is PSGallery.
    .PARAMETER Force
    Skip confirmation prompt.
    .EXAMPLE
    Install-PSModule -Name "Pester"
    .EXAMPLE
    Install-PSModule -Name "Az" -Version "9.0.0" -Scope AllUsers
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string]$Name,

        [string]$Version,

        [ValidateSet('CurrentUser', 'AllUsers')]
        [string]$Scope = 'CurrentUser',

        [string]$Repository = 'PSGallery',

        [switch]$Force
    )

    # Retrieve module info for confirmation display
    $info = $null
    try {
        $info = Invoke-ProviderGetInfo -Name $Name -Repository $Repository
    } catch {
        Write-Warning "Could not retrieve module info for '$Name'. Proceeding with basic install."
    }

    if (-not $info) {
        $info = [GalleryModuleInfo]::new()
        $info.Name = $Name
        $info.Version = $Version ?? 'latest'
        $info.Repository = $Repository
        $info.InstallStatus = 'NotInstalled'
    }

    $installVersion = if ($Version) { $Version } else { $info.Version }

    if ($Version) {
        try {
            $availableVersions = Invoke-ProviderGetVersions -Name $Name -Repository $Repository
            if ($Version -notin $availableVersions) {
                $ErrorActionPreference = 'Continue'
                Write-Error "Version '$Version' was not found for module '$Name' in repository '$Repository'."
                return
            }
        } catch {
            $ErrorActionPreference = 'Continue'
            Write-Error "Failed to validate version '$Version' for '$Name': $_"
            return
        }
    }

    if ($PSCmdlet.ShouldProcess("$Name v$installVersion", "Install")) {
        if (-not $Force -and -not $WhatIfPreference) {
            $confirmed = Show-InstallConfirmation -ModuleInfo $info -Version $installVersion -Scope $Scope
            if (-not $confirmed) {
                Write-Host "Installation cancelled."
                return
            }
        }

        try {
            Write-Host "Installing $Name v$installVersion..."
            $installParams = @{
                Name = $Name
                Scope = $Scope
                Repository = $Repository
                Force = $Force
            }

            if ($Version) {
                $installParams.Version = $installVersion
            }

            Invoke-ProviderInstall @installParams
            Write-Host "Successfully installed $Name."
        } catch {
            $ErrorActionPreference = 'Continue'
            Write-Error "Failed to install '$Name': $_"
        }
    }
}