pf-loader.ps1

$Script:ignoredDepencies = @('smbshare', 'Hyper-V', "Pester", "pf-assert")

function Get-ScriptFolder {
    $callStack = Get-PSCallStack | Where-Object ScriptName
    $scriptPath = $callStack[1]
    $scriptPath = Split-Path $scriptPath.ScriptName -Parent
    return $scriptPath
}

function Register-PSRepository_Local {
    #Set-PSRepository -name PsGallery -InstallationPolicy Trusted
    $global:PSRepositoryLocal = 'LocalRepo'
    if (-not (Get-PSRepository -Name $PSRepositoryLocal -ErrorAction SilentlyContinue)) {
        $PSRepo = 'C:\code\PSRepository'
        mkdir $PSRepo -Force
        Register-PSRepository -Name $PSRepositoryLocal -SourceLocation $PSRepo `
            -PublishLocation $PSRepo -InstallationPolicy Trusted
    }
}  

function Get-ScriptList($path) {
    if (-not $path) {
        $path = Get-ScriptFolder
    }
    $result = Get-ChildItem -Path $path -Recurse -Include "*.ps1" |
         Sort-Object FullName
    return $result
}

function Uninstall-Module_WhenDuplicated {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline=$true)]
        $Module,
        [switch]$PassThru
    )
    process {
       $mm = Get-module $Module.Name -ListAvailable 
       if ( $mm -and -not $mm.Path.StartsWith($Module.ModuleBase)) {
           Uninstall-Module $Module.Name -Force -Verbose
       }
       if ($PassThru) {
           return $Module
       }
    }
}

function Import-Module_Reload {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline=$true)]
        $Module
    )
    begin {
        $modulesToIgnore = (New-Object System.Collections.Generic.HashSet[string])
    }
    process {
        if ($Module) {
            if ($Module.Name -notin $modulesToIgnore) {
                if (get-module $Module.Name -ErrorAction SilentlyContinue ) {
                    Write-Host "Removing $($Module.Name)"
                    remove-module $Module.Name -Force -Confirm:$false 
                }
            }
            Import-Module_Smart -name $Module.Name -Global -modulesToIgnore $modulesToIgnore
        }
    }
} 

function Get-Module_Dependencies {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline=$true)]
        $Module
    )
    process {
        function GetDepenciesFromPs1 {
            $modulePath =  Join-Path -Path $Module.ModuleBase -ChildPath ($Module.Name + ".psm1") 
            if (Test-Path $modulePath) {
                $modulePsd1 =  Join-Path -Path $Module.ModuleBase -ChildPath ($Module.Name + ".psd1") 
                $psd1 = Import-PowerShellDataFile -Path $modulePsd1 -ErrorAction SilentlyContinue
                if ($psd1.PrivateData.PSData.ExternalModuleDependencies) {
                    $psd1.PrivateData.PSData.ExternalModuleDependencies | ForEach-Object { 
                        Write-Output $_ 
                    }
                } 
            }
        }

        function GetDepenciesFromMetadata {
            $GetMetadataCmd = "Get-Metadata_" + $Module.Name 
            $GetMetadataCmd = Get-Function_ValidName -name $GetMetadataCmd
            if (Get-Command $GetMetadataCmd -ErrorAction SilentlyContinue) {
                $metadata = Invoke-Expression  $GetMetadataCmd
                $metadata.ExternalModuleDependencies
            }
        }

        GetDepenciesFromPs1
        GetDepenciesFromMetadata
    }
}
function Get-Module_Dependencies:::example {
    get-module pf-loader | Get-Module_Dependencies
}

function Import-Module_Smart {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline=$true)]
        $name,
        [switch]$Global,
        [System.Collections.Generic.HashSet[string]]$modulesToIgnore = (New-Object System.Collections.Generic.HashSet[string])
    )
    process {
        if ($name -in $modulesToIgnore) {
            return
        }
        $modulesToIgnore.Add($name) | Out-Null
        $module = get-module $name -ErrorAction SilentlyContinue
        if (-not $module ) {
            Write-Host "Import-Module $name"
            $moduleRoot = Get-ChildItem -Filter "$name.psm1" -Recurse | Select-Object -First 1
            if ( $moduleRoot ) {
                $moduleFolder = Split-Path $moduleRoot -Parent
                $module = Import-Module $moduleFolder -Global:($Global.IsPresent) -Force -PassThru
            }
    
            if (-not $module) {
                $module = Get-Module -name $name -ListAvailable
                if (-not $module) {
                    Install-Module -Name $name -Repository PsGallery -Confirm:$false -Force -AllowClobber -Scope CurrentUser
                }
                $module = Import-Module -Name $name -PassThru -Global:($Global.IsPresent)
            }
        }

        $Module | Import-Module_Depedencies -Global:($Global.IsPresent) -modulesToIgnore $modulesToIgnore
    }
}

function Import-Module_Depedencies {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline=$true)]
        $module,
        [switch]$Global,
        [System.Collections.Generic.HashSet[string]]$modulesToIgnore = (New-Object System.Collections.Generic.HashSet[string])
    )
    process {
        $dependencies = $Module | Get-Module_Dependencies
        if (-not $dependencies) { return }
        $dependencies = $dependencies | Where-Object { $_ -notin $ignoredDepencies}
        $dependencies | Import-Module_Smart -Global:($Global.IsPresent) -modulesToIgnore $modulesToIgnore
    }
}

function Get-Modules_Local {
    $folders = Get-ChildItem -file -Recurse -Filter *.* -include @('*.psd1', '*.psm1', "*.ps1")
        | Where-Object { $_.FullName -notlike "*pending*" }      
        | Where-Object { $_.BaseName -eq $_.Directory.BaseName } 
        | Select-Object DirectoryName -Unique
        
    $folders.DirectoryName | 
        ForEach-Object { [PSCustomObject]@{ 
            Name = (Split-Path $_ -LeafBase)
            DirectoryName = $_
            ModuleBase = $_ }        
        }
}

function Import-Script_AsModule {
    [CmdletBinding()]
    param (
        $ScriptName,
        [string[]]$WhenNotDefined, 
        $RequiredVersion, 
        [Switch]$Global,
        [Switch]$PassThru
    )
    if ($WhenNotDefined) {
        foreach ($item in $WhenNotDefined) {
            $cmd = Get-Command -Name $item -ErrorAction SilentlyContinue 
            if ( $cmd ){
                if ($PassThru) {
                    return $cmd.Module
                }
                return
            }
        }
    }
    $installResult = Install-Script -Name $ScriptName -PassThru -Force -RequiredVersion $RequiredVersion
    $scriptPath = Join-Path $installResult.InstalledLocation -ChildPath "$ScriptName.ps1" 
    $scriptContent = Get-Content -Raw -Path $scriptPath
    $sb = [scriptblock]::Create($scriptContent)
    $mm = New-Module -ScriptBlock $sb -Name "ImportScript_$ScriptName"
    $mm | Import-Module -Global:($Global.IsPresent) -Force -PassThru:($PassThru.IsPresent)
}

function Import-PSSnapin ($name) {
    if (-not (Get-PSSnapin | Where-Object Name -eq $name))     {
        if ( Get-PSSnapin  -Registered | Where-Object Name -eq $name ) {
            Add-PsSnapin $name 
        }
        else {
            Write-Warning "SNAPIN not available : '$name'"
        }
    }
}
function Import-PSSnapin:::Example {
    Import-PSSnapin Microsoft.SharePoint.PowerShell
}

function Get-Function_RestricterChars() {
    return @('(', ')', '{', '}', '[', ']', '&', '-', '/', '\',
             '$', '^', ';', ':', '"', '''', '<', '>', '|', '?',
              '@', '`', '*', '%', '+', '=', '~')
}

function Get-Function_ValidName([string]$name) {
    if ( [string]::IsNullOrEmpty($name)) { return $name }
    $first = $name.IndexOf('-') + 1;
    $verb  = $name.Substring(0,$first)
    $noun  = $name.Substring($first)
    foreach ($char in Get-Function_RestricterChars) {
        $noun = $noun.Replace($char,'_')
    }
    return $verb + $noun 
}
function Get-Function_ValidName:::Test {
    Get-Function_ValidName -name "" | should -be ""
    Get-Function_ValidName -name "Get-Function>ValidName" | should -be "Get-Function_ValidName"
    Get-Function_ValidName -name "Get<Function>ValidName" | should -be "Get_Function_ValidName"
}