modules/HomeLab.Core/HomeLab.Core.psm1

<#
.SYNOPSIS
    Core functionality for HomeLab including configuration management, logging, setup, and prerequisites.
.DESCRIPTION
    This module provides the core functionality for HomeLab including configuration
    management, logging, setup, prerequisites, and other essential utilities.
.NOTES
    Author: Jurie Smit
    Date: March 8, 2025
#>


# ===== CRITICAL SECTION: PREVENT INFINITE LOOPS =====
# Save original preferences to restore later
$originalPSModuleAutoLoadingPreference = $PSModuleAutoLoadingPreference
$originalDebugPreference = $DebugPreference
$originalVerbosePreference = $VerbosePreference
$originalErrorActionPreference = $ErrorActionPreference

# Disable automatic module loading to prevent recursive loading
$PSModuleAutoLoadingPreference = 'None'
# Disable debugging which can cause infinite loops
$DebugPreference = 'SilentlyContinue'
# Control verbosity
$VerbosePreference = 'SilentlyContinue'
# Make errors non-terminating
$ErrorActionPreference = 'Continue'

# Create a guard to prevent recursive loading
if ($script:IsLoading) {
    Write-Warning "Module is already loading. Preventing recursive loading."
    # Restore original preferences
    $PSModuleAutoLoadingPreference = $originalPSModuleAutoLoadingPreference
    $DebugPreference = $originalDebugPreference
    $VerbosePreference = $originalVerbosePreference
    $ErrorActionPreference = $originalErrorActionPreference
    return
}
$script:IsLoading = $true

try {
    # Get the module path
    $ModulePath = $PSScriptRoot
    $ModuleName = (Get-Item $PSScriptRoot).BaseName

    # Initialize the global configuration with default values
    if (-not $Global:Config) {
        $Global:Config = @{
            # Default configuration values
            env = "dev"
            loc = "saf"
            project = "homelab"
            location = "southafricanorth"
            LogFile = "$env:USERPROFILE\.homelab\logs\homelab.log"
            ConfigFile = "$env:USERPROFILE\.homelab\config.json"
        }
    }

    # Create log directory if it doesn't exist
    $logDir = Split-Path -Path $Global:Config.LogFile -Parent
    if (-not (Test-Path -Path $logDir)) {
        New-Item -ItemType Directory -Path $logDir -Force | Out-Null
    }

    # Create an array to store public function names
    $PublicFunctionNames = @()

    # Import all private functions first
    $PrivateFunctions = Get-ChildItem -Path "$ModulePath\Private\*.ps1" -Recurse -ErrorAction SilentlyContinue
    foreach ($Function in $PrivateFunctions) {
        try {
            . $Function.FullName
            Write-Verbose "Imported private function: $($Function.BaseName)"
        }
        catch {
            Write-Warning "Failed to import private function $($Function.BaseName): $_"
        }
    }

    # Import all public functions and add to export list
    $PublicFunctions = Get-ChildItem -Path "$ModulePath\Public\*.ps1" -Recurse -ErrorAction SilentlyContinue
    foreach ($Function in $PublicFunctions) {
        try {
            . $Function.FullName
            $PublicFunctionNames += $Function.BaseName
            Write-Verbose "Imported public function: $($Function.BaseName)"
        }
        catch {
            Write-Warning "Failed to import public function $($Function.BaseName): $_"
        }
    }

    # Export all public functions
    Export-ModuleMember -Function $PublicFunctionNames

    # Display functions defined in this module
    Write-Host "Functions defined in this module:" -ForegroundColor Cyan
    Get-Command -Module $ModuleName | ForEach-Object { 
        Write-Host " - $($_.Name)" -ForegroundColor Cyan 
    }
}
finally {
    # ===== CLEANUP SECTION =====
    # Reset module loading guard
    $script:IsLoading = $false
    
    # Restore original preferences
    $PSModuleAutoLoadingPreference = $originalPSModuleAutoLoadingPreference
    $DebugPreference = $originalDebugPreference
    $VerbosePreference = $originalVerbosePreference
    $ErrorActionPreference = $originalErrorActionPreference
}