private/Step-BuildBootCoreWinpeStartupCore.ps1

#Requires -PSEdition Core

function Step-BuildBootCoreWinpeStartupCore {
    <#
    .SYNOPSIS
        Copies configured and profile-local WinpeStartup Core folders into the mounted image
 
    .DESCRIPTION
        Automatically includes Boot-Assets winpestartup-core\main when present, then
        copies directories from global BuildMedia.WinpeStartupCore, followed by the
        immediate child directories discovered in the build profile's WinpeStartup\core
        directory.
        Paths are processed in main-first, configured, then profile-local order, and
        duplicate paths are copied only once.
 
        Each source directory is copied to WinpeStartup\core\<FolderName> under the
        mounted image. Content from directories with the same name is merged recursively,
        and existing files are overwritten. Missing source paths produce warnings.
 
    .EXAMPLE
        PS> Step-BuildBootCoreWinpeStartupCore
 
        Copies configured and profile-local WinpeStartup Core folders into the mounted image.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        None.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-10-05
        Change Summary:
        - Initial version.
 
        Requires global BuildMedia with WinpeStartupCore, BuildProfile, and MountPath
        properties. BuildProfileContentPath optionally overrides the profile-local content
        directory. Modifies the mounted image WinpeStartup\core directory.
    #>

    [CmdletBinding()]
    param ()

    $WinpeStartupCore = @()
    $MainCorePath = Join-Path $Script:OSDeployBootAssetsPath 'winpestartup-core' 'main'
    if (Test-Path -LiteralPath $MainCorePath -PathType Container) {
        $WinpeStartupCore += $MainCorePath
    }
    $WinpeStartupCore += @($global:BuildMedia.WinpeStartupCore | Where-Object { $_ })
    $BuildProfilePath = $global:BuildMedia.BuildProfile
    $BuildProfileContentPath = $global:BuildMedia.BuildProfileContentPath
    if (-not $BuildProfileContentPath -and $BuildProfilePath) {
        $BuildProfileContentPath = Split-Path -Path $BuildProfilePath -Parent
    }
    $ProfileWinpeStartupCorePath = if ($BuildProfileContentPath) {
        Join-Path $BuildProfileContentPath 'WinpeStartup' 'core'
    }

    # Append immediate child directories from the profile-local core directory.
    if ($ProfileWinpeStartupCorePath -and (Test-Path -LiteralPath $ProfileWinpeStartupCorePath -PathType Container)) {
        $WinpeStartupCore += Get-ChildItem -LiteralPath $ProfileWinpeStartupCorePath -Directory -ErrorAction SilentlyContinue |
            Sort-Object FullName |
            Select-Object -ExpandProperty FullName
    }

    # Preserve copy order while preventing the same path from being copied twice.
    $SeenFolders = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
    $WinpeStartupCore = @($WinpeStartupCore | Where-Object { $SeenFolders.Add([System.String]$_) })
    if (-not $WinpeStartupCore) { return }

    $WinpeStartupCorePath = Join-Path $global:BuildMedia.MountPath 'WinpeStartup' 'core'

    foreach ($Item in $WinpeStartupCore) {
        if (Test-Path -LiteralPath $Item -PathType Container) {
            Write-HostDateTimeDarkGray "winpestartup-core: $Item"
            $FolderDestPath = Join-Path $WinpeStartupCorePath (Split-Path -Path $Item -Leaf)
            if (-not (Test-Path -LiteralPath $FolderDestPath)) {
                New-Item -ItemType Directory -Path $FolderDestPath -Force | Out-Null
            }
            # Copy children into the existing destination so same-name folders merge.
            foreach ($Child in @(Get-ChildItem -LiteralPath $Item -Force -ErrorAction SilentlyContinue)) {
                Copy-Item -LiteralPath $Child.FullName -Destination $FolderDestPath -Recurse -Force
            }
        }
        else {
            Write-Warning "[$($MyInvocation.MyCommand.Name)] WinpeStartup Core folder not found: $Item"
        }
    }
}