diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 110d92c..8092451 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -531,29 +531,161 @@ function Install-ADK { throw $_ } } -Function Get-ADK { - Writelog 'Get ADK Path' - # Define the registry key and value name to query - $adkRegKey = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots" - $adkRegValueName = "KitsRoot10" +function Get-InstalledProgramRegKey { + param ( + [string]$DisplayName + ) - # Check if the registry value exists - if ($null -ne (Get-ItemProperty -Path $adkRegKey -Name $adkRegValueName -ErrorAction SilentlyContinue)) { - # Get the registry value for the Windows ADK installation path - $adkPath = (Get-ItemProperty -Path $adkRegKey -Name $adkRegValueName).$adkRegValueName + $uninstallRegPath = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" + $uninstallRegKeys = Get-ChildItem -Path $uninstallRegPath -Recurse + + foreach ($regKey in $uninstallRegKeys) { + try { + $regValue = $regKey.GetValue("DisplayName") + if ($regValue -eq $DisplayName) { + return $regKey + } + } + catch { + WriteLog $_ + throw "Error retrieving installed program info for $DisplayName : $_" + } + } +} + +function Uninstall-ADK { + param ( + [ValidateSet("Windows ADK", "WinPE add-on")] + [string]$ADKOption + ) + + # Match name as it appears in the registry + $displayName = switch ($ADKOption) { + "Windows ADK" { "Windows Assessment and Deployment Kit" } + "WinPE add-on" { "Windows Assessment and Deployment Kit Windows Preinstallation Environment Add-ons" } + } + + try { + $adkRegKey = Get-InstalledProgramRegKey -DisplayName $displayName + + if (-not $adkRegKey) { + WriteLog "$ADKOption is not installed." + return + } + + $adkBundleCachePath = $adkRegKey.GetValue("BundleCachePath") + WriteLog "Uninstalling $ADKOption..." + Invoke-Process $adkBundleCachePath "/uninstall /quiet" + WriteLog "$ADKOption uninstalled successfully." + } + catch { + WriteLog $_ + Write-Error "Error occurred while uninstalling $ADKOption. Please manually uninstall it." + throw $_ + } +} + +function Confirm-ADKVersionIsLatest { + param ( + [ValidateSet("Windows ADK", "WinPE add-on")] + [string]$ADKOption + ) + + $displayName = switch ($ADKOption) { + "Windows ADK" { "Windows Assessment and Deployment Kit" } + "WinPE add-on" { "Windows Assessment and Deployment Kit Windows Preinstallation Environment Add-ons" } + } + + try { + $adkRegKey = Get-InstalledProgramRegKey -DisplayName $displayName + + if (-not $adkRegKey) { + return $false + } + + $installedADKVersion = $adkRegKey.GetValue("DisplayVersion") + + # Retrieve content of Microsoft documentation page + $adkWebPage = Invoke-RestMethod "https://learn.microsoft.com/en-us/windows-hardware/get-started/adk-install" + # Specify regex pattern for ADK version + $adkVersionPattern = 'ADK\s+(\d+(\.\d+)+)' + # Check for regex pattern match + $adkVersionMatch = [regex]::Match($adkWebPage, $adkVersionPattern) + + if (-not $adkVersionMatch.Success) { + WriteLog "Failed to retrieve latest ADK version from web page." + return $false + } + + # Extract ADK version from the matched pattern + $latestADKVersion = $adkVersionMatch.Groups[1].Value + + if ($installedADKVersion -eq $latestADKVersion) { + WriteLog "Installed $ADKOption version $installedADKVersion is the latest." + return $true + } + else { + WriteLog "Installed $ADKOption version $installedADKVersion is not the latest ($latestADKVersion)" + return $false + } + } + catch { + WriteLog "An error occurred while confirming the ADK version: $_" + return $false + } +} + +function Get-ADK { + # Check if latest ADK and WinPE add-on are installed + $latestADKInstalled = Confirm-ADKVersionIsLatest -ADKOption "Windows ADK" + $latestWinPEInstalled = Confirm-ADKVersionIsLatest -ADKOption "WinPE add-on" + + # Uninstall older versions and install latest versions if necessary + if (-not $latestADKInstalled) { + Uninstall-ADK -ADKOption "Windows ADK" + Install-ADK -ADKOption "Windows ADK" + } + + if (-not $latestWinPEInstalled) { + Uninstall-ADK -ADKOption "WinPE add-on" + Install-ADK -ADKOption "WinPE add-on" + } + + # Define registry path + $adkPathKey = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots" + $adkPathName = "KitsRoot10" + + # Check if ADK installation path exists in registry + $adkPathNameExists = (Get-ItemProperty -Path $adkPathKey -Name $adkPathName -ErrorAction SilentlyContinue) + + if ($adkPathNameExists) { + # Get the ADK installation path + WriteLog 'Get ADK Path' + $adkPath = (Get-ItemProperty -Path $adkPathKey -Name $adkPathName).$adkPathName WriteLog "ADK located at $adkPath" - return $adkPath } else { - WriteLog "ADK is not installed. Installing ADK now..." - Install-ADK -ADKOption "Windows ADK" - WriteLog "Installing WinPE add-on for Windows ADK..." - Install-ADK -ADKOption "WinPE add-on" - $adkPath = (Get-ItemProperty -Path $adkRegKey -Name $adkRegValueName).$adkRegValueName - WriteLog "ADK located at $adkPath" - return $adkPath - # throw "Windows ADK is not installed or the installation path could not be found." + throw "Windows ADK installation path could not be found." } + + # If ADK was already installed, then check if the Windows Deployment Tools feature is also installed + $deploymentToolsRegKey = Get-InstalledProgramRegKey -DisplayName "Windows Deployment Tools" + + if (-not $deploymentToolsRegKey) { + WriteLog "ADK is installed, but the Windows Deployment Tools feature is not installed." + $adkRegKey = Get-InstalledProgramRegKey -DisplayName "Windows Assessment and Deployment Kit" + $adkBundleCachePath = $adkRegKey.GetValue("BundleCachePath") + if ($adkBundleCachePath) { + WriteLog "Installing Windows Deployment Tools..." + $adkInstallPath = $adkPath.TrimEnd('\') + Invoke-Process $adkBundleCachePath "/quiet /installpath ""$adkInstallPath"" /features OptionId.DeploymentTools" + WriteLog "Windows Deployment Tools installed successfully." + } + else { + throw "Failed to retrieve path to adksetup.exe to install the Windows Deployment Tools. Please manually install it." + } + } + return $adkPath } function Get-WindowsESD { param(