Compare commits

...

122 Commits

Author SHA1 Message Date
rbalsleyMSFT 6e95ff92b1 fix: update script version to 2505.2 in BuildFFUVM.ps1 and ApplyFFU.ps1 for consistency across files 2025-08-12 17:47:25 -07:00
rbalsleyMSFT d4274d54d2 fix: Microsoft Update Catalog now includes the windows version information in the KB article title. This caused an issue where parsing the KB article was failing. Fixed the regex to accomdate this. 2025-08-12 17:33:26 -07:00
rbalsleyMSFT aee33a6a4b Update README.md 2025-08-01 20:30:35 -07:00
rbalsleyMSFT 25a0928195 Update README.md 2025-07-31 18:17:43 -07:00
rbalsleyMSFT d809fc021f Updated changelog.md 2025-05-21 17:29:12 -07:00
rbalsleyMSFT 582df6e3a8 Merge pull request #165 from rbalsleyMSFT/dev
2505.1
2025-05-21 17:26:25 -07:00
rbalsleyMSFT d5a4f96482 Enhance FFU Development Scripts and Configuration
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
2025-05-21 16:44:21 -07:00
rbalsleyMSFT d2fc9cf558 Merge pull request #116 from zehadialam/win-ltsc
Support for Windows LTSC
2025-05-19 11:04:51 -07:00
Zehadi Alam b530ac5a5c Added comment for .NET updates and added condition in CaptureFFU.ps1 to fix naming for LTSC 2019 2025-05-18 22:06:40 -04:00
Zehadi Alam 2659336ee9 Move .NET folder creation code 2025-05-16 00:26:06 -04:00
Zehadi Alam c32a09bfc1 Add .NET update support for Windows LTSC 2025-05-16 00:11:50 -04:00
Zehadi Alam f7ff415374 Merge branch 'dev' into win-ltsc 2025-05-15 11:55:02 -04:00
rbalsleyMSFT 9cac674d7b Marged in changes to Add-WindowsPackage that were missing 2025-05-15 08:38:01 -07:00
Zehadi Alam 2cf7da9c91 Merge branch 'dev' into win-ltsc 2025-05-15 11:02:18 -04:00
rbalsleyMSFT 0d1d3a1ed5 Fix issue with checkpoint CUs and May 2025-05B CU. Should future proof new checkpoint CUs in the future. 2025-05-14 19:59:04 -07:00
rbalsleyMSFT 7e2ebe8013 Merge pull request #150 from JonasKloseBW/2412.3-Set-Computer-Name-through-SerialNumber-List
2412.3 set computer name through serial number list
2025-02-27 10:04:08 -08:00
JonasKloseBW 0606a1278c Update ApplyFFU.ps1
- 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
2025-02-27 18:37:29 +01:00
rbalsleyMSFT 7c9f24f695 Fixed issues
- 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.
2025-01-16 18:00:08 -08:00
rbalsleyMSFT 227fb4fa94 Merge pull request #129 from JonasKloseBW/2412.3-Add-AppList-Parameter
Add $AppListPath parameter
2025-01-13 09:06:37 -08:00
JonasKloseBW 77ef154941 Add $AppListPath parameter
- Add $AppListPath parameter
- Set default value to "$AppsPath\AppList.json"
- Modify Get-Apps call to use the $AppListPath parameter
2025-01-13 12:51:32 +01:00
rbalsleyMSFT a00aa3ee02 Merge pull request #123 from rbalsleyMSFT/main
2412.3
2025-01-10 13:51:21 -08:00
rbalsleyMSFT 7b6b5efd8d Merge branch 'main' of https://github.com/rbalsleyMSFT/FFU 2025-01-10 13:50:03 -08:00
rbalsleyMSFT db62e05275 Bug fixes
- 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
2025-01-10 13:50:00 -08:00
rbalsleyMSFT 3db66eb55b Merge pull request #119 from HedgeComp/HP-Versions-Fix
Fix HP Driver Windows Version case sensitivity
2025-01-08 12:08:04 -08:00
HedgeComp 4709177bc3 Fix HP Driver Windows Version case sensitivity 2025-01-08 13:16:08 -05:00
Zehadi Alam e25a890946 Remove extra lines 2024-12-28 20:30:03 -05:00
Zehadi Alam bc4a181182 Add support for LTSC versions of Windows 2024-12-28 20:01:01 -05:00
rbalsleyMSFT ce7af09f25 Update README.md 2024-12-20 13:03:14 -08:00
rbalsleyMSFT e3da438225 Update README.md 2024-12-20 13:02:20 -08:00
rbalsleyMSFT edbb7ccabe Update ChangeLog.md 2024-12-20 13:01:50 -08:00
rbalsleyMSFT f4360b34d9 Merge pull request #113 from rbalsleyMSFT/2410.1
2412.1
2024-12-20 12:42:44 -08:00
rbalsleyMSFT 0ed0cf4aa2 Changed ApplyFFU version to 2412.1 2024-12-19 17:09:06 -08:00
rbalsleyMSFT 61fc2198c9 Updated docs and update parameter descriptions in BuildFFUVM.ps1 2024-12-19 16:52:52 -08:00
rbalsleyMSFT f45f5a899b Added parameter description for ExportConfigFile 2024-12-19 15:47:10 -08:00
rbalsleyMSFT 37f6dce344 Changes
- 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.
2024-12-18 16:10:35 -08:00
rbalsleyMSFT 10624787fe Fix ODT
- Refactored the Get-ODTURL function to fix recent download issues. Also added some better error handling
- Moved the odtsetup.exe download to the FFUDevelopment folder and will clean it up after office has downloaded
2024-12-10 15:39:49 -08:00
rbalsleyMSFT d7a697d68d Misc Fixes
- Added Get-Childprocesses function to return child processes of parent process
- Added a new -Wait boolean parameter to Invoke-Process function. This is to control whether Invoke-Process should wait in order to track stdout and stderr output. This is needed for processes that may hang, waiting for user input and there isn't a way to bypass (some Intel drivers provided by Dell leave dialog windows even when running silently)
-Invoke-Process now returns process information (returns $cmd). This allows for process tracking when calling the function.
- Since Invoke-Process now returns the process information, also needed to add Out-Null to the majority of the Invoke-Process references to prevent Invoke-Process from writing to the terminal
- Refactored a lot of the Get-DellDrivers function due to inconsistencies with how driver extraction behaves between client and server devices. For client, /s /e seemed to work fine, but for server it would only extract the driver installer content and other dell related files, rather than the driver files themselves. We have since switched to using /s /drivers= which will extract the driver content. Not all drivers support /drivers= and may output some information to the terminal that looks like help documentation. If a driver doesn't support /drivers, the script falls back to using /s /e to do the extraction. If this doesn't work for you, you can always provide your own drivers that you manually download from Dell's website.
- Updated Malicious Software Removal Tool (MSRT) code to handle Windows Server
2024-12-09 14:59:02 -08:00
rbalsleyMSFT 97954f59c3 - Added Windows 2025/24H2 mapping 2024-12-03 16:55:40 -08:00
rbalsleyMSFT 3b23e9f420 Merge pull request #91 from JonasKloseBW:Better-Windows-Server-Patch-Search
2410.1 Find better Windows Server patches
2024-12-03 16:14:17 -08:00
rbalsleyMSFT 94712ecbfc Merge remote-tracking branch 'origin/2410.1' into pr/JonasKloseBW/91 2024-12-03 16:13:26 -08:00
Mike Kelly a2c2b69026 Update USBImagingToolCreator.ps1 2024-12-03 13:43:36 -08:00
rbalsleyMSFT 6abc6f9d1a Fixed an error with removing the office variable when capturing the FFU 2024-12-02 18:34:58 -08:00
rbalsleyMSFT db0fbfaaf4 Refactor CaptureFFU.ps1 to use $WindowsVersion and $WindowsRelease for improved clarity and consistency in FFU naming 2024-12-02 18:11:38 -08:00
JonasKloseBW a59210c559 Update CaptureFFU.ps1
- Add $CustomFFUNameTemplate support in Update CaptureFFU.ps1
2024-12-02 18:11:38 -08:00
JonasKloseBW add11b0037 Update BuildFFUVM.ps1
- Add $CustomFFUNameTemplate and the required code into BuildFFUVM.ps1
2024-12-02 18:11:38 -08:00
HedgeComp c26034a89c Update unattend_arm64.xml 2024-12-02 10:40:18 -08:00
HedgeComp 9287464eb8 Update unattend_x64.xml 2024-12-02 10:40:18 -08:00
HedgeComp 1c103b2db7 Rename SampleUnattend_64.xml to SampleUnattend_x64.xml 2024-12-02 10:40:18 -08:00
HedgeComp ed6a5fc7f1 Create SampleUnattend_64.xml
Sample for Unattend File.
2024-12-02 10:40:18 -08:00
rbalsleyMSFT 768efc8cf7 Merge pull request #99 from rbalsleyMSFT/revert-98-revert-89-2410.1-Allow-VHDX-caching
Revert "Revert "2410.1 Allow vhdx caching""
2024-11-28 17:41:06 -08:00
rbalsleyMSFT 39a9bc9022 Revert "Revert "2410.1 Allow vhdx caching"" 2024-11-28 17:40:22 -08:00
rbalsleyMSFT f90b7b3c9b Merge pull request #98 from rbalsleyMSFT/revert-89-2410.1-Allow-VHDX-caching
Revert "2410.1 Allow vhdx caching"
2024-11-28 17:38:07 -08:00
rbalsleyMSFT 802a225c3e Revert "2410.1 Allow vhdx caching" 2024-11-28 17:36:00 -08:00
rbalsleyMSFT 74370db5de Merge pull request #89 from JonasKloseBW/2410.1-Allow-VHDX-caching 2024-11-27 13:18:20 -08:00
rbalsleyMSFT db788c3c30 - If not passing an ISO, hardcoded WindowsVersion of 22H2 for Windows 10 or 24H2 for Windows 11 since the ESD media only provides those two versions. Not doing this allowed for unnecessary VHDX creation since it checks the WindowsVersion via the json file. This also fixes an issue where CUs could be searched for that didn’t exist, but the media would still download
- Added some additional logging entries
- Removed verbose output of the Optimize-Volume command
- Fixed an issue where not passing an ISO caused the script to fail
- Cleaned up the KBPath folder at the end of the run
- Changed some minor formatting items
2024-11-27 13:13:29 -08:00
JonasKloseBW eae619e7e8 Update BuildFFUVM.ps1
- Fix update search for Windows Server 2025 release
2024-11-04 18:23:57 +01:00
JonasKloseBW 0f3380e91e Merge pull request #19 from rbalsleyMSFT/2410.1
- $WindowsVersion set to 24h2, can override by using -WindowsVersion …
2024-10-12 03:30:16 +02:00
JonasKloseBW 7c80486d88 Merge pull request #18 from rbalsleyMSFT/2410.1
- $WindowsVersion set to 24h2, can override by using -WindowsVersion …
2024-10-12 03:22:31 +02:00
rbalsleyMSFT 1f65198803 - $WindowsVersion set to 24h2, can override by using -WindowsVersion 23H2 if you want the old behavior
- Removed the "Downloading information GUID" messages when downloading content from the Microsoft Update Catalog while -verbose was specified in the command line
- In Get-KBLink, made a change to just grab the first result returned instead of the entire results page. This removes the need to use a break statement in Save-KB when downloading updates. This fixed an issue with the new 24H2 Checkpoint Cumulative Updates in Win11 and Server 2025.
- Changed Windows MSRT search string for x64 and x86. This was mainly to get x64 to the top of the search results. x86 won't actually download since the code isn't in place for content from the MU Catalog to download x86 content (no idea if anyone actually builds x86 FFUs for Win10 - I hope not)
2024-10-09 16:17:11 -07:00
JonasKloseBW 0f18b7bd80 Merge branch '2410.1' into Better-Windows-Server-Patch-Search 2024-10-05 02:36:47 +02:00
JonasKloseBW b89f4a3b6b Merge branch '2410.1' into 2410.1-Allow-VHDX-caching 2024-10-05 02:11:50 +02:00
rbalsleyMSFT 658d2d7af4 - Added server skus to validateset for $WindowsSKU
- Added new variable $installationType which uses $WindowsRelease to determine Server or Client. If $installationType is Server, $WindowsRelease version is used to set $WindowsVersion to the appropriate version (1607, 1809, 21H2)
- Fixed an issue where the recovery partition wouldn't be created on server OSes due to winre.wim being hidden. Never saw this on client OSes even though it also was hidden IIRC.
- Removed verbosity for Optimize-Volume as it was outputting when -verbose was not specified.
- Modified some search strings for .NET CUs when installing on Server OS
- Included SSU for Windows Server 2016 as it's mandatory
- Added some error checking for Server 2019 and 2022 CU installations when CU fails due to lack of SSU. If you run into this error, you're using old media and should use the latest. Always use the latest ISO if you can.
2024-10-04 14:58:21 -07:00
JonasKloseBW f09c404f65 Update BuildFFUVM.ps1
- Find better results for Windows Server 2019 .NET Framework updates
2024-10-03 03:47:33 +02:00
JonasKloseBW fbe8eca263 Update Search Strings: Update BuildFFUVM.ps1
- Update search strings for Windows / .NET Framework updates to get more consistent and reliable results
2024-10-02 15:05:41 +02:00
JonasKloseBW 923e8b070d Merge branch '2410.1' into 2410.1-Allow-VHDX-caching 2024-10-01 03:46:04 +02:00
rbalsleyMSFT e6e53e566f Merge pull request #84 from JonasKloseBW/2410.1
Add support for Windows Server in 2410.1 branch
2024-09-30 10:31:42 -07:00
JonasKloseBW f144f1d71c Update CaptureFFU.ps1
- Add support for Server Core in SKU name
2024-09-30 16:52:15 +02:00
JonasKloseBW 3694e1a6e4 Update BuildFFUVM.ps1
- Add parameter $AllowVHDXCaching
- Adds the ability to cache VHDX files together with their configuration
- This should roughly cut the build time in half as long as there are no new patches released since the last cached VHDX file
2024-09-30 15:44:40 +02:00
JonasKloseBW d45b6dc8dc Update BuildFFUVM.ps1
- improve Optimize-FFUCaptureDrive
- use the drive letter that the Windows partition gets after mounting the vhdx file
2024-09-30 14:14:33 +02:00
JonasKloseBW 5194133a78 Update BuildFFUVM.ps1
- Add help for parameter AppsScriptVariables
2024-09-27 18:34:41 +02:00
JonasKloseBW 6e5d634af6 Update BuildFFUVM.ps1
- Bypass VMSwitchIPAddress to VMHostAddress check on systems with a configured NAT setup
2024-09-27 02:15:25 +02:00
JonasKloseBW 32d5ff3b47 Merge branch 'rbalsleyMSFT:2410.1' into 2410.1 2024-09-26 20:11:45 +02:00
JonasKloseBW 5545554d7e Update BuildFFUVM.ps1
- Fix accidental variable accumulation in InstallAppsandSysprep.cmd
2024-09-26 20:08:47 +02:00
JonasKloseBW 6a0faa958e Update InstallAppsandSysprep.cmd 2/2
- Add parameter $AppsScriptVariablesvariable
- Allow value based behavior changes during the app install phase in InstallAppsandSysprep.cmd
2024-09-26 17:16:22 +02:00
JonasKloseBW 15c0478710 Update BuildFFUVM.ps1 1/2
- Add parameter $AppsScriptVariablesvariable
- Allow value based behavior changes during the app install phase in InstallAppsandSysprep.cmd
2024-09-26 17:15:17 +02:00
rbalsleyMSFT bab9804022 Merge pull request #79 from zehadialam/2410.1
Include Latest Windows Malicious Software Removal Tool
2024-09-24 14:28:23 -07:00
Zehadi Alam c93c417dba Removed Get-MSRTUrl function and use Microsoft Update Catalog to retrieve latest MSRT 2024-09-23 23:42:09 -04:00
JonasKloseBW 2fe91de000 Merge branch 'main' into 2410.1 2024-09-23 11:27:52 +02:00
JonasKloseBW 412e3a078c Update CaptureFFU.ps1
- Add Windows Server support like in BuildFFUVM.ps1
2024-09-23 04:37:09 +02:00
JonasKloseBW b6dda55a82 Update BuildFFUVM.ps1
- Updated the .NET Framework download code
- Download the appropriate .NET Framework for Windows Server
2024-09-23 04:29:04 +02:00
JonasKloseBW b8bda93e8d Update BuildFFUVM.ps1
- Updated MU Catalog search
- Search now includes searching for Windows Server updates

