src/Install-CciModule.ps1

function Install-CciModule {
<#
.SYNOPSIS
    Install a CCI module from a tenant feed.
.PARAMETER Name
    Module name (required). Wildcards are not supported by Install-PSResource.
.PARAMETER Version
    Optional version constraint passed to Install-PSResource.
.PARAMETER Tenant
    Optional. Tenant feed to install from. If omitted, uses defaultFeed from
    Get-CciGetConfig.
.PARAMETER Scope
    CurrentUser (default) or AllUsers.
.EXAMPLE
    Install-CciModule Cci.Citrix
.EXAMPLE
    Install-CciModule Cci.Common -Tenant ccidev -Version 0.1.0
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory, Position = 0)]
        [string]$Name,
        [string]$Version,
        [string]$Tenant,
        [ValidateSet('CurrentUser','AllUsers')]
        [string]$Scope = 'CurrentUser',
        [switch]$Reinstall,
        [switch]$TrustRepository,
        # Set by Invoke-CciGetBootstrap: it narrates the whole flow itself, so
        # the per-step hint would just be noise in the middle of it.
        [switch]$NoGuidance
    )

    if (-not $Tenant) { $Tenant = (Get-CciGetConfig).defaultFeed }
    $feed     = (_Resolve-CciGetFeed -Tenant $Tenant)[0]
    $repoName = _Get-CciGetRepositoryName -FeedName $feed.name

    # v2 feeds serve tenant-prefixed names; let consumers say 'vmware' or 'Cci.Vmware'.
    $resolved = _Resolve-CciModuleName -Name $Name -Feed $feed
    if ($resolved -ne $Name) { Write-Host "cciget: '$Name' -> '$resolved' on feed '$($feed.name)'." }
    $Name = $resolved

    if (-not $Script:CciGetSource) {
        Connect-CciGet -Tenant $feed.name | Out-Null
    }

    # Connect-CciGet resolves ONE source per session. 'store' is the
    # machine-builder path: Azure RBAC only, no Azure DevOps entitlement.
    if ($Script:CciGetSource -eq 'store') {
        $blobCtx = _Connect-CciBlobStore -Feed $feed
        if (-not $blobCtx) { throw "cciget: the tenant distribution store is not reachable for '$($feed.name)'." }
        $index = _Get-CciBlobModuleIndex -Feed $feed -Context $blobCtx
        if (-not $index) { throw "cciget: no module index in the tenant distribution store for '$($feed.name)'." }
        _Install-CciModuleFromBlob -Name $Name -Feed $feed -Context $blobCtx -Index $index `
            -Version $Version -Scope $Scope -Reinstall:$Reinstall
        if (-not $NoGuidance) { _Write-CciInstalledNextStep -Name $Name }
        return
    }

    if (-not (Get-PSResourceRepository -Name $repoName -ErrorAction SilentlyContinue)) {
        Connect-CciGet -Tenant $feed.name | Out-Null
    }

    $params = @{
        Name       = $Name
        Repository = $repoName
        Scope      = $Scope
    }
    if ($Version)         { $params.Version         = $Version }
    if ($Reinstall)       { $params.Reinstall       = $true }
    if ($TrustRepository) { $params.TrustRepository = $true }

    Install-PSResource @params
    if (-not $NoGuidance) { _Write-CciInstalledNextStep -Name $Name }
}