Public/Import-GatekeeperConfig.ps1

function Import-GatekeeperConfig {
    <#
    .SYNOPSIS
    Loads the Gatekeeper module configuration with multi-level precedence.
 
    .DESCRIPTION
    Imports the Gatekeeper configuration using the Configuration module's precedence
    chain: module defaults, machine-wide settings, enterprise roaming settings, and
    user local settings. The result is cached in module scope so subsequent calls
    return quickly without re-reading disk.
 
    Logging scripts defined in the configuration are parsed and stored in
    $script:GatekeeperLogging. Scripts may be inline scriptblocks, inline PowerShell
    strings, or paths to local .ps1 files. UNC and remote paths are rejected.
 
    .PARAMETER ForceReload
    Clears the module-scope cache and re-reads configuration from disk.
 
    .OUTPUTS
    System.Collections.Hashtable
 
    .EXAMPLE
    Import-GatekeeperConfig
 
    Returns the cached configuration, loading from disk on first call.
 
    .EXAMPLE
    Import-GatekeeperConfig -ForceReload
 
    Discards the cached configuration and reloads from disk.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [switch]
        $ForceReload
    )

    begin {
        if (-not $script:GatekeeperConfiguration) {
            Write-Verbose "Gatekeeper configuration not loaded, importing..."
        }
        if ($ForceReload -and $script:GatekeeperConfiguration) {
            Write-Verbose "Forcing reload of Gatekeeper configuration."
            $script:GatekeeperConfiguration = $null
        }
    }
    process {
        if ($script:GatekeeperConfiguration) {
            Write-Verbose "Using cached Gatekeeper configuration."
        } else {
            Write-Verbose "Loading Gatekeeper configuration from disk."
            $script:GatekeeperConfiguration = Import-Configuration
        }
        # Check if the configuration was imported successfully
        if (-not $script:GatekeeperConfiguration) {
            throw "Failed to import Gatekeeper configuration."
        }

        #region Parse the logging configuration
        if ($script:GatekeeperConfiguration.Logging) {
            Write-Verbose "Parsing logging configuration."
            $script:GatekeeperLogging = @{}
            foreach ($level in $script:GatekeeperConfiguration.Logging.Keys) {
                if (-not $script:GatekeeperConfiguration.Logging[$level].Enabled) {
                    Write-Verbose "Logging level '$level' is disabled, skipping."
                    continue
                }
                # A logging Script is executed as code with the caller's full
                # privileges. It can be a literal scriptblock (set in-memory) or a
                # string. A string ending in '.ps1' is treated as a path to a local
                # script file; any other string is treated as inline PowerShell code.
                # UNC / remote paths are rejected so the user-writable configuration
                # file cannot pull a payload off the network.
                $scriptContent = $script:GatekeeperConfiguration.Logging[$level].Script
                if ($scriptContent -is [scriptblock]) {
                    Write-Verbose "Using inline script block for logging level: $level"
                    $script:GatekeeperLogging[$level] = $scriptContent
                } elseif ($scriptContent -is [string]) {
                    if ([string]::IsNullOrWhiteSpace($scriptContent)) {
                        Write-Warning "Logging level '$level' has an empty Script value; skipping."
                        continue
                    }
                    if ($scriptContent -match '\.ps1\s*$') {
                        $scriptPath = $scriptContent
                        $parsedUri = $null
                        $isRemotePath = $scriptPath -match '^(\\\\|//)' -or (
                            [System.Uri]::TryCreate($scriptPath, [System.UriKind]::Absolute, [ref]$parsedUri) -and
                            ($parsedUri.IsUnc -or $parsedUri.Scheme -ne 'file')
                        )
                        if ($isRemotePath) {
                            Write-Warning "Logging level '$level' Script path '$scriptPath' is a UNC or remote path; refusing to load it."
                            continue
                        }
                        if (-not (Test-Path -Path $scriptPath -PathType Leaf -ErrorAction SilentlyContinue)) {
                            Write-Warning "Logging level '$level' Script path '$scriptPath' was not found; skipping."
                            continue
                        }
                        Write-Verbose "Loading logging script from file: $scriptPath"
                        $script:GatekeeperLogging[$level] = [scriptblock]::Create((Get-Content -Path $scriptPath -Raw))
                    } else {
                        Write-Verbose "Compiling inline logging script for level: $level"
                        $script:GatekeeperLogging[$level] = [scriptblock]::Create($scriptContent)
                    }
                } else {
                    Write-Warning "No valid script found for logging level: $level"
                }
            }
        }
        #endregion Parse the logging configuration
    }
    end {
        Write-Verbose "Gatekeeper configuration imported successfully."
        return $script:GatekeeperConfiguration
    }
}