Has been verified to work for Windows Server 2022 and Windows Server 2025 only.
2024-09-23 04:26:30 +02:00
JonasKloseBW ac485f9c87 Update BuildFFUVM.ps1
- Update Get-WindowsVersionInfo
- Server Standard is now called 'Srv_Std'
- Server Datacenter is now called 'Srv_Dtc'
- 17763 is matched as Windows Server 2019
- 20348 is matched as Windows Server 2022
- 26100 is matched as Windows Server 2025
- other versions are matched as $DisplayVersion as a fallback

Please remember to update the Windows Server version of 2025 in case it changes until release.
2024-09-23 04:16:57 +02:00
JonasKloseBW 4b33627d19 Update BuildFFUVM.ps1
- Fix bug in New-OSPartition
- CompactOS is now avoided on Windows Server
2024-09-23 04:11:15 +02:00
JonasKloseBW af28624e2d Update BuildFFUVM.ps1
- Update Get-Index to support processing Windows Server images
2024-09-23 04:08:01 +02:00
JonasKloseBW 3457aedf5d Update BuildFFUVM.ps1
- Add support for searching Windows Server SKUs in images in Get-WimIndex
2024-09-23 04:04:13 +02:00
JonasKloseBW 5acac4ba5b Update BuildFFUVM.ps1
- Update Get-LatestWindowsKB to support searching for Windows Server updates
- Improve the HTML regex to return a more precise match by using the $WindowsRelease variable for lookbehind based searching
2024-09-23 04:02:28 +02:00
JonasKloseBW 0b151f9054 Update BuildFFUVM.ps1
- Throw error when trying to download Windows Server as it's not possible
2024-09-23 03:55:37 +02:00
JonasKloseBW cafc45dbba Update BuildFFUVM.ps1
- Add Dell driver download support for Windows Server 2016, 2022 and fall back to 2022 drivers for other Server versions.
2024-09-23 03:53:45 +02:00
JonasKloseBW e3cbcab6b2 Update BuildFFUVM.ps1
- Add script parameters to allow Windows Server image creation
2024-09-23 03:41:40 +02:00
Zehadi Alam ec7e9a546c Adjust pattern for URL scraping 2024-09-17 21:08:09 -04:00
Zehadi Alam 7a2aab3204 Adjust install command for MSRT 2024-09-17 20:36:22 -04:00
rbalsleyMSFT 5dcdd2c36f Clean up the Get-MicrosoftDrivers old code and version change 2024-09-17 14:03:43 -07:00
rbalsleyMSFT fb0a630bfd Merge pull request #78 from rbalsleyMSFT/main
Merge main to 2410.1
2024-09-17 13:58:55 -07:00
rbalsleyMSFT 47cd0deb03 Merge pull request #77 from rbalsleyMSFT/2409.2
2409.2
2024-09-17 13:54:58 -07:00
rbalsleyMSFT 378941cd5c Two fixes
- Fixed an issue with UWP apps downloaded via Winget weren't being fully installed. Added /StubPackageOption:installfull to the dism command
- Fixed an issue with Surface Drivers not downloading
2024-09-17 13:50:16 -07:00
Zehadi Alam 1da28024cc Add support for updating latest Windows Malicious Software Removal Tool 2024-09-15 00:41:04 -04:00
rbalsleyMSFT 480e6a62b6 Merge pull request #74 from w0/main
Added support for relative paths
2024-09-12 12:32:22 -07:00
w0 807456de86 removed unused variable. more format. 2024-09-12 13:57:58 -05:00
w0 c8ef42ab21 Update USBImagingToolCreator.ps1
added support for relative paths. formatted script and removed functions from inside if statement.
2024-09-12 13:54:58 -05:00
rbalsleyMSFT 60d147c71d Update README.md 2024-09-10 11:45:44 -07:00
rbalsleyMSFT cd36150ddc Merge pull request #71 from rbalsleyMSFT/2409.1
2409.1
2024-09-10 11:44:49 -07:00
rbalsleyMSFT 198a544dbb update change log 2024-09-10 11:44:12 -07:00
rbalsleyMSFT 40616776eb - Added VMHostIPAddress and VMSwitchName validation to validate the IP address matches the VMSwitchName 2024-09-07 09:53:14 -07:00
rbalsleyMSFT 20c9cf8ab3 Merge pull request #65 from HedgeComp/Time-to-Complete-Hours
Time To Complete Shows Hours if Needed
2024-09-06 11:26:54 -07:00
rbalsleyMSFT 17558f86aa Merge pull request #64 from HedgeComp/OneDrive-Silent
Silently Install Onedrive
2024-09-06 11:26:15 -07:00
rbalsleyMSFT 7408dbb435 Merge branch '2409.1' of https://github.com/rbalsleyMSFT/FFU into 2409.1 2024-09-06 11:24:21 -07:00
rbalsleyMSFT 9c1fc59af9 - Added new variables for the PPKG, Unattend, Autopilot, and PEDrivers validation 2024-09-06 11:24:16 -07:00
HedgeComp 31c785b5da Update BuildFFUVM.ps1
Add Hours to Total Time to complete only if greater than 1 hour
2024-09-06 13:00:09 -04:00
HedgeComp 5b93135ebb Update BuildFFUVM.ps1
Add Silent switch install to Onedrivesetup.exe
2024-09-06 12:57:36 -04:00
rbalsleyMSFT 5f4cf0c66e Merge pull request #60 from zehadialam/2409.1
Fix for Missing Windows Boot Manager Entry
2024-09-06 09:34:11 -07:00
Zehadi Alam ddbf2b0339 Use bcdedit to set Windows Boot Manager and default Windows boot loader to be first in the display order of UEFI firmware 2024-09-05 17:57:35 -04:00
rbalsleyMSFT e62d481405 - Remove ValidateScript on InstallDrivers and break it out in a validation block so -Make and -Model can be specified anywhere in the command line
- Check for Prefixes.txt file and copy to the USB drive if it exists
- Perform better validation for PPKG, Unattend, Autopilot json, and drivers
- Comment out the Windows Security Platform update as the file has been removed from the MU Catalog.
2024-09-04 17:05:06 -07:00
rbalsleyMSFT 6c07ac8595 Merge branch '2409.1' of https://github.com/rbalsleyMSFT/FFU into 2409.1 2024-09-04 13:20:38 -07:00
rbalsleyMSFT 7d74feec0c - Fix an issue with removal of Defender/OneDrive/Edge after FFU is complete
- 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
2024-09-04 13:20:35 -07:00
rbalsleyMSFT 6b2a4bcb27 Merge pull request #51 from HedgeComp/2408.2
Allow Preview CU update
2024-09-04 13:08:58 -07:00
rbalsleyMSFT 6da9ece0d8 Merge pull request #54 from w0/main
use ValidateSet for WindowsSKU
2024-08-15 18:59:01 -07:00
w0 dc4438dcf9 use ValidateSet for WindowsSKU 2024-08-15 20:11:41 -05:00
rbalsleyMSFT e250e2a130 Changed some logging when winget apps can't be found 2024-08-13 16:11:36 -07:00
Doctair dad51fdf80 updated Docs to relect new $UpdatePreviewCU Parameter 2024-08-12 13:15:16 -04:00
Doctair d60b0301c5 Remove a temp copy of BUildScript 2024-08-12 10:15:45 -04:00
Doctair db3e09650a Add new Parameter for Installing Preview CU from
Mircosoft Update Catalog. Recent Windows Pro
not Auto Activating to Enterprise License Bug speared
this idea as its resoleve in lastes Prieview CU.

