private/Install-SoftwareMicrosoftWindowsAdk26H1.ps1

function Install-SoftwareMicrosoftWindowsAdk26H1 {
    <#
    .SYNOPSIS
        Installs Windows ADK 10.1.28000.1 and its Windows PE add-on
 
    .DESCRIPTION
        Reads the 26H1 ADK version and bootstrapper URLs from OSDeploy module metadata. The
        function downloads the ADK and Windows PE add-on bootstrappers and installs the
        deployment tools, Imaging and Configuration Designer, and Windows Preinstallation
        Environment features.
 
        DownloadOnly caches the bootstrappers without installing features. When an ADK
        installation is detected, the function skips installation after downloading the
        bootstrappers. It also creates the missing x86 WinPE_OCs directory used by the MDT
        Windows PE MMC snap-in workaround. WhatIf and Confirm apply to downloading and
        installation, although the cache directory is created before ShouldProcess.
 
    .PARAMETER DownloadOnly
        Downloads the ADK and Windows PE add-on bootstrappers without installing either
        component.
 
    .EXAMPLE
        PS> Install-SoftwareMicrosoftWindowsAdk26H1
 
        Downloads and installs the configured 26H1 ADK and Windows PE add-on when an ADK is not
        already installed.
 
    .EXAMPLE
        PS> Install-SoftwareMicrosoftWindowsAdk26H1 -DownloadOnly
 
        Downloads both bootstrappers without installing components.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.Management.Automation.PSCustomObject. Returns ADK version, setup paths,
        installation status, process exit codes when available, and workaround status.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-28
 
        Requires Windows, Administrator rights, curl.exe, and complete
        $global:OSDeployModule.Software.adk.26h1 metadata. winget is not used because it does
        not reliably install this ADK version. Installation does not request an automatic
        restart.
 
    .LINK
        https://learn.microsoft.com/en-us/windows-hardware/get-started/adk-install
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    [OutputType([pscustomobject])]
    param (
        [switch] $DownloadOnly
    )

    if (-not $IsWindows) {
        throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Install-SoftwareMicrosoftWindowsAdk26H1 is supported only on Windows."
    }

    if (-not (Test-IsAdministrator)) {
        throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Install-SoftwareMicrosoftWindowsAdk26H1 requires Administrator rights. Re-run PowerShell as Administrator and try again."
    }

    $curl = Get-Command -Name 'curl.exe' -ErrorAction SilentlyContinue
    if (-not $curl) {
        throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] curl.exe is required but was not found. Ensure curl.exe is available in PATH (included with Windows 10 1803+)."
    }

    if (-not $global:OSDeployModule -or -not $global:OSDeployModule.Software.adk -or -not $global:OSDeployModule.Software.adk.'26h1') {
        throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] OSDeployCore module metadata is missing required adk.26h1 configuration."
    }

    $adkConfig = $global:OSDeployModule.Software.adk.'26h1'
    $adkVersion = [string]$adkConfig.version
    $adkUrl = [string]$adkConfig.adksetup
    $winpeUrl = [string]$adkConfig.winpesetup

    if ([string]::IsNullOrWhiteSpace($adkVersion) -or [string]::IsNullOrWhiteSpace($adkUrl) -or [string]::IsNullOrWhiteSpace($winpeUrl)) {
        throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] OSDeployCore module metadata adk.26h1 is incomplete. Required keys: version, adksetup, winpesetup."
    }

    $downloadDir = Join-Path -Path $Script:OSDeployCoreSoftwarePath -ChildPath "Microsoft.WindowsADK_$adkVersion"
    New-Item -Path $downloadDir -ItemType Directory -Force | Out-Null
    $adkSetup      = Join-Path -Path $downloadDir -ChildPath 'adksetup.exe'
    $winpeSetup    = Join-Path -Path $downloadDir -ChildPath 'adkwinpesetup.exe'

    # Detect currently installed ADK version from registry
    $adkRegistryPaths = @(
        'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
        'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
    $installedAdkVersion = $null
    foreach ($regPath in $adkRegistryPaths) {
        $entry = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue |
            Where-Object { $_.PSObject.Properties['DisplayName'] -and $_.DisplayName -like 'Windows Assessment and Deployment Kit*' } |
            Select-Object -First 1
        if ($entry) {
            $installedAdkVersion = $entry.DisplayVersion
            break
        }
    }

    $x86WinPEPath = 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\WinPE_OCs'

    if ($installedAdkVersion) {
        if ($installedAdkVersion -eq $adkVersion) {
            Write-Host "[$(Get-Date -Format s)] Windows ADK $adkVersion is already installed." -ForegroundColor Green
        }
        else {
            Write-Host "[$(Get-Date -Format s)] Windows ADK $installedAdkVersion is already installed. Skipping install of $adkVersion." -ForegroundColor DarkGray
        }
    }

    if (-not $PSCmdlet.ShouldProcess("Windows ADK $adkVersion", 'Download and install ADK and Windows PE add-on')) {
        return [pscustomobject]@{
            AdkVersion       = $installedAdkVersion
            AdkSetupPath     = $adkSetup
            WinPESetupPath   = $winpeSetup
            X86BugfixApplied = (Test-Path -Path $x86WinPEPath)
            AdkExitCode      = $null
            WinPEExitCode    = $null
            WasInstalled     = $false
        }
    }

    # Step 1: Download Windows ADK
    Write-Host "[$(Get-Date -Format s)] Downloading Windows ADK $adkVersion..." -ForegroundColor DarkGray
    & curl.exe --insecure --location --retry 5 --continue-at - --output $adkSetup --url $adkUrl
    if ($LASTEXITCODE -ne 0) {
        throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Failed to download Windows ADK setup (curl.exe exit code $LASTEXITCODE)."
    }

    # Step 2: Download Windows PE add-on
    Write-Host "[$(Get-Date -Format s)] Downloading Windows PE add-on for ADK $adkVersion..." -ForegroundColor DarkGray
    & curl.exe --insecure --location --retry 5 --continue-at - --output $winpeSetup --url $winpeUrl
    if ($LASTEXITCODE -ne 0) {
        throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Failed to download Windows PE add-on setup (curl.exe exit code $LASTEXITCODE)."
    }

    if ($DownloadOnly) {
        Write-Host "[$(Get-Date -Format s)] DownloadOnly: skipping installation." -ForegroundColor DarkGray
        return [pscustomobject]@{
            AdkVersion       = $adkVersion
            AdkSetupPath     = $adkSetup
            WinPESetupPath   = $winpeSetup
            X86BugfixApplied = $false
            AdkExitCode      = $null
            WinPEExitCode    = $null
            WasInstalled     = $false
            DownloadOnly     = $true
        }
    }

    if ($installedAdkVersion) {
        # ADK already installed; skip re-install but apply x86 bugfix if needed
        if (-not (Test-Path -Path $x86WinPEPath)) {
            Write-Host "[$(Get-Date -Format s)] Applying MDT Windows PE x86 bugfix..." -ForegroundColor DarkGray
            New-Item -Path $x86WinPEPath -ItemType Directory -Force | Out-Null
            Write-Host "[$(Get-Date -Format s)] Bugfix applied: created x86 WinPE_OCs directory." -ForegroundColor Green
        }
        return [pscustomobject]@{
            AdkVersion       = $installedAdkVersion
            AdkSetupPath     = $adkSetup
            WinPESetupPath   = $winpeSetup
            X86BugfixApplied = (Test-Path -Path $x86WinPEPath)
            AdkExitCode      = $null
            WinPEExitCode    = $null
            WasInstalled     = $false
        }
    }

    # Step 3: Install Windows ADK
    Write-Host "[$(Get-Date -Format s)] Installing Windows ADK..." -ForegroundColor DarkGray
    $adkArgs = @(
        '/features', 'OptionId.DeploymentTools', 'OptionId.ImagingAndConfigurationDesigner',
        '/quiet', '/ceip', 'off', '/norestart'
    )
    $adkProcess = Start-Process -FilePath $adkSetup -ArgumentList $adkArgs -Wait -PassThru
    if ($adkProcess.ExitCode -ne 0) {
        throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Windows ADK installation failed with exit code $($adkProcess.ExitCode)."
    }
    Write-Host "[$(Get-Date -Format s)] Windows ADK installed successfully." -ForegroundColor Green

    # Step 4: Install Windows PE add-on
    Write-Host "[$(Get-Date -Format s)] Installing Windows PE add-on..." -ForegroundColor DarkGray
    $winpeArgs = @(
        '/features', 'OptionId.WindowsPreinstallationEnvironment',
        '/quiet', '/ceip', 'off', '/norestart'
    )
    $winpeProcess = Start-Process -FilePath $winpeSetup -ArgumentList $winpeArgs -Wait -PassThru
    if ($winpeProcess.ExitCode -ne 0) {
        throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Windows PE add-on installation failed with exit code $($winpeProcess.ExitCode)."
    }
    Write-Host "[$(Get-Date -Format s)] Windows PE add-on installed successfully." -ForegroundColor Green

    Update-OSDeploySessionEnvironment

    # Step 5: Apply MDT Windows PE x86 MMC snap-in bugfix
    if (-not (Test-Path -Path $x86WinPEPath)) {
        Write-Host "[$(Get-Date -Format s)] Applying MDT Windows PE x86 bugfix..." -ForegroundColor DarkGray
        New-Item -Path $x86WinPEPath -ItemType Directory -Force | Out-Null
        Write-Host "[$(Get-Date -Format s)] Bugfix applied: created x86 WinPE_OCs directory." -ForegroundColor Green
    }

    [pscustomobject]@{
        AdkVersion       = $adkVersion
        AdkSetupPath     = $adkSetup
        WinPESetupPath   = $winpeSetup
        X86BugfixApplied = (Test-Path -Path $x86WinPEPath)
        AdkExitCode      = $adkProcess.ExitCode
        WinPEExitCode    = $winpeProcess.ExitCode
        WasInstalled     = $true
    }
}