private/Software/Install-MicrosoftWindowsAdk25H2.ps1
|
<#
.SYNOPSIS Installs Windows ADK 10.1.26100.2454 and its Windows PE add-on. .DESCRIPTION Downloads and installs Windows Assessment and Deployment Kit (ADK) version 10.1.26100.2454 (December 2024) 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-MicrosoftWindowsAdk25H2 Downloads and installs Windows ADK 10.1.26100.2454 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-MicrosoftWindowsAdk25H2 { [CmdletBinding(SupportsShouldProcess = $true)] [OutputType([pscustomobject])] param ( [switch] $DownloadOnly ) if (-not $IsWindows) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Install-MicrosoftWindowsAdk25H2 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-MicrosoftWindowsAdk25H2 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)] [$($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)] 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)] [$($MyInvocation.MyCommand.Name)] Windows ADK Installers downloaded successfully." -ForegroundColor DarkGray 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)] 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)] [$($MyInvocation.MyCommand.Name)] Windows PE add-on Installers downloaded successfully." -ForegroundColor DarkGray 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 } } |