Parameter is default $False but if set to $true will install
Preivew CU and take precendence over $UpdateLastestCU.
2024-08-12 10:07:41 -04:00
rbalsleyMSFT bcb9911cd0 Small update to fix a logging issue with script run time duration 2024-08-07 13:01:26 -07:00
13 changed files with 2512 additions and 706 deletions
+223
View File
@@ -1,5 +1,228 @@
# Change Log # Change Log
# 2505.1
Highly recommended that you upgrade to this release. Fixes the issue with the May 2025 cumulative update and some SKU naming issues for SKUs other than Pro.
# Support for Windows LTSB/LTSC
Thanks to @zehadialam for the code to allow support for LTSB and LTSC. This has been a requested feature from a number of customers and some might be opting for LTSC when Windows 10 support ends in October. We support LTSB 2016, LTSC 2019, 2021, 2024 including the N and IoT variants. Extensive testing has gone into validating CU and .net support. File an issue if you see any weird behavior.
# Support for automating computer naming via CSV
Thanks to @JonasKloseBW for PR #150
- 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
# Fixes
- Thanks to @JonasKloseBW for PR #129 for adding the -AppListPath parameter
- 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 (EDU mainly, but others too)
- Fix an issue with checkpoint CUs and May 2025-05B CU. Should future proof new checkpoint CUs in the future.
# Additional Fixes
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
# 2412.1
This is a major release with a number of quality-of-life improvements that will reduce the time it takes to create FFUs. I highly recommend you update to this release.
## Windows Server Support
Thanks to [JonasKloseBW](https://github.com/JonasKloseBW) we have added support for Windows Server! This includes support for Windows Server 2016 through 2025 and supports both core and desktop experience. It will require you to provide your own Server ISO
using the `-ISOPath` parameter since we can't automatically download it like we can with client. You also will want to set the `-WindowsSKU` parameter to either `'Standard', 'Datacenter', 'Standard (Desktop Experience)', or 'Datacenter (Desktop Experience)'` depending on your needs.
Cumulative Updates for Windows and .NET should work as expected. Defender updates should work too. If you notice anything that doesn't work, open an issue.
## VHDX Caching Support
Thanks again to Jonas for adding VHDX caching support #89. For those of you that might be making many FFUs for different configurations, instead of building the VHDX every time, you can cache the VHDX and re-use it for your next build. In testing, this seems to save about 10 minutes, depending on how you're installing Windows (via MCT download, or your own ISO and how old your media is).
The way this works is a VHDXCache folder is created in the FFUDevelopment folder. If `-AllowVHDXCaching $true`, we store the VHDX file and a config file that keeps track of the following info
```
{
"VhdxFileName": "_FFU-808829869.vhdx",
"LogicalSectorSizeBytes": 512,
"WindowsSKU": "Pro",
"WindowsRelease": "11",
"WindowsVersion": "24H2",
"OptionalFeatures": "",
"IncludedUpdates": [
{
"Name": "windows11.0-kb5043080-x64_953449672073f8fb99badb4cc6d5d7849b9c83e8.msu"
},
{
"Name": "windows11.0-kb5045934-x64-ndp481_fa9c3adfb0532eb8f4e521f4fb92a179380184c5.msu"
},
{
"Name": "windows11.0-kb5048667-x64_d4ad0ca69de9a02bc356757581e0e0d6960c9f93.msu"
}
]
}
```
The VHDX files are cached before boot, so they've never been sysprepped. On subsequent runs, if `-AllowVHDXCaching $true` is set, we search the VHDXCache folder, loop through any config files, and look to see if we find one that matches the build information you've passed to the script. If a match is found, robocopy copies in the VHDX and uses the cached VHDX to build the FFU VM.
## Configuration File Support
A configuration file can now be used to configure the parameters in lieu of, or in conjunction with, parameters specified on the command line. Configuration files are especially helpful for those making FFUs for different models, Windows releases, application sets, and more.
To use, run:
`.\BuildFFUVM.ps1 -ConfigFile 'C:\FFUDevelopment\config\Sample_default.json' -verbose`
### Creating your own Configuration Json file
If you have a command line that youve been using for awhile and would like to convert it to a json file automatically, run your command line like normal, adding
`-exportConfigFile 'C:\FFUDevelopment\config\YourConfigFile.json'`
to the end of the command. Doing this will generate a well-formatted json file with your configuration settings.
You can also temporarily overwrite parameters while using a config file. Using the following sample command:
`.\BuildFFUVM.ps1 -ConfigFile 'C:\FFUDevelopment\config\Sample_default.json' -verbose`
If youd like to not include Office (the Sample_default.json file installs Office), youd add `-InstallOffice $False` to the command line
`.\BuildFFUVM.ps1 -ConfigFile 'C:\FFUDevelopment\config\Sample_default.json' -verbose -InstallOffice $False`
Doing this will temporarily overwrite whatever is in the json for the `InstallOffice` parameter. It will not modify the json file. If you would like to change the json file, you can add `-exportConfigFile 'C:\FFUDevelopment\config\Sample_default.json'` and that will overwrite the json file with the new parameter.
`.\BuildFFUVM.ps1 -ConfigFile 'C:\FFUDevelopment\config\Sample_default.json' -verbose -InstallOffice $False -exportConfigFile 'C:\FFUDevelopment\config\Sample_default.json'`
## Custom FFU Naming Support
Thanks to Jonas, we now have custom FFU naming support. A new parameter -CustomFFUNameTemplate has been added.
This parameter sets a custom FFU output name with placeholders. Allowed placeholders are:
`{WindowsRelease}, {WindowsVersion}, {SKU}, {BuildDate}, {yyyy}, {MM}, {dd}, {H}, {hh}, {mm}, {tt}`
And below is a description of what to expect when you use each placeholder.
```
{WindowsRelease} = 10, 11, 2016, 2019, 2022, 2025
{WindowsVersion} = 1607, 1809, 21h2, 22h2, 23h2, 24h2, etc
{SKU} = Home, Home N, Home Single Language, Education, Education N, Pro, Pro N, Pro Education, Pro Education N, Pro for Workstations, Pro N for Workstations, Enterprise, Enterprise N, Standard, Standard (Desktop Experience), Datacenter, Datacenter (Desktop Experience)
{BuildDate} = e.g. Dec2024
{yyyy} = e.g. 2024
{MM} = 2 digit month format (e.g. 12 for December)
{dd} = Day of the month in 2 digit format (19)
{HH} = Current hour in 24-hour format (e.g., 14 for 2 PM)
{hh} = Current hour in 12-hour format (e.g., 02 for 2 PM)
{mm} = Current minute in 2-digit format (e.g., 09)
{tt} = Current AM/PM designator (e.g., AM or PM)
```
An example for Windows 11 24h2 Pro built today would be:
`-CustomFFUNameTemplate '{WindowsRelease}_{WindowsVersion}_{SKU}_{yyyy}-{MM}-{dd}_{HH}{mm}'`
Would result in a FFU file name of:
`Win11_24h2_Pro_2024-12-20_1225.ffu`
You can also mix in static text in the name
`-CustomFFUNameTemplate '{WindowsRelease}_{WindowsVersion}_{SKU}_Office_{yyyy}-{MM}-{dd}_{HH}{mm}'`
Would result in:
`Win11_24h2_Pro_Office_2024-12-20_1225.ffu`
## Additional PRs added
#79 Includes the latest Microsoft Software Removal Tool from `@zehadialam` - use `-UpdateLatestMSRT $true`
#72 Includes some Unattend Sample files from @HedgeComp in the `$FFUDevelopment\Unattend` folder
#74 Includes some improvements to the USBImagingToolCreator.ps1 file from @w0
#103 Includes some additional improvements to the USBImagingToolCreator.ps1 file from @MKellyCBSD
## Misc Fixes
- Added server skus to validateset for $WindowsSKU
- Added new variable $installationType which uses $WindowsRelease to determine Server or Client. If $installationType is Server, $WindowsRelease version is used to set $WindowsVersion to the appropriate version (1607, 1809, 21H2)
- Fixed an issue where the recovery partition wouldn't be created on server OSes due to winre.wim being hidden. Never saw this on client OSes even though it also was hidden IIRC.
- Removed verbosity for Optimize-Volume as it was outputting when -verbose was not specified.
- Modified some search strings for .NET CUs when installing on Server OS
- Included SSU for Windows Server 2016 as it's mandatory
- Added some error checking for Server 2019 and 2022 CU installations when CU fails due to lack of SSU. If you run into this error, you're using old media and should use the latest. Always use the latest ISO if you can.
- $WindowsVersion set to 24h2, can override by using -WindowsVersion 23H2 if you want the old behavior
- Removed the "Downloading information GUID" messages when downloading content from the Microsoft Update Catalog while -verbose was specified in the command line
- In Get-KBLink, made a change to just grab the first result returned instead of the entire results page. This removes the need to use a break statement in Save-KB when downloading updates. This fixed an issue with the new 24H2 Checkpoint Cumulative Updates in Win11 and Server 2025.
- Changed Windows MSRT search string for x64 and x86. This was mainly to get x64 to the top of the search results. x86 won't actually download since the code isn't in place for content from the MU Catalog to download x86 content (no idea if anyone actually builds x86 FFUs for Win10 - I hope not)
- If not passing an ISO, hardcoded WindowsVersion of 22H2 for Windows 10 or 24H2 for Windows 11 since the ESD media only provides those two versions. Not doing this allowed for unnecessary VHDX creation since it checks the WindowsVersion via the json file. This also fixes an issue where CUs could be searched for that didnt exist, but the media would still download
- Added some additional logging entries
- Removed verbose output of the Optimize-Volume command
- Fixed an issue where not passing an ISO caused the script to fail
- Cleaned up the KBPath folder at the end of the run
- Changed some minor formatting items
- Added Get-Childprocesses function to return child processes of parent process
- Added a new -Wait boolean parameter to Invoke-Process function. This is to control whether Invoke-Process should wait in order to track stdout and stderr output. This is needed for processes that may hang, waiting for user input and there isn't a way to bypass (some Intel drivers provided by Dell leave dialog windows even when running silently)
-Invoke-Process now returns process information (returns $cmd). This allows for process tracking when calling the function.
- Since Invoke-Process now returns the process information, also needed to add Out-Null to the majority of the Invoke-Process references to prevent Invoke-Process from writing to the terminal
- Refactored a lot of the Get-DellDrivers function due to inconsistencies with how driver extraction behaves between client and server devices. For client, /s /e seemed to work fine, but for server it would only extract the driver installer content and other dell related files, rather than the driver files themselves. We have since switched to using /s /drivers= which will extract the driver content. Not all drivers support /drivers= and may output some information to the terminal that looks like help documentation. If a driver doesn't support /drivers, the script falls back to using /s /e to do the extraction. If this doesn't work for you, you can always provide your own drivers that you manually download from Dell's website.
- Updated Malicious Software Removal Tool (MSRT) code to handle Windows Server
- Refactored the Get-ODTURL function to fix recent download issues. Also added some better error handling
- Moved the odtsetup.exe download to the FFUDevelopment folder and will clean it up after office has downloaded
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 where ever you want. Prior it required that the computername was the first component element.
## **2409.1**
### Fixes
- Fix an issue with removal of Defender/OneDrive/Edge after FFU is complete
- Migrate Winget downloads to use [Export-WingetPackage cmdlet](https://github.com/microsoft/winget-cli/blob/master/doc/specs/%23658%20-%20WinGet%20Download.md#winget-powershell-cmdlet) as per issue #50
- Add support for preview updates https://github.com/rbalsleyMSFT/FFU/pull/51 - thanks to @HedgeComp
- Refactor validation of Unattend/prefixes, PPKG, Autopilot to check for these files early in the process, similar to how we check for drivers
- Add better logging when unable to find HDD when applying FFU. Will inform to add WinPE drivers to Deployment Media if HDD not found.
- Remove ValidateScript on InstallDrivers and break it out in a validation block so -Make and -Model can be specified anywhere in the command line
- Add validation for VMHostIPAddress and VMSwtichName and inform the user if these don't match. Should prevent issues where the FFU isn't getting created.
- Removed installation of the Windows Security Platform Update as it has been removed from the MU Catalog. See issue #58
- Thanks to w0 for PR #54 to change the validation set for WindowsSKU
- Thanks to @zehadialam for PR #60 to fix an issue with Windows boot loader for certain devices where Windows Boot Manager is not the first boot entry after the FFU is applied.
- Thanks to @HedgeComp for PR #64 and PR #65
## **2408.1** ## **2408.1**
### External Drive Support ### External Drive Support
@@ -5,9 +5,12 @@ REM d:\Office\setup.exe /configure d:\office\DeployFFU.xml
REM Install Defender Platform Update REM Install Defender Platform Update
REM Install Defender Definitions REM Install Defender Definitions
REM Install Windows Security Platform Update REM Install Windows Security Platform Update
REM Install Windows Malicious Software Removal Tool
REM Install OneDrive Per Machine REM Install OneDrive Per Machine
REM Install Edge Stable REM Install Edge Stable
REM Winget Win32 Apps REM Winget Win32 Apps
REM START Batch variables placeholder
REM END Batch variables placeholder
REM Add additional apps below here REM Add additional apps below here
REM Contoso App (Example) REM Contoso App (Example)
REM msiexec /i d:\Contoso\setup.msi /qn /norestart REM msiexec /i d:\Contoso\setup.msi /qn /norestart
@@ -30,11 +33,8 @@ for /d %%D in ("%basepath%\*") do (
) )
) )
) )
@REM for %%F in ("!appfolder!\*.xml") do (
@REM set "licensefile=%%F"
@REM )
if defined mainpackage ( if defined mainpackage (
set "dism_command=DISM /Online /Add-ProvisionedAppxPackage /PackagePath:"!mainpackage!"" set "dism_command=DISM /Online /Add-ProvisionedAppxPackage /PackagePath:"!mainpackage!" /Region:all /StubPackageOption:installfull"
if exist "!dependenciesfolder!" ( if exist "!dependenciesfolder!" (
for %%G in ("!dependenciesfolder!\*") do ( for %%G in ("!dependenciesfolder!\*") do (
set "dism_command=!dism_command! /DependencyPackagePath:"%%G"" set "dism_command=!dism_command! /DependencyPackagePath:"%%G""
@@ -48,7 +48,6 @@ for /d %%D in ("%basepath%\*") do (
) else ( ) else (
set "dism_command=!dism_command! /SkipLicense" set "dism_command=!dism_command! /SkipLicense"
) )
set "dism_command=!dism_command! /Region:All"
echo !dism_command! echo !dism_command!
!dism_command! !dism_command!
) )
File diff suppressed because it is too large Load Diff
Binary file not shown.
+54 -33
View File
@@ -4,22 +4,34 @@ param(
$DeployISOPath, $DeployISOPath,
[Switch]$DisableAutoPlay [Switch]$DisableAutoPlay
) )
$Host.UI.RawUI.WindowTitle = 'USB Imaging Tool Creator' $Host.UI.RawUI.WindowTitle = 'Imaging Tool USB Creator'
if($DeployISOPath){ if($DeployISOPath){
$DevelopmentPath = $DeployISOPath | Split-Path $DevelopmentPath = $DeployISOPath | Split-Path
$ImagesPath = "$DevelopmentPath\FFU"
function WriteLog($LogText) { function WriteLog($LogText) {
$LogFileName = '\Script.log' $LogFileName = '\Script.log'
$LogFile = $DevelopmentPath + $LogFilename $LogFile = $DevelopmentPath + $LogFilename
Add-Content -path $LogFile -value "$((Get-Date).ToString()) $LogText" -Force -ErrorAction SilentlyContinue Add-Content -path $LogFile -value "$((Get-Date).ToString()) $LogText" -Force -ErrorAction SilentlyContinue
Write-Verbose $LogText Write-Verbose $LogText
} }
Function Get-USBDrive {
$USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") function Write-ProgressLog {
If ($USBDrives -and ($null -eq $USBDrives.count)) { param(
$USBDrivesCount = 1 [string]$Activity,
[string]$Status
)
Write-Progress -Activity $Activity -Status $Status -PercentComplete (($currentStep / $totalSteps) * 100)
WriteLog $Status
$script:currentStep++
} }
else { Function Get-RemovableDrive {
writelog "Get information for all removable drives"
$USBDrives = Get-WmiObject Win32_DiskDrive | Where-Object {$_.MediaType -eq "Removable media"}
If($USBDrives -and ($null -eq $USBDrives.count)) {
$USBDrivesCount = 1
} else {
$USBDrivesCount = $USBDrives.Count $USBDrivesCount = $USBDrives.Count
} }
WriteLog "Found $USBDrivesCount USB drives" WriteLog "Found $USBDrivesCount USB drives"
@@ -27,20 +39,23 @@ Function Get-USBDrive {
if ($null -eq $USBDrives) { if ($null -eq $USBDrives) {
WriteLog "No removable USB drive found. Exiting" WriteLog "No removable USB drive found. Exiting"
Write-Error "No removable USB drive found. Exiting" Write-Error "No removable USB drive found. Exiting"
Pause
exit 1 exit 1
} }
return $USBDrives, $USBDrivesCount return $USBDrives, $USBDrivesCount
} }
Function Build-DeploymentUSB{ Function Build-DeploymentUSB{
param( param(
[Array]$Drives [Array]$Drives
) )
writelog "Checking if ffu files are present in the ffu folder" writelog "Creating list of FFU image files"
$Images = Get-ChildItem -Path $FFUPath -Filter "*.ffu" -File -Recurse $Images = Get-ChildItem -Path $ImagesPath -Filter "*.ffu" -File -Recurse
writelog "Checking if drivers are present in the drivers folder" writelog "Checking if drivers are present in the drivers folder"
$Drivers = Get-ChildItem -Path $DriversPath -Recurse $Drivers = Get-ChildItem -Path $DriversPath -Recurse
$DrivesCount = $Drives.Count $DrivesCount = $Drives.Count
Writelog "Creating partitions..." Write-ProgressLog "Create Imaging Tool" "Creating partitions..."
writelog "Create job to partition each usb drive"
foreach ($USBDrive in $Drives) { foreach ($USBDrive in $Drives) {
$DriveNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "") $DriveNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "")
$Model = $USBDrive.model $Model = $USBDrive.model
@@ -65,7 +80,7 @@ Function Build-DeploymentUSB{
if($DrivesCount -gt 1){ if($DrivesCount -gt 1){
writelog "Get file system information for all drives" writelog "Get file system information for all drives"
$Partitions = Get-Partition | Get-Volume $Partitions = Get-Partition | Get-Volume
}else{ } else {
writelog "Get file system information for drive number $DiskNumber" writelog "Get file system information for drive number $DiskNumber"
$Partitions = Get-Partition -DiskNumber $DriveNumber | Get-Volume $Partitions = Get-Partition -DiskNumber $DriveNumber | Get-Volume
} }
@@ -97,13 +112,21 @@ $Destination = $Drive + ":\"
[string]$SFolder, [string]$SFolder,
[string]$DFolder [string]$DFolder
) )
New-Item -Path $DFolder -ItemType Directory -Force -Confirm: $false | Out-Null
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
} }
WriteLog "Start job to copy all FFU files to $Destination" WriteLog "Start job to copy all FFU files to $Destination"
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $FFUPath, $Destination | Out-Null Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $ImagesPath, $Destination | Out-Null
} }
} }
if(!($Images)){
foreach ($Drive in $DeployDrives) {
WriteLog "Create images directory"
$drivepath = $Drive + ":\"
New-Item -Path "$drivepath" -Name Images -ItemType Directory -Force -Confirm: $false | Out-Null
}
}
if($Drivers){ if($Drivers){
writelog "Copying driver files to all drives labeled deploy concurrently" writelog "Copying driver files to all drives labeled deploy concurrently"
foreach ($Drive in $DeployDrives) { foreach ($Drive in $DeployDrives) {
@@ -128,14 +151,14 @@ if(!($Drivers)){
} }
} }
if($DrivesCount -gt 1){ if($DrivesCount -gt 1){
Writelog "Building $DrivesCount drives concurrently...Please be patient..." Write-ProgressLog "Create Imaging Tool" "Building $DrivesCount drives concurrently...Please be patient..."
}else{ } else {
Writelog "Building the imaging tool on $model...Please be patient..." Write-ProgressLog "Create Imaging Tool" "Building the imaging tool on $model...Please be patient..."
} }
Get-Job | Wait-Job | Out-Null Get-Job | Wait-Job | Out-Null
Dismount-DiskImage -ImagePath $DeployISOPath | Out-Null Dismount-DiskImage -ImagePath $DeployISOPath | Out-Null
Writelog "Drive creation jobs completed..." Write-ProgressLog "Create Imaging Tool" "Drive creation jobs completed..."
} }
Function New-DeploymentUSB { Function New-DeploymentUSB {
@@ -154,7 +177,7 @@ Function New-DeploymentUSB {
$DriveSize = [math]::round($Drives[$i].size/1GB, 2) $DriveSize = [math]::round($Drives[$i].size/1GB, 2)
$DiskNumber = $Drives[$i].DeviceID.Replace("\\.\PHYSICALDRIVE", "") $DiskNumber = $Drives[$i].DeviceID.Replace("\\.\PHYSICALDRIVE", "")
$Properties = [ordered]@{Number = $i + 1 ; DriveNumber = $DiskNumber ; DriveModel = $driveModel ; 'Size (GB)' = $DriveSize} $Properties = [ordered]@{Number = $i + 1 ; DriveNumber = $DiskNumber ; DriveModel = $driveModel ; 'Size (GB)' = $DriveSize}
$Drivelist += New-Object PSObject -Property $Properties $Drivelist += New-Object PSObject -Property $Properties
} }
if($Count -gt 1){ if($Count -gt 1){
@@ -167,20 +190,15 @@ Function New-DeploymentUSB {
$var = $true $var = $true
$DriveSelected = Read-Host 'Enter the drive number to apply the .iso to' $DriveSelected = Read-Host 'Enter the drive number to apply the .iso to'
$DriveSelected = ($DriveSelected -as [int]) -1 $DriveSelected = ($DriveSelected -as [int]) -1
if($Last){ writelog "Drive $DriveSelected selected"
writelog "All drives selected"
}else{
writelog "Drive $DriveSelected selected"}
} }
catch {
catch {
Write-Host 'Input was not in correct format. Please enter a valid FFU number' Write-Host 'Input was not in correct format. Please enter a valid FFU number'
$var = $false $var = $false
} }
} until (($DriveSelected -le $Count -1 -or $last) -and $var) } until (($DriveSelected -le $Count -1 -or $last) -and $var)
if($DisableAutoPlay){
$DisableAutoPlayCurrentSetting = (Get-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name DisableAutoplay).DisableAutoplay
if($DisableAutoPlay -and $DisableAutoPlayCurrentSetting -ne 1){
writelog "Disable autoPlay current setting is $DisableAutoPlayCurrentSetting"
WriteLog "Setting the registry key to disable autoplay for all drives" WriteLog "Setting the registry key to disable autoplay for all drives"
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value 1 -Type DWORD Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value 1 -Type DWORD
} }
@@ -193,16 +211,16 @@ Function New-DeploymentUSB {
if($Selection -eq $last){ if($Selection -eq $last){
Read-Host -Prompt "ALL DRIVES SELECTED! WILL ERASE ALL CURRENTLY CONNECTED USB DRIVES!! Press ENTER to continue" Read-Host -Prompt "ALL DRIVES SELECTED! WILL ERASE ALL CURRENTLY CONNECTED USB DRIVES!! Press ENTER to continue"
Build-DeploymentUSB -Drives $Drives Build-DeploymentUSB -Drives $Drives
}else{ } else {
Read-Host -Prompt "Drive number $Selection was selected. Press ENTER to continue" Read-Host -Prompt "Drive number $Selection was selected. Press ENTER to continue"
Build-DeploymentUSB -Drives $Drives[$DriveSelected] Build-DeploymentUSB -Drives $Drives[$DriveSelected]
} }
WriteLog "Setting the registry key to re-enable autoplay for all drives" WriteLog "Setting the registry key to re-enable autoplay for all drives"
if($DisableAutoPlay){ if($DisableAutoPlay){
Writelog "Setting disable autoplay setting back to $DisableAutoPlayCurrentSetting" Write-ProgressLog "Create Imaging Tool" "Enabling Autoplay"
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value $DisableAutoPlayCurrentSetting -Type DWORD Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value 0 -Type DWORD
} }
Writelog "Completed!" Write-ProgressLog "Create Imaging Tool" "Completed!"
} }
#Get USB Drive and create log file #Get USB Drive and create log file
if(Test-Path "$DevelopmentPath\Script.log"){ if(Test-Path "$DevelopmentPath\Script.log"){
@@ -211,12 +229,15 @@ New-item -Path $DevelopmentPath -Name 'Script.log' -ItemType "file" -Force | Out
} }
WriteLog 'Begin Logging' WriteLog 'Begin Logging'
WriteLog 'Getting USB drive information and usb drive count' WriteLog 'Getting USB drive information and usb drive count'
$USBDrives,$USBDrivesCount = Get-USBDrive $USBDrives,$USBDrivesCount = Get-RemovableDrive
WriteLog 'Setting first step for percentage progress bar'
$currentStep = 1
New-DeploymentUSB -Drives $USBDrives -Count $USBDrivesCount New-DeploymentUSB -Drives $USBDrives -Count $USBDrivesCount
read-host -Prompt "USB drive creation complete. Press ENTER to exit" read-host -Prompt "USB drive creation complete. Press ENTER to exit"
Exit Exit
}else{ } else {
Write-Host "No .ISO file selected..." Write-Host "No .ISO file selected..."
read-host "Press ENTER to Exit..." read-host "Press ENTER to Exit..."
Exit Exit
@@ -1,6 +1,6 @@
#Modify the net use W: \\192.168.1.158\FFUCaptureShare /user:ffu_user ddb1f077-3eed-433c-b4d9-7b8cd54ce727 #Modify the net use W: \\192.168.1.158\FFUCaptureShare /user:ffu_user ddb1f077-3eed-433c-b4d9-7b8cd54ce727
net use W: \\192.168.1.158\FFUCaptureShare /user:ffu_user ddb1f077-3eed-433c-b4d9-7b8cd54ce727 net use W: \\192.168.1.158\FFUCaptureShare /user:ffu_user ddb1f077-3eed-433c-b4d9-7b8cd54ce727
#Custom naming placeholder
$AssignDriveLetter = 'x:\AssignDriveLetter.txt' $AssignDriveLetter = 'x:\AssignDriveLetter.txt'
Start-Process -FilePath diskpart.exe -ArgumentList "/S $AssignDriveLetter" -Wait -ErrorAction Stop | Out-Null Start-Process -FilePath diskpart.exe -ArgumentList "/S $AssignDriveLetter" -Wait -ErrorAction Stop | Out-Null
#Load Registry Hive #Load Registry Hive
@@ -11,53 +11,102 @@ reg load "HKLM\FFU" $Software
$SKU = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'EditionID' $SKU = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'EditionID'
[int]$CurrentBuild = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'CurrentBuild' [int]$CurrentBuild = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'CurrentBuild'
$DisplayVersion = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'DisplayVersion' $InstallationType = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'InstallationType'
if ($CurrentBuild -notin 14393, 17763 -and $InstallationType -ne "Server") {
$WindowsVersion = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'DisplayVersion'
}
# For Windows 10 LTSB 2016, set WindowsVersion to 2016
if ($CurrentBuild -eq 14393 -and $InstallationType -eq "Client") {
$WindowsVersion = '2016'
}
# For Windows 10 LTSC 2019, set WindowsVersion to 2019
if ($CurrentBuild -eq 17763 -and $InstallationType -eq "Client") {
$WindowsVersion = '2019'
}
$BuildDate = Get-Date -uformat %b%Y $BuildDate = Get-Date -uformat %b%Y
$SKU = switch ($SKU) { $SKU = switch ($SKU) {
Core { 'Home' } Core { 'Home' }
CoreN { 'HomeN'} CoreN { 'Home_N' }
CoreSingleLanguage { 'HomeSL'} CoreSingleLanguage { 'Home_SL' }
Professional { 'Pro' } Professional { 'Pro' }
ProfessionalN { 'ProN'} ProfessionalN { 'Pro_N' }
ProfessionalEducation { 'Pro_Edu' } ProfessionalEducation { 'Pro_Edu' }
ProfessionalEducationN { 'Pro_EduN' } ProfessionalEducationN { 'Pro_Edu_N' }
Enterprise { 'Ent' } Enterprise { 'Ent' }
EnterpriseN { 'EntN'} EnterpriseN { 'Ent_N' }
EnterpriseS { 'Ent_LTSC' }
EnterpriseSN { 'Ent_N_LTSC' }
IoTEnterpriseS { 'IoT_Ent_LTSC' }
Education { 'Edu' } Education { 'Edu' }
EducationN { 'EduN'} EducationN { 'Edu_N' }
ProfessionalWorkstation { 'Pro_Wks' } ProfessionalWorkstation { 'Pro_Wks' }
ProfessionalWorkstationN { 'Pro_WksN' } ProfessionalWorkstationN { 'Pro_Wks_N' }
ServerStandard { 'Srv_Std' }
ServerDatacenter { 'Srv_Dtc' }
} }
if($CurrentBuild -ge 22000){ if ($InstallationType -eq "Client") {
$Name = 'Win11' if ($CurrentBuild -ge 22000) {
$WindowsRelease = 'Win11'
}
else {
$WindowsRelease = 'Win10'
}
} }
else{ else {
$Name = 'Win10' $WindowsRelease = switch ($CurrentBuild) {
26100 { '2025' }
20348 { '2022' }
17763 { '2019' }
14393 { '2016' }
Default { $WindowsVersion }
}
if ($InstallationType -eq "Server Core") {
$SKU += "_Core"
}
} }
#If Office is installed, modify the file name of the FFU if ($CustomFFUNameTemplate) {
#$Office = Get-childitem -Path 'M:\Program Files\Microsoft Office' -ErrorAction SilentlyContinue | Out-Null $CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{WindowsRelease}', $WindowsRelease
$Office = Get-childitem -Path 'M:\Program Files\Microsoft Office' -ErrorAction SilentlyContinue $CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{WindowsVersion}', $WindowsVersion
if($Office){ $CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{SKU}', $SKU
$ffuFilePath = "W:\$Name`_$DisplayVersion`_$SKU`_Office`_$BuildDate.ffu" $CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{BuildDate}', $BuildDate
$dismArgs = "/capture-ffu /imagefile=$ffuFilePath /capturedrive=\\.\PhysicalDrive0 /name:$Name$DisplayVersion$SKU /Compress:Default" $CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{yyyy}', (Get-Date -UFormat '%Y')
$CustomFFUNameTemplate = $CustomFFUNameTemplate -creplace '{MM}', (Get-Date -UFormat '%m')
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{dd}', (Get-Date -UFormat '%d')
} $CustomFFUNameTemplate = $CustomFFUNameTemplate -creplace '{HH}', (Get-Date -UFormat '%H')
else{ $CustomFFUNameTemplate = $CustomFFUNameTemplate -creplace '{hh}', (Get-Date -UFormat '%I')
$ffuFilePath = "W:\$Name`_$DisplayVersion`_$SKU`_Apps`_$BuildDate.ffu" $CustomFFUNameTemplate = $CustomFFUNameTemplate -creplace '{mm}', (Get-Date -UFormat '%M')
$dismArgs = "/capture-ffu /imagefile=$ffuFilePath /capturedrive=\\.\PhysicalDrive0 /name:$Name$DisplayVersion$SKU /Compress:Default" $CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{tt}', (Get-Date -UFormat '%p')
if($CustomFFUNameTemplate -notlike '*.ffu') {
$CustomFFUNameTemplate += '.ffu'
}
$dismArgs = "/capture-ffu /imagefile=W:\$CustomFFUNameTemplate /capturedrive=\\.\PhysicalDrive0 /name:$WindowsRelease$WindowsVersion$SKU /Compress:Default"
} else {
#If Office is installed, modify the file name of the FFU
#$Office = Get-childitem -Path 'M:\Program Files\Microsoft Office' -ErrorAction SilentlyContinue | Out-Null
$Office = Get-ChildItem -Path 'M:\Program Files\Microsoft Office' -ErrorAction SilentlyContinue
if ($Office) {
$ffuFilePath = "W:\$WindowsRelease`_$WindowsVersion`_$SKU`_Office`_$BuildDate.ffu"
} else {
$ffuFilePath = "W:\$WindowsRelease`_$WindowsVersion`_$SKU`_Apps`_$BuildDate.ffu"
}
$dismArgs = "/capture-ffu /imagefile=$ffuFilePath /capturedrive=\\.\PhysicalDrive0 /name:$WindowsRelease$WindowsVersion$SKU /Compress:Default"
} }
#Unload Registry #Unload Registry
Set-Location X:\ Set-Location X:\
Remove-Variable SKU Remove-Variable SKU
Remove-Variable CurrentBuild Remove-Variable CurrentBuild
Remove-Variable DisplayVersion if ($CurrentBuild -notin 14393, 17763) {
Remove-Variable Office Remove-Variable WindowsVersion
}
if($Office) {
Remove-Variable Office
}
reg unload "HKLM\FFU" reg unload "HKLM\FFU"
#This prevents Critical Process Died errors you can have during deployment of the FFU - may not happen during capture from WinPE, but adding here to be consistent with VHDX capture #This prevents Critical Process Died errors you can have during deployment of the FFU - may not happen during capture from WinPE, but adding here to be consistent with VHDX capture
Write-Host "Sleeping for 60 seconds to allow registry to unload prior to capture" Write-Host "Sleeping for 60 seconds to allow registry to unload prior to capture"
@@ -65,5 +114,4 @@ Start-sleep 60
Start-Process -FilePath dism.exe -ArgumentList $dismArgs -Wait -PassThru -ErrorAction Stop | Out-Null Start-Process -FilePath dism.exe -ArgumentList $dismArgs -Wait -PassThru -ErrorAction Stop | Out-Null
#Copy DISM log to Host #Copy DISM log to Host
xcopy X:\Windows\logs\dism\dism.log W:\ /Y | Out-Null xcopy X:\Windows\logs\dism\dism.log W:\ /Y | Out-Null
wpeutil Shutdown wpeutil Shutdown
@@ -55,11 +55,18 @@ function Set-DiskpartAnswerFiles($DiskpartFile,$DiskID){
function Set-Computername($computername){ function Set-Computername($computername){
[xml]$xml = Get-Content $UnattendFile [xml]$xml = Get-Content $UnattendFile
if($xml.unattend.settings.component.Count -ge 2){ $components = $xml.unattend.settings.component
#Assumes that Computername is the first component element $found = $false
$xml.unattend.settings.component[0].ComputerName = $computername foreach ($component in $components) {
}else{ if ($component.ComputerName) {
$xml.unattend.settings.component.ComputerName = $computername $component.ComputerName = $computername
$found = $true
break
}
}
if (-not $found) {
WriteLog 'ComputerName element not found in unattend.xml.'
throw 'ComputerName element not found in unattend.xml.'
} }
$xml.Save($UnattendFile) $xml.Save($UnattendFile)
return $computername return $computername
@@ -128,13 +135,18 @@ $LogFileName = 'ScriptLog.txt'
$USBDrive = Get-USBDrive $USBDrive = Get-USBDrive
New-item -Path $USBDrive -Name $LogFileName -ItemType "file" -Force | Out-Null New-item -Path $USBDrive -Name $LogFileName -ItemType "file" -Force | Out-Null
$LogFile = $USBDrive + $LogFilename $LogFile = $USBDrive + $LogFilename
$version = '2408.1' $version = '2505.2'
WriteLog 'Begin Logging' WriteLog 'Begin Logging'
WriteLog "Script version: $version" WriteLog "Script version: $version"
#Find PhysicalDrive #Find PhysicalDrive
# $PhysicalDeviceID = Get-HardDrive # $PhysicalDeviceID = Get-HardDrive
$hardDrive = Get-HardDrive $hardDrive = Get-HardDrive
if($null -eq $hardDrive){
WriteLog 'No hard drive found. Exiting'
WriteLog 'Try adding storage drivers to the PE boot image (you can re-create your FFU and USB drive and add the PE drivers to the PEDrivers folder and add -CopyPEDrivers $true to the command line, or manually add them via DISM)'
Exit
}
$PhysicalDeviceID = $hardDrive.DeviceID $PhysicalDeviceID = $hardDrive.DeviceID
$BytesPerSector = $hardDrive.BytesPerSector $BytesPerSector = $hardDrive.BytesPerSector
WriteLog "Physical BytesPerSector is $BytesPerSector" WriteLog "Physical BytesPerSector is $BytesPerSector"
@@ -210,6 +222,7 @@ if (Test-Path -Path $PPKGFolder){
$UnattendFolder = $USBDrive + "unattend\" $UnattendFolder = $USBDrive + "unattend\"
$UnattendFilePath = $UnattendFolder + "unattend.xml" $UnattendFilePath = $UnattendFolder + "unattend.xml"
$UnattendPrefixPath = $UnattendFolder + "prefixes.txt" $UnattendPrefixPath = $UnattendFolder + "prefixes.txt"
$UnattendComputerNamePath = $UnattendFolder + "SerialComputerNames.csv"
If (Test-Path -Path $UnattendFilePath){ If (Test-Path -Path $UnattendFilePath){
$UnattendFile = Get-ChildItem -Path $UnattendFilePath $UnattendFile = Get-ChildItem -Path $UnattendFilePath
If ($UnattendFile){ If ($UnattendFile){
@@ -222,6 +235,12 @@ If (Test-Path -Path $UnattendPrefixPath){
$UnattendPrefix = $true $UnattendPrefix = $true
} }
} }
If (Test-Path -Path $UnattendComputerNamePath){
$UnattendComputerNameFile = Get-ChildItem -Path $UnattendComputerNamePath
If ($UnattendComputerNameFile){
$UnattendComputerName = $true
}
}
#Ask for device name if unattend exists #Ask for device name if unattend exists
if ($Unattend -and $UnattendPrefix){ if ($Unattend -and $UnattendPrefix){
@@ -266,7 +285,25 @@ if ($Unattend -and $UnattendPrefix){
$computername = Set-Computername($computername) $computername = Set-Computername($computername)
Writelog "Computer name set to $computername" Writelog "Computer name set to $computername"
} }
elseif($Unattend){ elseif($Unattend -and $UnattendComputerName){
Writelog 'Unattend file found with SerialComputerNames.csv. Getting name for current computer.'
$SerialComputerNames = Import-Csv -Path $UnattendComputerNameFile.FullName -Delimiter ","
$SerialNumber = (Get-CimInstance -Class Win32_Bios).SerialNumber
$SCName = $SerialComputerNames | Where-Object { $_.SerialNumber -eq $SerialNumber }
If ($SCName) {
[string]$computername = $SCName.ComputerName
$computername = Set-Computername($computername)
Writelog "Computer name set to $computername"
} else {
Writelog 'No matching serial number found in SerialComputerNames.csv. Setting random computer name to complete setup.'
[string]$computername = ("FFU-" + (-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 11 | ForEach-Object { [char]$_ })))
$computername = Set-Computername($computername)
Writelog "Computer name set to $computername"
}
}
elseif($Unattend) {
Writelog 'Unattend file found with no prefixes.txt, asking for name' Writelog 'Unattend file found with no prefixes.txt, asking for name'
[string]$computername = Read-Host 'Enter device name' [string]$computername = Read-Host 'Enter device name'
Set-Computername($computername) Set-Computername($computername)
@@ -549,6 +586,12 @@ If (Test-Path -Path $Drivers)
WriteLog 'Copying drivers succeeded' WriteLog 'Copying drivers succeeded'
} }
WriteLog "Setting Windows Boot Manager to be first in the display order."
Invoke-Process bcdedit.exe "/set {fwbootmgr} displayorder {bootmgr} /addfirst"
WriteLog "Windows Boot Manager has been set to be first in the display order."
WriteLog "Setting default Windows boot loader to be first in the display order."
Invoke-Process bcdedit.exe "/set {bootmgr} displayorder {default} /addfirst"
WriteLog "The default Windows boot loader has been set to be first in the display order."
#Copy DISM log to USBDrive #Copy DISM log to USBDrive
WriteLog "Copying dism log to $USBDrive" WriteLog "Copying dism log to $USBDrive"
invoke-process xcopy "X:\Windows\logs\dism\dism.log $USBDrive /Y" invoke-process xcopy "X:\Windows\logs\dism\dism.log $USBDrive /Y"
Binary file not shown.
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
<settings pass="specialize">
<!--<ComputerName> must be in the first Component Element "Microsoft-Windows-Shell-Setup" . Do not change the order or remove it -->
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ComputerName>MYCOMPUTER</ComputerName><!--Leave Default will be renamed-->
<TimeZone>Eastern Standard Time</TimeZone><!--Add Your Local TimeZone-->
</component>
<!-- Place additional Components Elements and Settings below here: -->
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RunASynchronous>
<RunASynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>cmd.exe /c date 09-07-2024</Path> <!--Set the device clock to the current date. Helpful when BIOS clocks out of sync. -->
<Description>Set system date to a specific date</Description>
</RunASynchronousCommand>
</RunASynchronous>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<InputLocale>0409:00000409</InputLocale><!--Set your Keybaord and System Local https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-8.1-and-8/hh825682(v=win.10) -->
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<OOBE>
<ProtectYourPC>3</ProtectYourPC> <!--Disable Diagnostic Data sent to Microsoft-->
<HideEULAPage>true</HideEULAPage><!--Hide the End User License agreement -->
<HideWirelessSetupInOOBE>false</HideWirelessSetupInOOBE> <!--Show Wifi Setup -->
</OOBE>
</component>
</settings>
</unattend>
+4 -2
View File
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend"> <unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="specialize"> <settings pass="specialize">
<!--<ComputerName> must be in the first Component Element "Microsoft-Windows-Shell-Setup" . Do not change the order or remove it -->
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="arm64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="arm64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ComputerName>MyComputer</ComputerName> <ComputerName>MyComputer</ComputerName>
</component> </component>
<!--Place addtional Components Elements and settings below here. -->
</settings> </settings>
</unattend> </unattend>
+4 -2
View File
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend"> <unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="specialize"> <settings pass="specialize">
<!--<ComputerName> must be in the first Component Element "Microsoft-Windows-Shell-Setup" . Do not change the order or remove it -->
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ComputerName>MyComputer</ComputerName> <ComputerName>MyComputer</ComputerName>
</component> </component>
<!--Place addtional Components Elements and settings below here. -->
</settings> </settings>
</unattend> </unattend>
+3 -5
View File
@@ -1,6 +1,8 @@
**Update 2025-08-01:** [2507.2 UI Preview is now available](https://github.com/rbalsleyMSFT/FFU/releases) - click the link to get the build and check out the Youtube walk-through.
# Using Full Flash Update (FFU) files to speed up Windows deployment # Using Full Flash Update (FFU) files to speed up Windows deployment
What if you could have a Windows image that has: What if you could have a Windows image (Windows 10/11 or Server) that has:
- The latest Windows cumulative update - The latest Windows cumulative update
- The latest .NET cumulative update - The latest .NET cumulative update
@@ -18,10 +20,6 @@ And the best part: it takes less than two minutes to apply the image, even with
The Full-Flash update (FFU) process can automatically download the latest release of Windows 11, the updates mentioned above, and creates a USB drive that can be used to quickly reimage a machine. The Full-Flash update (FFU) process can automatically download the latest release of Windows 11, the updates mentioned above, and creates a USB drive that can be used to quickly reimage a machine.
# Updates
2408.1 has been released! Check out the changes in the [Change Log](ChangeLog.md)
# Getting Started # Getting Started
- Download the latest [release](https://github.com/rbalsleyMSFT/FFU/releases) - Download the latest [release](https://github.com/rbalsleyMSFT/FFU/releases)