private/New-OSDeployCoreWindowsAdkISO.ps1

#Requires -PSEdition Core

function New-OSDeployCoreWindowsAdkISO {
    <#
    .SYNOPSIS
        Creates a UEFI-bootable ISO with Windows ADK Oscdimg
 
    .DESCRIPTION
        Locates amd64 or arm64 oscdimg.exe beneath a Windows ADK root and creates a
        UEFI-bootable UDF ISO from a WinPE media directory. The function searches the
        media directory and then the Oscdimg directory for efisys_noprompt.bin or efisys.bin.
 
        The output directory is created when missing before ShouldProcess evaluates ISO
        creation. Oscdimg uses optimization, permits media larger than a standard CD, and
        may replace an existing output ISO. A nonzero Oscdimg exit code writes an error.
 
    .PARAMETER MediaPath
        Specifies the required WinPE media directory containing the files to place in the ISO.
        The path must exist.
 
    .PARAMETER IsoFileName
        Specifies the required output filename, including the .iso extension when desired.
 
    .PARAMETER IsoLabel
        Specifies the required volume label passed to Oscdimg.
 
    .PARAMETER WindowsAdkRoot
        Specifies the required Windows ADK root. The function searches amd64 first and then
        arm64 Deployment Tools Oscdimg directories.
 
    .PARAMETER IsoDirectory
        Specifies the required output directory. The function creates it when it does not exist.
 
    .EXAMPLE
        PS> New-OSDeployCoreWindowsAdkISO -MediaPath 'C:\WinPE\Media' -IsoFileName 'BootMedia.iso' -IsoLabel 'OSDEPLOY' -WindowsAdkRoot 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit' -IsoDirectory 'C:\OSDeploy\ISO'
 
        Creates C:\OSDeploy\ISO\BootMedia.iso from the WinPE media directory.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.IO.FileInfo. Returns the created ISO file after Oscdimg exits successfully.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 0.1.0
        Date: 2026-08-28
 
        Requires Windows ADK Deployment Tools and UEFI boot-sector content from the media
        directory or the selected Oscdimg directory.
 
    .LINK
        https://learn.microsoft.com/windows-hardware/manufacture/desktop/oscdimg-command-line-options
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $MediaPath,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $IsoFileName,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $IsoLabel,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $WindowsAdkRoot,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $IsoDirectory
    )

    if (-not (Test-Path -Path $MediaPath)) {
        Write-Error "MediaPath not found: $MediaPath"
        return
    }

    # Locate oscdimg.exe - check both amd64 and arm64
    $oscdimgExe = $null
    foreach ($arch in @('amd64', 'arm64')) {
        $candidate = Join-Path $WindowsAdkRoot "Deployment Tools\$arch\Oscdimg\oscdimg.exe"
        if (Test-Path $candidate) {
            $oscdimgExe = $candidate
            break
        }
    }

    if (-not $oscdimgExe) {
        Write-Error "oscdimg.exe not found under $WindowsAdkRoot"
        return
    }

    # Locate efisys_noprompt.bin / efisys.bin: media path first, then ADK Oscdimg directory
    $efisysBin = $null
    $oscdimgDir = Split-Path $oscdimgExe -Parent
    foreach ($candidate in @(
        (Join-Path $MediaPath    'EFI\Microsoft\Boot\efisys_noprompt.bin'),
        (Join-Path $MediaPath    'EFI\Microsoft\Boot\efisys.bin'),
        (Join-Path $oscdimgDir   'efisys_noprompt.bin'),
        (Join-Path $oscdimgDir   'efisys.bin')
    )) {
        if (Test-Path $candidate) {
            $efisysBin = $candidate
            break
        }
    }

    if (-not $efisysBin) {
        Write-Error "efisys.bin not found in $MediaPath or $oscdimgDir"
        return
    }

    $isoFilePath = Join-Path $IsoDirectory $IsoFileName

    if (-not (Test-Path $IsoDirectory)) {
        New-Item -Path $IsoDirectory -ItemType Directory -Force | Out-Null
    }

    if ($PSCmdlet.ShouldProcess($isoFilePath, 'Create bootable ISO')) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Creating ISO: $isoFilePath"

        # UEFI-only ISO creation
        $oscdimgArgs = @(
            '-m'
            '-o'
            '-u2'
            '-udfver102'
            "-bootdata:1#pEF,e,b`"$efisysBin`""
            "-l`"$IsoLabel`""
            "`"$MediaPath`""
            "`"$isoFilePath`""
        )

        $process = Start-Process -FilePath $oscdimgExe -ArgumentList $oscdimgArgs -NoNewWindow -Wait -PassThru
        if ($process.ExitCode -ne 0) {
            Write-Error "oscdimg.exe exited with code $($process.ExitCode)"
        }
        else {
            Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] ISO created: $isoFilePath"
            Get-Item $isoFilePath
        }
    }
}