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 profile
        folders and legacy 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. Profile folders are copied as folders; 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 legacy files and canonical profile folders from profile-local content.
    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

        $WinpeStartupProfile += Get-ChildItem -LiteralPath $ProfileStartupProfilePath -Directory -ErrorAction SilentlyContinue |
            Sort-Object FullName |
            Where-Object { Test-Path -LiteralPath (Join-Path $_.FullName 'winpestartup.json') -PathType Leaf } |
            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
        }
        elseif (Test-Path -LiteralPath $Item -PathType Container) {
            Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] winpestartup-profile: $Item"
            Copy-Item -LiteralPath $Item -Destination $ProfilesDestPath -Recurse -Force
        }
        else {
            Write-Warning "[$(Get-Date -Format s)] WinpeStartup Profile not found: $Item"
        }
    }
}