Functions/Import-BT_Module.ps1

<#
.SYNOPSIS
    This function installs and imports the correct edition (Beta/Prod) of a BitTitan.Runbooks module.
#>

function Import-BT_Module {
    [CmdletBinding(PositionalBinding=$true, DefaultParameterSetName="performModuleVersionCheckNotSpecified")]
    param (
        # The name of the module to import.
        [Parameter(Mandatory=$true, ParameterSetName="performModuleVersionCheckSpecified", Position=0)]
        [Parameter(Mandatory=$true, ParameterSetName="performModuleVersionCheckNotSpecified", Position=0)]
        [ValidateNotNullOrEmpty()]
        [String]$moduleName,

        # Select whether to perform a module version check when installing a module.
        [Parameter(Mandatory=$false, ParameterSetName="performModuleVersionCheckSpecified")]
        [Switch]$performModuleVersionCheck,

        # Select whether to suppress information messages.
        [Parameter(Mandatory=$false, ParameterSetName="performModuleVersionCheckSpecified")]
        [Parameter(Mandatory=$false, ParameterSetName="performModuleVersionCheckNotSpecified")]
        [ValidateNotNull()]
        [Switch]$quiet
    )

    # Set the default value for $performModuleVersionCheck
    if ($PSCmdlet.ParameterSetName -eq "performModuleVersionCheckNotSpecified") {
        # Use the global default parameter value if it is set
        if ($null -ne $Global:PSDefaultParameterValues["Import-BT_Module:PerformModuleVersionCheck"]) {
            $performModuleVersionCheck = $Global:PSDefaultParameterValues["Import-BT_Module:PerformModuleVersionCheck"]
        }
        else {
            $performModuleVersionCheck = [Switch]::Present
        }
    }

    # Retrieve the BitTitan Runbook Environment settings
    if ($Global:PSDefaultParameterValues.ContainsKey("*-BT_*:Environment")) {
        $environment = $Global:PSDefaultParameterValues["*-BT_*:Environment"]
    }
    else {
        $environment = "Beta"
    }
    if ($Global:PSDefaultParameterValues.ContainsKey("*-BT_*:IsRunningOnLocalMachine")) {
        $isRunningOnLocalMachine = $Global:PSDefaultParameterValues["*-BT_*:IsRunningOnLocalMachine"]
    }
    else {
        $isRunningOnLocalMachine = $false
    }

    # Import based on the environment and whether it is running on the local machine
    try {
        if ($isRunningOnLocalMachine) {
            # Import the module
            Import-Module -Name $moduleName -Force -Global

            # Import any nested modules
            $nestedModuleFolderPath = "$((Get-Module -ListAvailable $moduleName)[0].ModuleBase)\NestedModules"
            if (Test-Path -Path $nestedModuleFolderPath -ErrorAction SilentlyContinue) {
                foreach ($nestedModule in (Get-ChildItem "$($nestedModuleFolderPath)\*" -Directory)) {
                    Import-Module -Name $nestedModule.FullName -Force -Global
                }
            }

            # Verify imported module
            $importedModule = Get-Module -Name $moduleName
            if ($importedModule) {
                if (!$quiet) {
                    Write-Information "Imported '$($moduleName)' ($(if ($environment -eq 'BT') { 'Prod' } else { 'Beta' })) from the local machine."
                }
            }
            else {
                throw "Failed to import '$($moduleName)' ($(if ($environment -eq 'BT') { 'Prod' } else { 'Beta' })) from the local machine."
            }
        }

        # Running on the platform
        else {
            $userModulesPath = "$($env:USERPROFILE)\Documents\WindowsPowerShell\Modules"

            # Running on the Prod platform
            if ($environment -eq "BT") {
                # Retrieve the currently installed modules
                $currentlyInstalledModules = Get-ChildItem $userModulesPath -Directory | Where-Object { $_.FullName -like "*$($moduleName)*" }

                # Track the current module version
                $moduleVersion = ""

                # The module is currently installed
                if ($currentlyInstalledModules) {
                    # Only check the module version if directed
                    if ($performModuleVersionCheck) {
                        # Retrieve the versions of the currently installed module and the latest module
                        $installedModuleVersion = [Version](Get-ChildItem "$($userModulesPath)\$($moduleName)" -Directory | Sort-Object -Property { [Version]$_.Name } -Descending)[0].Name
                        $latestModuleVersion = [Version](Find-Module $moduleName).Version
                        $moduleVersion = $latestModuleVersion

                        # The currently installed module is not the latest version, install the latest version
                        if ($installedModuleVersion -lt $latestModuleVersion) {
                            Install-Module -Name $moduleName -Scope CurrentUser -AllowClobber -Force
                            if (!$quiet) {
                                # Retrieve the version which was just installed
                                $newlyInstalledModuleVersion = (Get-ChildItem "$($userModulesPath)\$($moduleName)" -Directory | Sort-Object -Property { [Version]$_.Name } -Descending)[0].Name
                                Write-Information "Installed '$($moduleName)' version $($newlyInstalledModuleVersion) to replace version $($installedModuleVersion) from the PowerShell Gallery."
                            }
                            $moduleVersion = $newlyInstalledModuleVersion
                        }
                    }
                    else {
                        if (!$quiet) {
                            Write-Warning "Skipping the module version check for '$($moduleName)', and importing the currently installed version. The imported module may not be up to date."
                        }
                    }
                }

                # The module is not currently installed, install the module
                else {
                    Install-Module -Name $moduleName -Scope CurrentUser -AllowClobber -Force
                    if (!$quiet) {
                        # Retrieve the version which was installed
                        # Retrieve the highest version currently installed if there is more than one present
                        $installedModuleVersion = (Get-ChildItem "$($userModulesPath)\$($moduleName)" -Directory | Sort-Object -Property { [Version]$_.Name } -Descending)[0].Name
                        Write-Information "Installed '$($moduleName)' version $($installedModuleVersion) from the PowerShell Gallery."
                    }
                    $moduleVersion = $installedModuleVersion
                }

                # Import the module
                Import-Module -Name "$($userModulesPath)\$($moduleName)" -Force -Global

                # Import any nested modules
                $nestedModuleFolderPath = "$($userModulesPath)\$($moduleName)\$($moduleVersion)\NestedModules"
                if (Test-Path -Path $nestedModuleFolderPath -ErrorAction SilentlyContinue) {
                    foreach ($nestedModule in (Get-ChildItem "$($nestedModuleFolderPath)\*" -Directory)) {
                        Import-Module -Name $nestedModule.FullName -Force -Global
                    }
                }

                # Verify that the module has been imported
                $importedModule = Get-Module -Name $moduleName
                if ($importedModule) {
                    if (!$quiet) {
                        Write-Information "Imported '$($moduleName)' version $($importedModule.Version) from the local machine."
                    }
                }
                else {
                    throw "Failed to import '$($moduleName)' from the local machine."
                }
            }

            # Running on the Beta platform
            else {
                # Retrieve the currently installed modules
                $currentlyInstalledModules = Get-ChildItem $userModulesPath -Directory | Where-Object { $_.FullName -like "*$($moduleName)*" }

                # Track the current module version
                $moduleVersion = ""

                # The module is already installed
                if ($currentlyInstalledModules) {
                    # Only check the module version if directed
                    if ($performModuleVersionCheck) {
                        # Retrieve the versions of the currently installed module and the latest module
                        $installedModuleVersion = [Version](Get-ChildItem "$($userModulesPath)\$($moduleName)" -Directory | Sort-Object -Property { [Version]$_.Name } -Descending)[0].Name
                        $latestModuleVersion = [Version](Find-Module $moduleName).Version
                        $moduleVersion = $latestModuleVersion

                        # The currently installed module is not the latest version, install the latest version
                        if ($installedModuleVersion -lt $latestModuleVersion) {
                            Install-Module -Name "$($moduleName).Beta" -Scope CurrentUser -AllowClobber -Force

                            # Remove the ".Beta" from the names of the Beta module files
                            $item = Get-Item -Path "$($userModulesPath)\$($moduleName).Beta\*\$($moduleName).Beta.psd1"
                            Move-Item -Path $item.FullName -Destination ($item.FullName -Replace "$($moduleName).Beta.psd1", "$($moduleName).psd1" ) -Force
                            $item = Get-Item -Path "$($userModulesPath)\$($moduleName).Beta\*\$($moduleName).Beta.psm1"
                            Move-Item -Path $item.FullName -Destination ($item.FullName -Replace "$($moduleName).Beta.psm1", "$($moduleName).psm1" ) -Force

                            # Remove the ".Beta" from the name of the Beta module folder
                            Move-Item -Path "$($userModulesPath)\$($moduleName).Beta\" -Destination "$($userModulesPath)\$($moduleName)\" -Force
                            if (!$quiet) {
                                # Retrieve the version which was just installed
                                $newlyInstalledModuleVersion = (Get-ChildItem "$($userModulesPath)\$($moduleName)" -Directory | Sort-Object -Property { [Version]$_.Name } -Descending)[0].Name
                                Write-Information "Installed '$($moduleName).Beta' version $($newlyInstalledModuleVersion) to replace version $($installedModuleVersion) from the PowerShell Gallery as '$($moduleName)'."
                            }
                            $moduleVersion = $newlyInstalledModuleVersion
                        }
                    }
                    else {
                        if (!$quiet) {
                            Write-Warning "Skipping the module version check for '$($moduleName)', and importing the currently installed version. The imported module may not be up to date."
                        }
                    }
                }

                # The module is not currently installed, install the module
                else {
                    Install-Module -Name "$($moduleName).Beta" -Scope CurrentUser -AllowClobber -Force

                    # Remove the ".Beta" from the names of the Beta module files
                    $item = Get-Item -Path "$($userModulesPath)\$($moduleName).Beta\*\$($moduleName).Beta.psd1"
                    Move-Item -Path $item.FullName -Destination ($item.FullName -Replace "$($moduleName).Beta.psd1", "$($moduleName).psd1" ) -Force
                    $item = Get-Item -Path "$($userModulesPath)\$($moduleName).Beta\*\$($moduleName).Beta.psm1"
                    Move-Item -Path $item.FullName -Destination ($item.FullName -Replace "$($moduleName).Beta.psm1", "$($moduleName).psm1" ) -Force

                    # Remove the ".Beta" from the name of the Beta module folder
                    Move-Item -Path "$($userModulesPath)\$($moduleName).Beta\" -Destination "$($userModulesPath)\$($moduleName)\" -Force
                    if (!$quiet) {
                        # Retrieve the version which was just installed
                        $newlyInstalledModuleVersion = (Get-ChildItem "$($userModulesPath)\$($moduleName)" -Directory | Sort-Object -Property { [Version]$_.Name } -Descending)[0].Name
                        Write-Information "Installed '$($moduleName).Beta' version $($newlyInstalledModuleVersion) from the PowerShell Gallery as '$($moduleName)'."
                    }
                    $moduleVersion = $newlyInstalledModuleVersion
                }

                # Import the Beta module
                Import-Module -Name "$($userModulesPath)\$($moduleName)" -Force -Global

                # Import any nested modules
                $nestedModuleFolderPath = "$($userModulesPath)\$($moduleName)\$($moduleVersion)\NestedModules"
                if (Test-Path -Path $nestedModuleFolderPath -ErrorAction SilentlyContinue) {
                    foreach ($nestedModule in (Get-ChildItem "$($nestedModuleFolderPath)\*" -Directory)) {
                        Import-Module -Name $nestedModule.FullName -Force -Global
                    }
                }

                # Verify imported module
                $importedModule = Get-Module -Name $moduleName
                if ($importedModule) {
                    if (!$quiet) {
                        Write-Information "Imported '$($moduleName)' (Beta) version $($importedModule.Version) from the local machine."
                    }
                }
                else {
                    throw "Failed to import '$($moduleName)' (Beta) from the local machine."
                }
            }
        }
    }
    catch {
        Write-Error "Exception occurred on line $($_.InvocationInfo.ScriptLineNumber): `r`n$($_.Exception.Message)"
    }
}