private/Software/Install-MicrosoftWindowsAdk26H1.ps1

<#
.SYNOPSIS
Installs Windows ADK 10.1.28000.1 and its Windows PE add-on.
 
.DESCRIPTION
Downloads and installs Windows Assessment and Deployment Kit (ADK) version
10.1.28000.1 and its Windows PE add-on using curl.exe.
Also applies the MDT Windows PE x86 MMC snap-in bugfix by creating the
missing x86 WinPE_OCs directory.
 
.OUTPUTS
System.Management.Automation.PSCustomObject
 
.EXAMPLE
Install-MicrosoftWindowsAdk26H1
 
Downloads and installs Windows ADK 10.1.28000.1 and the Windows PE add-on.
 
.NOTES
Author: David Segura
Company: Recast Software
This function is supported only on Windows.
winget is not used because it does not reliably install this ADK version.
 
If installation fails, refer to the official documentation for troubleshooting:
https://learn.microsoft.com/en-us/windows-hardware/get-started/adk-install
 
.LINK
https://learn.microsoft.com/en-us/windows-hardware/get-started/adk-install
Change Summary:
#>

function Install-MicrosoftWindowsAdk26H1 {
    [CmdletBinding(SupportsShouldProcess = $true)]
    [OutputType([pscustomobject])]
    param (
        [switch] $DownloadOnly
    )

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

    $currentPrincipal = [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
    if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Install-MicrosoftWindowsAdk26H1 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)] [$($MyInvocation.MyCommand.Name)] Windows ADK $adkVersion is already installed." -ForegroundColor Green
        }
        else {
            Write-Host "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] 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)] [$($MyInvocation.MyCommand.Name)] Downloading Windows ADK $adkVersion..." -ForegroundColor DarkGray
    & curl.exe --insecure --location --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)] [$($MyInvocation.MyCommand.Name)] Downloading Windows PE add-on for ADK $adkVersion..." -ForegroundColor DarkGray
    & curl.exe --insecure --location --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)] [$($MyInvocation.MyCommand.Name)] 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)] [$($MyInvocation.MyCommand.Name)] Applying MDT Windows PE x86 bugfix..." -ForegroundColor DarkGray
            New-Item -Path $x86WinPEPath -ItemType Directory -Force | Out-Null
            Write-Host "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] 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)] [$($MyInvocation.MyCommand.Name)] 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)] [$($MyInvocation.MyCommand.Name)] Windows ADK installed successfully." -ForegroundColor Green

    # Step 4: Install Windows PE add-on
    Write-Host "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] 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)] [$($MyInvocation.MyCommand.Name)] 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)] [$($MyInvocation.MyCommand.Name)] Applying MDT Windows PE x86 bugfix..." -ForegroundColor DarkGray
        New-Item -Path $x86WinPEPath -ItemType Directory -Force | Out-Null
        Write-Host "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] 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
    }
}