private/Install-SoftwareMicrosoftWindowsAdk25H2.ps1
|
function Install-SoftwareMicrosoftWindowsAdk25H2 { <# .SYNOPSIS Installs Windows ADK 10.1.26100.2454 and its Windows PE add-on .DESCRIPTION Reads the 25H2 ADK version and bootstrapper URLs from OSDeploy module metadata. The function downloads the ADK and Windows PE add-on bootstrappers, creates offline layout content, and installs the deployment tools, Imaging and Configuration Designer, and Windows Preinstallation Environment features. DownloadOnly caches the bootstrappers without creating layouts or 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 cache directories are created before ShouldProcess. .PARAMETER DownloadOnly Downloads the ADK and Windows PE add-on bootstrappers without installing either component. .EXAMPLE PS> Install-SoftwareMicrosoftWindowsAdk25H2 Downloads and installs the configured 25H2 ADK and Windows PE add-on when an ADK is not already installed. .EXAMPLE PS> Install-SoftwareMicrosoftWindowsAdk25H2 -DownloadOnly Downloads both bootstrappers without creating layouts or 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.25h2 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-SoftwareMicrosoftWindowsAdk25H2 is supported only on Windows." } if (-not (Test-IsAdministrator)) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Install-SoftwareMicrosoftWindowsAdk25H2 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.'25h2') { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] OSDeployCore module metadata is missing required adk.25h2 configuration." } $adkConfig = $global:OSDeployModule.Software.adk.'25h2' $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.25h2 is incomplete. Required keys: version, adksetup, winpesetup." } $downloadDir = Join-Path -Path $Script:OSDeployCoreSoftwarePath -ChildPath "Microsoft.WindowsADK_$adkVersion" $adkLayoutDir = Join-Path -Path $downloadDir -ChildPath 'adk' $winpeLayoutDir = Join-Path -Path $downloadDir -ChildPath 'adkwinpe' New-Item -Path $adkLayoutDir -ItemType Directory -Force | Out-Null New-Item -Path $winpeLayoutDir -ItemType Directory -Force | Out-Null $adkSetup = Join-Path -Path $adkLayoutDir -ChildPath 'adksetup.exe' $winpeSetup = Join-Path -Path $winpeLayoutDir -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)] Downloading Windows ADK Installers $adkVersion..." -ForegroundColor DarkGray $adkLayoutArgs = @('/quiet', '/layout', $adkLayoutDir) $adkLayoutProcess = Start-Process -FilePath $adkSetup -ArgumentList $adkLayoutArgs -Wait -PassThru if ($adkLayoutProcess.ExitCode -ne 0) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Windows ADK Installers download failed with exit code $($adkLayoutProcess.ExitCode)." } Write-Host "[$(Get-Date -Format s)] Windows ADK Installers downloaded successfully." -ForegroundColor DarkGray 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)] Downloading Windows PE add-on Installers $adkVersion..." -ForegroundColor DarkGray $winpeLayoutArgs = @('/quiet', '/layout', $winpeLayoutDir) $winpeLayoutProcess = Start-Process -FilePath $winpeSetup -ArgumentList $winpeLayoutArgs -Wait -PassThru if ($winpeLayoutProcess.ExitCode -ne 0) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Windows PE add-on Installers download failed with exit code $($winpeLayoutProcess.ExitCode)." } Write-Host "[$(Get-Date -Format s)] Windows PE add-on Installers downloaded successfully." -ForegroundColor DarkGray 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 } } |