OSDeploy.psm1

<#
.SYNOPSIS
    OSDeploy root module loader.
 
.DESCRIPTION
    Dot-sources all Private and Public functions.
    Exports all Public functions.
#>


# Capture root path before any dot-sourcing (functions see a different $PSScriptRoot)
$script:OSDeployModuleBase = $PSScriptRoot

#region --- Preview expiry check ---
$script:OSDeployPreviewExpiry = [datetime]'2026-06-30'
$script:OSDeployToday         = [datetime]::Today
if ($script:OSDeployToday -gt $script:OSDeployPreviewExpiry) {
    throw 'OSDeploy Preview expired on 2026-06-30. Visit https://www.recastsoftware.com to obtain the latest release.'
}
elseif ($script:OSDeployToday -ge $script:OSDeployPreviewExpiry.AddDays(-14)) {
    $script:OSDeployDaysLeft = ($script:OSDeployPreviewExpiry - $script:OSDeployToday).Days
    Write-Warning ("OSDeploy Preview expires in {0} day(s) on 2026-06-30. Visit https://www.recastsoftware.com to obtain the latest release." -f $script:OSDeployDaysLeft)
}
#endregion

#region --- Dot-source Private helpers (edition-neutral) ---
$privateScripts = Get-ChildItem -Path (Join-Path $PSScriptRoot 'private') -Filter '*.ps1' -Recurse -ErrorAction SilentlyContinue |
    Where-Object { $_.FullName -notmatch '\\ps\\' -and $_.FullName -notmatch '\\pwsh\\' }
foreach ($script in $privateScripts) {
    try   { . $script.FullName }
    catch { Write-Error "Failed to import private function '$($script.FullName)': $_" }
}
#endregion

#region --- Dot-source Private helpers (edition-specific) ---
if ($PSEdition -eq 'Core') {
    $pwshScripts = Get-ChildItem -Path (Join-Path $PSScriptRoot 'private') -Filter '*.ps1' -Recurse -ErrorAction SilentlyContinue |
        Where-Object { $_.FullName -match '\\pwsh\\' }
    foreach ($script in $pwshScripts) {
        try   { . $script.FullName }
        catch { Write-Error "Failed to import private function '$($script.FullName)': $_" }
    }
}
else {
    # PS 5.1 Desktop: load snap-in bridge functions from ps\ subdirectories
    $desktopPrivate = @(
        (Join-Path $PSScriptRoot 'private\MDT\ps\Import-MDTCmdlets.ps1')
    )
    foreach ($filePath in $desktopPrivate) {
        if (Test-Path -LiteralPath $filePath) {
            try   { . $filePath }
            catch { Write-Error "Failed to import private function '$filePath': $_" }
        }
    }
}
#endregion

#region --- Dot-source Public functions ---
$publicScripts = Get-ChildItem -Path (Join-Path $PSScriptRoot 'public') -Filter '*.ps1' -Recurse -ErrorAction SilentlyContinue
$script:InlinedPublicFunctions = [System.Collections.Generic.List[string]]::new()
foreach ($script in $publicScripts) {
    try {
        . $script.FullName
        $script:InlinedPublicFunctions.Add([System.IO.Path]::GetFileNameWithoutExtension($script.Name))
    }
    catch { Write-Error "Failed to import public function '$($script.FullName)': $_" }
}
#endregion

# Root path for downloaded and expanded content (shared by all Initialize functions)
$script:OSDeployCorePath = Join-Path $env:ProgramData 'OSDeployCore'
$script:OSDeployCoreCachePath = Join-Path $script:OSDeployCorePath 'cache'
$script:OSDeployCoreRepositoryPath = Join-Path $script:OSDeployCorePath 'Repository'
$script:OSDeployCoreDownloadsPath = Join-Path $script:OSDeployCoreCachePath 'downloads'
$script:OSDeployCoreSoftwarePath = Join-Path $script:OSDeployCorePath 'Software'

# Load the full module configuration into a global so it is accessible from any scope
$global:OSDeployModule = Get-Content -Path (Join-Path $PSScriptRoot 'core\module.json') -Raw | ConvertFrom-Json

# Initialize each functional area (BootImage, MDT, Software, WinPEDrivers) to load their configs and PSDefaultParameterValues
Initialize-OSDeployBootMedia
Initialize-OSDeployMDT
Initialize-OSDeploySoftware
Initialize-OSDeployWinPEDrivers

$script:ExportedFunctions = [System.Collections.Generic.List[string]]::new()
foreach ($fn in $script:InlinedPublicFunctions) { $script:ExportedFunctions.Add($fn) }

Export-ModuleMember -Function $script:ExportedFunctions