Allows users to bypass driver installation by entering 0 at the selection prompt, providing flexibility for deployments that don't require driver updates.
Introduces a skip flag and restructures the selection validation logic to accept either a valid driver selection or a skip command. When skipped, driver-related variables are set to null and appropriate logging messages are generated.
Introduces helper functions to create and remove SUBST drive mappings for driver folders, addressing potential issues with long file paths during driver injection.
The new implementation:
- Adds `Get-AvailableDriveLetter` to find an unused drive letter
- Adds `New-DriverSubstMapping` to create a virtual drive mapping to the source folder
- Adds `Remove-DriverSubstMapping` to clean up the mapping after use
- Updates the driver injection workflow to use the mapped drive path instead of the original path
- Wraps the operation in try-catch-finally to ensure cleanup occurs even on errors
This approach mitigates issues with excessively long driver folder paths that could exceed command-line limits or cause path-related failures during DISM operations.
Removes hardcoded manufacturer name list and treats all immediate child folders under the Drivers path as potential manufacturer containers. This supports both known vendors (Dell, HP, Lenovo, Microsoft) and unknown/custom manufacturers without requiring code changes.
Adds support for manufacturer folders that directly contain installable driver content (no model subfolders), enabling flatter folder structures when appropriate.
Improves code readability by consolidating the folder processing logic into a single loop that checks for model subfolders first, then falls back to treating the manufacturer folder itself as a driver source if it contains installable content.
Improves driver folder discovery logic by explicitly defining recognized manufacturer folder names (Dell, HP, Lenovo, Microsoft) instead of treating any root-level folder with children as a manufacturer folder.
Prevents incorrect categorization of non-manufacturer folders at the root level and ensures only legitimate OEM folders are processed for model-specific driver packages.
Refactors control flow to eliminate else block, improving code clarity and maintainability.
Simplifies the driver source selection table by removing the full Path column from the formatted output.
The RelativePath column already provides sufficient information for users to identify driver sources, making the full path redundant and cluttering the display.
Adds validation to filter out driver folders containing only WIM files or no installable content before attempting driver injection. This prevents unnecessary processing and potential errors when scanning driver repositories.
Introduces a helper function to recursively check folders for installable driver content (non-WIM files). The validation runs before adding folders to the driver sources list, with appropriate logging when folders are skipped.
Also includes minor code formatting improvements for consistency.
Enhances the driver source selection menu by displaying relative paths instead of full paths, making it easier to identify manufacturer and model folders at a glance.
Adds logic to surface Manufacturer\Model folder structures by expanding top-level folders that contain subdirectories, while preserving simple folder listings when no nested structure exists.
Includes a relative path resolver that normalizes paths and calculates display-friendly names relative to the drivers root directory.
Updates logging and console output to show relative paths for better readability while maintaining full path information internally for file operations.
Implements a generic model-based matching strategy for manufacturers without explicit handling rules in the driver mapping logic.
Previously, unsupported manufacturers would immediately return null without attempting to match driver rules. Now falls back to comparing normalized model names against available rules, improving driver detection coverage for manufacturers that don't require specialized matching logic.
Updates logging to distinguish between successful generic matches and complete failures to find matching drivers.
Allows driver mapping to support all Microsoft-branded devices, not just Surface products.
Previously, the code rejected any Microsoft device that didn't match "Surface" in the model name. This restriction prevented proper driver mapping for other Microsoft hardware.
Updates log messages to use generic "Microsoft model" terminology instead of "Surface" to reflect the broader device support.
Extends hardware detection and driver mapping capabilities to support Panasonic, Viglen, AZW, Fujitsu, Getac, ByteSpeed, and Intel devices.
Implements manufacturer-specific identification logic using baseboard SKU and product information where appropriate. Adds special handling for ByteSpeed devices that may be rebranded Intel NUCs.
Improves model name trimming to ensure consistent string comparisons across all manufacturers.
Extracts manufacturer-specific identifier resolution into a new Get-SystemIdentityMetadata function to improve code organization and reusability.
Consolidates normalization logic so UI display and driver mapping share consistent system identifiers, eliminating duplicate manufacturer detection calls. Stores normalized values alongside original data for better traceability.
Improves maintainability by centralizing model name handling for Lenovo devices and identifier resolution logic for Dell, HP, and Lenovo systems into a single reusable component.
Consolidates manufacturer-specific identifier logic into a single metadata object to reduce code duplication and improve maintainability.
Previously, manufacturer identifiers were captured and assigned using separate variables with duplicated switch-case logic. Now captures all metadata (SystemSku, FallbackSku, MachineType, Label, IdentifierValue) upfront in a structured object, allowing downstream logic to reference a single source of truth.
Improves readability by centralizing the identifier selection logic within each manufacturer case rather than scattering it across multiple switch statements.
Implements manufacturer-specific device identification for automatic driver selection using System SKU, Machine Type, and other vendor identifiers instead of relying solely on model name pattern matching.
Adds normalized manufacturer detection to handle vendor name variations consistently across Dell, HP, Lenovo, and Microsoft Surface devices.
Extracts comprehensive system information from WMI including baseboard details, BIOS metadata, and firmware versions to support accurate device identification and troubleshooting.
Refactors system information gathering into reusable functions that separate data collection from display logic, enabling the driver mapping feature to leverage device identifiers.
Enhances logging by capturing vendor-specific identifiers while hiding internal matching fields from user-facing output to reduce confusion.
Fixes minor log message wording for clarity when driver installation encounters expected failures.
Increments internal preview version for build and deployment scripts to reflect next preview cycle, ensuring logs and artifacts show the correct release identifier for traceability.
Enhances the model name normalization function to better handle variations in hardware model strings. This change introduces specific rules to canonicalize "All-in-One" and screen size variants (e.g., "-in" or "inch") for more reliable matching against driver mapping rules.
Additionally, optimizes performance by normalizing the system model once before the comparison loop. Logging is also added to show the original and normalized model strings for easier debugging.
Improves JSON parsing of the driver mapping file to handle different file structures more reliably.
Adds logging to show all potential driver mapping rules that match the current system, making it easier to diagnose rule selection.
Updates the logging messages to more accurately reflect that the computer name change takes effect after a restart. The `Set-Computername` command stages the change, so the log now indicates the name "will be set" instead of "was set".
Moves the 'Device Name Selection' section header out of the conditional blocks to a common location. This refactoring avoids code repetition and improves maintainability.
Updates the Win32 app installation script to handle WinGet-sourced apps and user-defined apps in two separate batches instead of merging them. This ensures all WinGet apps are installed before any user-defined apps.
The core installation logic is extracted into a reusable function, improving script structure and readability.
Additionally, removes a pause command and a redundant console message from other scripts to improve automation flow.
Enhances the driver mapping logic to ensure JSON files with a single entry are handled correctly. The model matching is now more flexible, allowing for partial matches in either direction between the system's reported model and the mapping file.
Adds a user-facing message to indicate that the driver injection process may take a significant amount of time, preventing confusion about the script stalling.
Introduces a progress reporting system to provide real-time feedback during the FFU build. This includes adding a progress bar and status messages to the UI, which are updated at key stages of the build process.
- Adds a new `Set-Progress` function to log progress updates.
- Integrates `Set-Progress` calls throughout the main build script.
- Updates the UI to parse progress logs and update the progress bar and status text.
- Improves error reporting in the UI to display more detailed failure reasons.
- Corrects a typo in the `LogicalSectorSizeBytes` parameter name in documentation and log messages.
Introduces a centralized function to handle script termination, ensuring the DISM log is always copied on failure for easier debugging.
Improves user-facing error messages to provide clearer guidance for common issues, such as a missing hard drive, incorrect USB drive configuration, or FFU logical sector size mismatches.
Adds post-deployment verification to ensure the Windows partition is created and assigned a drive letter correctly after applying the FFU.
Refactors the script's console output to be cleaner and more user-friendly.
- Adds formatted section headers to clearly delineate each stage of the deployment process.
- Replaces verbose console logging with more selective and meaningful status messages for the user.
- Prevents external commands from opening new windows, creating a more seamless execution flow in the terminal.
Replaces the slow WIM extraction process with a faster WIM mount operation. This significantly improves performance when injecting drivers from a WIM file.
The script now properly unmounts the WIM after injection to ensure resources are cleaned up correctly.
Additionally, log messages are now written to the console for better real-time feedback during script execution.
Adds a new function to gather and display detailed system information (model, CPU, memory, disk size) in both the log file and the console. This helps with verification and troubleshooting.
Improves the user experience by adding an ASCII art banner and cleaning up the console output by suppressing progress bars and command echoes.
Modernizes the script by replacing the deprecated `Get-WmiObject` cmdlet with `Get-CimInstance`.
Refines the driver selection logic to correctly handle overlapping or wildcard-based rules in the driver mapping file.
Previously, the script would use the first rule that matched the system manufacturer and model. This could lead to a less specific rule being chosen if it appeared before a more specific one.
The logic now finds all matching rules and selects the one with the most specific model name, ensuring a more accurate driver package is applied.
Adds a `DriverMapping.json` file to automate driver injection during image deployment.
Driver download tasks now generate or update this mapping file with the relative path for each successfully downloaded driver package.
The deployment script now uses this file to automatically detect and select the correct drivers for the target hardware, removing the need for manual selection. The manual driver selection prompt is retained as a fallback.
Streamlines the driver discovery process by searching for both WIM files and driver folders at the same time. This replaces the previous sequential logic that checked for WIMs first, then folders.
If multiple driver sources are found, they are now presented in a single, unified list for user selection, regardless of whether they are a WIM or a folder. This simplifies the script's control flow and improves the user experience.
Updates the driver installation logic to prioritize searching for and installing drivers from .wim files located in the `Drivers` directory. If a single WIM is found, it is used automatically. If multiple WIMs are found, the user is prompted for a selection.
The script extracts the WIM to a temporary location before injecting the drivers. The previous method of installing from a folder is retained as a fallback if no WIM files are present. Error handling and cleanup for the WIM installation process are also included.
BuildFFUVM.ps1
- Added parameter definitions that were missing:
- AppListPath - Path to a JSON file containing a list of applications to install using WinGet. Default is $FFUDevelopmentPath\Apps\AppList.json.
- PEDriversFolder - Path to the folder containing drivers to be injected into the WinPE deployment media. Default is $FFUDevelopmentPath\PEDrivers.
- Added two new parameters:
- UpdateLatestMicrocode - This is used for Windows 10/Server. When set to $true, will download and install the latest microcode updates for applicable Windows releases (e.g., Windows Server 2016/2019, Windows 10 LTSC 2016/2019) into the FFU. Default is $false.
- UpdateADK - Added for airgapped scenarios where you've manually updated the ADK and don't need it to continually check. When set to $true, the script will check for and install the latest Windows ADK and WinPE add-on if they are not already installed or up-to-date. Default is $true.
- Reorganized the WindowsSKU validateset to make it easier to read and added in 2016 LTSB releases
- Changed version to 2505.1
- Reorganized the releasetoMapping SKUs to make it easier to read
- Omitted Defender/Edge from reporting KB ID since neither includes it
- Updated Save-KB with some enhancements from the UI branch which will handle KBs that don't have an architecture defined in their file name that will leverage a new function Get-PEArchitecture that can interrogate the file name and determine the correct architecture
- Updated Get-ShortenedWindowsSKU with LTSB/LTSC SKUs
- Updated New-FFUFileName to use $winverinfo.Name for $WindowsRelease for client OSes to which will set $WindowsRelease to using Win10 or Win11. This fixes a bug where you might see 10 or 11 instead of Win10 or Win11 for FFU builds that use only the VHDX (e.g. `-InstallApps $false`. This keeps the naming consistent with FFUs built via VM.
- Updated Get-WindowsVersionInfo to fix an issue with naming LTSC 2019
- Added Get-PEArchitecture function
- Commented out the Windows Security Platform Update code since the URL is dead for the content. This is fixed in the UI branch and will be reintroduced in Dev and Main at a later date when the UI work is complete.
- Created a new variable `$isLTSC`
- Modified and reorganized the search strings for the various .net framework components. LTSC introduced some complexity with handling the various .net releases.
- VHDXCaching will now recurse the KBPath folder when finding downloaded KBs to include in its config file
Sample_default.json
- Added new/missing parameters
- ApplistPath
- UpdateADK
- UpdateLatestMicrocode
CaptureFFU.ps1
- `$WindowsVersion` 2016 and 2019 for LTSC releases
- Changed some SKU spacing to make things more consistent and included Enterprise N LTSC
ApplyFFU.ps1
- Updated version to 2505.1
- Allows setting the computer name with a predefined list (SerialComputerNames.csv) of serial numbers and matching computer names
- Defaults to FFU-{Random} if no matching serial number is found in list so FFU deployment can continue without user input
- Fixed an issue where if AppsScriptVariables was configured in a config file, the hashtable wasn't being created by the script when setting the variable.
- Fixed a crash where shortening the Windows SKU was creating duplicate shortened names for certain SKUs.
- Fixed an issue with WinPE Drivers not being added to Deployment media
- Fixed an issue where Windows SKUs that include spaces in their names (e.g. Pro Education) and `$InstallApps $false`, FFU creation would fail due to the name including a space. Added a new function `Get-ShortenedWindowsSKU` to truncate the SKU for FFU name creation purposes. This required various changes throughout the script that relied on the Windows SKU for naming.
- Updated version 2412.3
- Updated parameter definition block to be alphabetized (not to be confused by the param block, which is not alphabetized)
- Added $PEDriversFolder script variable to the param block (for some reason it was missing)
- Added ConfigFile and ExportConfigFile parameters to support json config files
- Changed Version to 2412.1
- Modified vhdxCacheItem class to include $LogicalSectorSizeBytes
- Added new function Get-Parameters to help with new config and export config file functionality
- Fixed Get-MicrosoftDrivers function to not require the HTMLFILE COM object, which isn't available in Windows 11. It seems to be installed with Office, which is what was allowing downloads to work and masked the issue.
- Added long path support to prevent issues with oscdimg creating the Apps.iso.
- Fixed an issue where the $PEDriversFolder variable wasn't being used (instead $FFUDevelopment\PEDrivers was used)
- Created a new function New-FFUFileName - this works in conjunction with the new $CustomFFUNameTemplate. The function was needed to support both scenarios where $InstallApps is either $true or $false.
- Added new function Export-ConfigFile. When passing -ExportConfigFile 'Path\To\ConfigFile.json' the script will generate a parameter dump of all of the configured parameters
- Added driver folder validation to throw an error if spaces are detected in the folder name of the drivers folder (e.g. C:\FFUDevelopment\Drivers\Dell 3190). This is due to an issue with Dell drivers and their inability to handle paths with spaces consistently.
- Added back the Windows Security Platform update which grabs it from the web instead of the Microsoft update catalog
- Fixed an issue where the Drivers folder was being completely deleted instead of its sub-folders
- Removed the Requires -PSEdition Desktop. The script works with both Desktop and Core, so pwsh 7 is fine.
- Created a new config folder to hold config files. A new sample_default.json file is provided to show what the format looks like.
- You can now set the computername in the unattend.xml file whereever you want. Prior it required that the computername was the first component element.
- Migrate Winget downloads to use Export-WingetPackage cmdlet as per issue Known Issue: Winget downloads fail on Non-English OS #50
- Add better logging when unable to find HDD when applying FFU