Public/Import-OriAzBopPsd.ps1

<#
.SYNOPSIS
    Install PowerShell module from online gallery based on psd1 file
    It returns dependency tree
 
.DESCRIPTION
    Install PowerShell module from online gallery based on psd1 file
    It returns dependency tree
 
.PARAMETER DevOpsAccount
    The name of the dev ops account. Default value is 'oriflame'
 
.PARAMETER RegisterPsRepoFeedList
    Powershell Repository feed to register if needed
     
.PARAMETER RegisterNugetRepoFeedList
    Nuget Repository feed to register if needed
 
.PARAMETER SkipInstallCredProvider
    When is set Installation of Credential provider will be skipped.
 
.PARAMETER Repository
    Repository feed to register if needed for getting powershell modules.
 
.PARAMETER Path
    Path to psd1 file
     
.PARAMETER Credential
    Repository Credential if needed
 
.PARAMETER SkipImportType
    When is 'No' module will be loaded.
    When is 'SkipAllImports' no module will be imported.
    When is 'ImportRequiredButSkipTheModule' all required modules by dependecies will be loaded.
 
.PARAMETER Prefix
    When is set the Prefix is used while the Import-Module function as switch parameter
 
.PARAMETER SleepInSec
    Sleep time in sec between test if the module is ready to import.
 
.PARAMETER MaxRetry
    Max retry while waiting to import module
 
.PARAMETER Proxy
    Use it when is required to use proxy while accessing the repository
 
.PARAMETER ProxyCredential
    Use it when is required to use proxy with credential
 
.EXAMPLE
$password = ConvertTo-SecureString 'xbchuuuuhaaaatest' -AsPlainText -Force
$RepositoryCredential = New-Object System.Management.Automation.PSCredential 'feafeafae@mydomain.net',$password
Import-OriAzBopPsd `
-Path $(Build.SourcesDirectory)\src\$(Build.Repository.Name).psd1 `
-Credential $RepositoryCredential
 
