Public/Miscellaneous/Import-MyModule.ps1

Function Import-MyModule {
    <#
        .SYNOPSIS
            Imports a PowerShell module with enhanced error handling and functionality.

        .DESCRIPTION
            This function imports a specified PowerShell module with additional
            error handling, verbose output, and advanced features. It checks if the module
            is available, handles different versions, and provides options for forced imports
            and minimum version requirements. It also accepts additional arguments for maximum flexibility.

        .PARAMETER Name
            The name of the module to import.

        .PARAMETER MinimumVersion
            The minimum version of the module to import. If specified, the function will
            import the newest version that meets this criteria.

        .PARAMETER RequiredVersion
            The exact version of the module to import. If specified, only this version
            will be imported.

        .PARAMETER Force
            Forces a module to be imported even if it's already imported.

        .PARAMETER Global
            Imports the module into the global session state.

        .PARAMETER PassThru
            Returns the imported module object.

        .PARAMETER Prefix
            Adds a prefix to the imported module's cmdlets and other items.

        .PARAMETER DisableNameChecking
            Suppresses the message that warns you when you import a cmdlet or function
            whose name includes an unapproved verb or a prohibited character.

        .PARAMETER NoClobber
            Prevents importing commands that would hide or overwrite existing commands.

        .PARAMETER Scope
            Defines the scope of the import, either 'Global' or 'Local'.

        .PARAMETER SkipEditionCheck
            Skips the edition check if importing modules designed for Windows PowerShell in PowerShell Core.

        .PARAMETER UseWindowsPowerShell
            Forces the module to be imported using Windows PowerShell instead of PowerShell Core.


        .EXAMPLE
            Import-MyModule -Name ActiveDirectory
            Tries to import the ActiveDirectory module, providing verbose output
            and handling errors if the module is not available.

        .EXAMPLE
            Import-MyModule -Name AzureAD -MinimumVersion 2.0.0 -Force -Verbose
            Imports the AzureAD module with a minimum version of 2.0.0, forcing the import
            even if it's already loaded, and provides verbose output.

        .NOTES
            Used Functions:
                Name ║ Module/Namespace
                ════════════════════════════════════════╬══════════════════════════════
                Get-Module ║ Microsoft.PowerShell.Core
                Import-Module ║ Microsoft.PowerShell.Core
                Write-Verbose ║ Microsoft.PowerShell.Utility
                Write-Error ║ Microsoft.PowerShell.Utility
                Get-FunctionDisplay ║ EguibarIT

        .NOTES
            Version: 2.4
            DateModified: 25/Apr/2025
            LastModifiedBy: Vicente Rodriguez Eguibar
                vicente@eguibar.com
                Eguibar IT
                http://www.eguibarit.com
    #>


    [CmdletBinding(
        SupportsShouldProcess = $true,
        ConfirmImpact = 'low'
    )]
    [OutputType([System.Management.Automation.PSModuleInfo])]

    Param (

        # Param1 STRING for the Module Name
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Name of the module to be imported',
            Position = 0)]
        [ValidateNotNullOrEmpty()]
        [Alias('Module', 'ModuleName')]
        [string]
        $Name,

        [Parameter(Mandatory = $false)]
        [switch]
        $Force,

        [Parameter(Mandatory = $false)]
        [switch]
        $Global,

        [Parameter(Mandatory = $false)]
        [System.Version]
        $MinimumVersion,

        [Parameter(Mandatory = $false)]
        [System.Version]
        $RequiredVersion,

        [Parameter(Mandatory = $false)]
        [switch]
        $PassThru,

        [Parameter(Mandatory = $false)]
        [string]
        $Prefix,

        [Parameter(Mandatory = $false)]
        [switch]
        $DisableNameChecking,

        [Parameter(Mandatory = $false)]
        [switch]
        $NoClobber,

        [Parameter(Mandatory = $false)]
        [ValidateSet('Global', 'Local')]
        [string]
        $Scope,

        [Parameter(Mandatory = $false)]
        [switch]
        $SkipEditionCheck,

        [Parameter(Mandatory = $false)]
        [switch]
        $UseWindowsPowerShell
    )

    Begin {
        # Set strict mode
        Set-StrictMode -Version Latest

        # Initialize logging
        if ($null -ne $Variables -and
            $null -ne $Variables.HeaderDelegation) {

            $txt = ($Variables.HeaderDelegation -f
                (Get-Date).ToShortDateString(),
                $MyInvocation.Mycommand,
                (Get-FunctionDisplay -HashTable $PsBoundParameters -Verbose:$False)
            )
            Write-Verbose -Message $txt
        } #end If

        ##############################
        # Variables Definition

        # Store original VerbosePreference to restore it later
        [string]$OriginalVerbosePreference = $VerbosePreference

        # Define function name for consistent logging
        [string]$FunctionName = $MyInvocation.MyCommand.Name

        # Initialize module tracking variables
        [System.Management.Automation.PSModuleInfo]$AvailableModule = $null
        [System.Management.Automation.PSModuleInfo]$ImportedModule = $null

        # Create import parameters hashtable
        [hashtable]$ImportParams = @{
            Name        = $Name
            ErrorAction = 'Stop'
        }

        # Add optional parameters based on what was passed to the function
        if ($Force) {
            $ImportParams['Force'] = $true
        } #end If

        if ($Global) {
            $ImportParams['Global'] = $true
        } #end If

        if ($PSBoundParameters.ContainsKey('MinimumVersion')) {
            $ImportParams['MinimumVersion'] = $MinimumVersion
        } #end If

        if ($PSBoundParameters.ContainsKey('RequiredVersion')) {
            $ImportParams['RequiredVersion'] = $RequiredVersion
        } #end If

        if ($PassThru) {
            $ImportParams['PassThru'] = $true
        } #end If

        if ($PSBoundParameters.ContainsKey('Prefix')) {
            $ImportParams['Prefix'] = $Prefix
        } #end If

        if ($DisableNameChecking) {
            $ImportParams['DisableNameChecking'] = $true
        } #end If

        if ($NoClobber) {
            $ImportParams['NoClobber'] = $true
        } #end If

        # Only add these parameters if running in PowerShell 7+
        if ($PSVersionTable.PSVersion.Major -ge 7) {

            if ($PSBoundParameters.ContainsKey('Scope')) {
                $ImportParams['Scope'] = $Scope
            } #end If

            if ($SkipEditionCheck) {
                $ImportParams['SkipEditionCheck'] = $true
            } #end If

            if ($UseWindowsPowerShell) {
                $ImportParams['UseWindowsPowerShell'] = $true
            } #end If

        } else {

            # Warn if user tries to use these parameters in Windows PowerShell
            if ($PSBoundParameters.ContainsKey('Scope') -or $SkipEditionCheck -or $UseWindowsPowerShell) {

                Write-Warning -Message ('
                    Parameters -Scope, -SkipEditionCheck, and -UseWindowsPowerShell
                    are only supported in PowerShell 7 and above.
                    They will be ignored.'

                )
            } 
        } #end If-else

        # Handle Verbose parameter correctly
        if ($PSBoundParameters.ContainsKey('Verbose')) {
            $ImportParams['Verbose'] = $PSBoundParameters['Verbose']
        } #end If

    } #end Begin

    Process {

        try {

            # First check if the module is available (installed) on the system
            $AvailableModule = Get-Module -Name $Name -ListAvailable -ErrorAction SilentlyContinue -Verbose:$false

            if ($null -eq $AvailableModule) {

                # Special case handling for built-in modules with specific paths
                if ($Name -eq 'GroupPolicy') {

                    $GpPath = 'C:\Windows\system32\WindowsPowerShell\v1.0\Modules\GroupPolicy\GroupPolicy.psd1'

                    if (Test-Path -Path $GpPath) {

                        $ImportParams['Name'] = $GpPath
                        Write-Verbose -Message (
                            '[{0}] Using specific path for GroupPolicy module: {1}' -f
                            $FunctionName, $GpPath
                        )

                    } else {

                        Write-Error -Message (
                            'Module "{0}" is not installed.
                            Please install the module before importing.'
 -f
                            $Name
                        )
                        return

                    } #end If-else

                } elseif ($Name -eq 'ServerManager') {

                    $SmPath = 'C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ServerManager\ServerManager.psd1'

                    if (Test-Path -Path $SmPath) {

                        $ImportParams['Name'] = $SmPath
                        Write-Verbose -Message (
                            '[{0}] Using specific path for ServerManager module: {1}' -f
                            $FunctionName, $SmPath
                        )

                    } else {

                        Write-Error -Message (
                            'Module "{0}" is not installed. Please install the module before importing.' -f
                            $Name
                        )
                        return
                    } #end If-else

                } else {

                    Write-Error -Message (
                        'Module "{0}" is not installed. Please install the module before importing.' -f
                        $Name
                    )
                    return

                } #end If-else

            } else {

                Write-Verbose -Message (
                    '[{0}] Found module {1} installed on the system.' -f
                    $FunctionName, $Name
                )

            } #end If-else

            # Check if the module is already imported
            $ImportedModule = Get-Module -Name $Name -ErrorAction SilentlyContinue -Verbose:$false

            if ($null -ne $ImportedModule -and -not $Force) {

                Write-Verbose -Message (
                    '[{0}] Module {1} is already imported.' -f
                    $FunctionName, $Name
                )

                if ($PassThru) {

                    return $ImportedModule

                } #end If

                return

            } #end If

            # Perform the import
            if ($PSCmdlet.ShouldProcess($Name, 'Import Module')) {

                Write-Verbose -Message ('[{0}] Importing module {1}...' -f $FunctionName, $Name)

                if ($PassThru) {

                    $ImportedModule = Import-Module @ImportParams -PassThru

                    Write-Verbose -Message (
                        '[{0}] Successfully imported module {1}' -f
                        $FunctionName, $Name
                    )
                    return $ImportedModule

                } else {

                    Import-Module @ImportParams

                    Write-Verbose -Message (
                        '[{0}] Successfully imported module {1}' -f
                        $FunctionName, $Name
                    )

                } #end If-else

            } #end If

        } catch {

            Write-Error -Message (
                '[{0}] Error importing module {1}: {2}' -f
                $FunctionName, $Name, $_.Exception.Message
            )

        } #end Try-Catch

    } #end Process

    End {
        # Restore original VerbosePreference
        $VerbosePreference = $OriginalVerbosePreference

        if ($null -ne $Variables -and
            $null -ne $Variables.FooterDelegation) {

            $txt = ($Variables.FooterDelegation -f $MyInvocation.InvocationName,
                'importing module.'
            )
            Write-Verbose -Message $txt

        } #end If

    } #end End
} #end Function Import-MyModule