private/Step-BuildBootCoreWinPEStartupProfiles.ps1

#Requires -PSEdition Core

function Step-BuildBootCoreWinPEStartupProfiles {
    <#
    .SYNOPSIS
        Copies configured and profile-local WinPEStartup profiles into the mounted image
 
    .DESCRIPTION
        Copies paths from global BuildMedia.WinPEStartupProfile, followed by root-level
        JSON files discovered in the build profile's WinPEStartup\profiles directory.
        Paths are processed in configured-first order, and duplicate paths are copied
        only once.
 
        The destination WinPEStartup\profiles directory is created under the mounted
        image when needed. Existing files are overwritten, and missing source paths
        produce warnings.
 
    .EXAMPLE
        PS> Step-BuildBootCoreWinPEStartupProfiles
 
        Copies configured and profile-local startup profiles 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-08-28
        Change Summary:
        - Initial version.
 
        Requires global BuildMedia with WinPEStartupProfile, BuildProfile, and
        MountPath properties. BuildProfileContentPath optionally overrides the
        profile-local content directory. Modifies the mounted image profile directory.
    #>

    [CmdletBinding()]
    param ()

    # Start with startup profiles explicitly configured in osdeployboot.json.
    $WinPEStartupProfile = @($global:BuildMedia.WinPEStartupProfile | Where-Object { $_ })
    $BuildProfilePath = $global:BuildMedia.BuildProfile
    $BuildProfileContentPath = $global:BuildMedia.BuildProfileContentPath
    if (-not $BuildProfileContentPath -and $BuildProfilePath) {
        $BuildProfileContentPath = Split-Path -Path $BuildProfilePath -Parent
    }
    $ProfileStartupProfilePath = if ($BuildProfileContentPath) {
        Join-Path $BuildProfileContentPath 'WinPEStartup' 'profiles'
    }

    # Append root-level JSON files from the profile-local WinPEStartup\profiles directory.
    if ($ProfileStartupProfilePath -and (Test-Path -LiteralPath $ProfileStartupProfilePath -PathType Container)) {
        $WinPEStartupProfile += Get-ChildItem -LiteralPath $ProfileStartupProfilePath -Filter '*.json' -File -ErrorAction SilentlyContinue |
            Sort-Object FullName |
            Select-Object -ExpandProperty FullName
    }

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

    $ProfilesDestPath = Join-Path $global:BuildMedia.MountPath 'WinPEStartup' 'profiles'
    if (-not (Test-Path -Path $ProfilesDestPath)) {
        New-Item -ItemType Directory -Path $ProfilesDestPath -Force | Out-Null
    }

    foreach ($Item in $WinPEStartupProfile) {
        if (Test-Path -LiteralPath $Item -PathType Leaf) {
            Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] winpestartup-profile: $Item"
            Copy-Item -LiteralPath $Item -Destination $ProfilesDestPath -Force
        }
        else {
            Write-Warning "[$(Get-Date -Format s)] WinPEStartup Profile not found: $Item"
        }
    }
}