.EXAMPLE
$password = ConvertTo-SecureString 'xbchuuuuhaaaatest' -AsPlainText -Force
$RepositoryCredential = New-Object System.Management.Automation.PSCredential 'feafeafae@mydomain.net',$password
Import-OriAzBopPsd `
-Path $(Build.SourcesDirectory)\src\$(Build.Repository.Name).psd1 `
-Credential $RepositoryCredential `
-Proxy 'http://myproxy:8080'
 
#>

function Import-OriAzBopPsd {
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingInvokeExpression', '', Justification = "There's required use the recomanded code.")]
    [CmdLetBinding()]
    [OutputType([PSCustomObject])]
    param (
        [Parameter(Mandatory = $false, HelpMessage = "The name of the dev ops account")]
        [String] $DevOpsAccount = $Script:VstsAccount,

        [Parameter(Mandatory = $false, HelpMessage = "Powershell Repository feed to register if needed")]
        [String[]] $RegisterPsRepoFeedList = @('PackageManagementFeed'),

        [Parameter(Mandatory = $false, HelpMessage = "Nuget Repository feed to register if needed")]
        [String[]] $RegisterNugetRepoFeedList = @('DeploymentPackages'),

        [Parameter(Mandatory = $false, HelpMessage = "Repository feed to register if needed for getting powershell modules")]
        [String] $Repository = 'PackageManagementFeed',

        [Parameter(Mandatory = $true, HelpMessage = "Path to psd1 file")]
        [ValidateScript( { Test-Path $_ })]
        [string] $Path,

        [Parameter(Mandatory = $false, HelpMessage = "Repository Credential if needed")]
        [PSCredential] $Credential = $null,

        [Parameter(Mandatory = $false, HelpMessage = "When is 'No' module will be loaded. When is 'SkipAllImports' no module will be imported. When is 'ImportRequiredButSkipTheModule' all required modules by dependecies will be loaded.")]
        [ValidateSet("No", "SkipAllImports", "ImportRequiredButSkipTheModule")]
        [string] $SkipImportType = "No",

        [Parameter(Mandatory = $false, HelpMessage = "When is set Installation of Credential provider will be skipped.")]
        [switch] $SkipInstallCredProvider,

        [Parameter(Mandatory = $False, HelpMessage = "When is set the Prefix is used while the Import-Module function as switch parameter")]
        [String] $Prefix,

        [Parameter(Mandatory = $false, HelpMessage = "Use it when is required to use proxy while accessing the repository")]
        [Uri] $Proxy = $null,
    
        [Parameter(Mandatory = $false, HelpMessage = "Use it when is required to use proxy with credential")]
        [PSCredential] $ProxyCredential = $null,

        [Parameter(Mandatory = $False, HelpMessage = "Sleep time in sec between test if the module is ready to import.")]
        [int] $SleepInSec = 10,

        [Parameter(Mandatory = $False, HelpMessage = "Max retry")]
        [int] $MaxRetry = 20
    )
    $ErrorActionPreference = 'Stop'
    Write-Verbose -Message ("[ START: {0}:{1} (v.{2}) ]" -f $Local:MyInvocation.MyCommand.Source, $Local:MyInvocation.MyCommand.Name, $Local:MyInvocation.MyCommand.Version)
    foreach ($arg in $PSBoundParameters.GetEnumerator()) {
        if ([string]::IsNullOrEmpty($arg.Value)) {
            Write-Debug -Message ("[null] {0}: {1}" -f $arg.Key, $arg.Value) -ErrorAction SilentlyContinue 
        }
        else {
            Write-Debug -Message ("[{2}] {0}: {1}" -f $arg.Key, $arg.Value, $arg.Value.GetType().Name) -ErrorAction SilentlyContinue 
        }
    }


    # Swich Default protol security to TLS12
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    # Fix credential provider
    if (-not($SkipInstallCredProvider.IsPresent)) {
        Invoke-OriAzExrExceptionRetry `
            -ListedExceptions @('*') `
            -MaxRetry 60 `
            -SleepTimeInSec 60 `
            -ScriptBlockToRun {

            [hashtable] $WebRequestParam = @{
                Uri             = "https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.ps1"
                UseBasicParsing = $true
            }

            if (![string]::IsNullOrEmpty($Proxy)) {
                $WebRequestParam += @{ Proxy = $Proxy }
            }
            if (![string]::IsNullOrEmpty($ProxyCredential)) {
                $WebRequestParam += @{ ProxyCredential = $ProxyCredential }
            }

            Invoke-WebRequest @WebRequestParam | Invoke-Expression 6> $null
        }
    }
    
    [bool] $SkipImportRequired = $false
    if ($SkipImportType -eq 'SkipAllImports') {
        $SkipImportRequired = $true
    }
    
    Install-OriAzBopPrerequisite `
        -Name PowerShellGet `
        -MinimumVersion 2.2.5 `
        -SkipImport:$SkipImportRequired `
        -Proxy $Proxy `
        -ProxyCredential $ProxyCredential `
        -AllowClobber `
        -SkipPublisherCheck
    
    Install-OriAzBopPrerequisite `
        -Name PackageManagement `
        -MinimumVersion 1.4.7 `
        -SkipImport:$SkipImportRequired `
        -Proxy $Proxy `
        -ProxyCredential $ProxyCredential `
        -AllowClobber `
        -SkipPublisherCheck

    # Required module needs to be installed and imported
    Register-OriAzBopRepository `
        -DevOpsAccount $DevOpsAccount `
        -RepositoryCredential $Credential `
        -PsProjectName $RegisterPsRepoFeedList `
        -NugetProjectName $RegisterNugetRepoFeedList `
        -SkipPrompt:$true `
        -Proxy $Proxy `
        -ProxyCredential $ProxyCredential `
        -Verbose:$VerbosePreference `
        -Debug:$DebugPreference 

    [PSCustomObject] $DependencyMap = Invoke-ResolveDependency `
        -InstalledLocation $Path `
        -Credential $Credential `
        -Repository $Repository `
        -SkipImport:$SkipImportRequired `
        -Proxy $Proxy `
        -ProxyCredential $ProxyCredential `
        -Verbose:$VerbosePreference `
        -Debug:$DebugPreference
       
    Write-Debug "Re-Import Module Path: $Path"
    # Note: Following import does NOT work.
    # Import-Module -Name $Name -RequiredVersion $RequiredVersion -Verbose
    # Any using of -RequiredVersion skip execution of init.ps1
    # This problem we're bpassing via using Import-Module on installed path of module.
    if ($SkipImportType -ne "No") {
        Write-Debug "Skip of Import-Module. SkipImportType = [$SkipImportType]"
    }
    else {

        Wait-OriAzBopModuleComplete `
            -Path $Path `
            -SleepInSec $SleepInSec `
            -MaxRetry $MaxRetry `
            -Verbose:$VerbosePreference `
            -Debug:$DebugPreference

        $ImportParameter = @{ Name = $Path }

        if (![string]::IsNullOrEmpty($Prefix)) {
            $ImportParameter += @{ Prefix = $Prefix }
        }

        Write-Debug "Import paramters ImportParameter: [$(ConvertTo-Json -InputObject $ImportParameter)]"

        # 2022-10-20 Petr Jezek Commented the parameter -Force
        # It fails not even the the same module is already loaded, but when the assebly is already loaded.
        # The exception "Assembly with same name is already loaded" is no even possible catch into "try {} catch {}" block of code.
        Import-Module @ImportParameter `
            -Verbose:$VerbosePreference `
            -Debug:$DebugPreference `


    }

    Write-Verbose -Message ("[ END: {0} ]" -f $Local:MyInvocation.MyCommand.Name)
    return $DependencyMap
}