Compare commits

..

88 Commits

Author SHA1 Message Date
rbalsleyMSFT 67e3035c38 Merge pull request #47 from rbalsleyMSFT/2408.1
2408.1
2024-08-06 17:57:42 -07:00
rbalsleyMSFT 94dd256889 update docs 2024-08-06 17:55:17 -07:00
rbalsleyMSFT cc383c84cb update docs 2024-08-06 17:51:53 -07:00
rbalsleyMSFT b20b614f5e update changelog.md and ApplyFFU.ps1 to 2408.1 2024-08-06 17:39:13 -07:00
rbalsleyMSFT 31984e104e update readme.md 2024-08-06 15:52:35 -07:00
rbalsleyMSFT 94f74a194d update readme 2024-08-06 15:50:32 -07:00
rbalsleyMSFT eaa58e6804 update readme 2024-08-06 15:49:26 -07:00
rbalsleyMSFT 351c87ab96 update readme 2024-08-06 15:47:49 -07:00
rbalsleyMSFT 13e2765c3f update readme 2024-08-06 15:46:42 -07:00
rbalsleyMSFT c049840baa update readme.md 2024-08-06 15:45:44 -07:00
rbalsleyMSFT e1ab74e5a3 Refactored Get-USBDrives and New-DeploymentUSB to use tables when displaying multiple drives or FFUs to the user. Fixed an issue with cleaning up InstallAppsandSysprep.cmd. Re-wrote Readme.md. 2024-08-06 15:43:23 -07:00
rbalsleyMSFT 02d858f27f Merge pull request #45 from HedgeComp/2408.1
2408.1
2024-08-02 11:57:23 -07:00
rbalsleyMSFT 1d8e9f352d Merge branch '2408.1' of https://github.com/rbalsleyMSFT/FFU into 2408.1 2024-08-02 10:54:14 -07:00
rbalsleyMSFT 7b59e3d0ec Fixed an issue with clean up of Defender, OneDrive, and Edge. Fixed an issue with the formatting of InstallAppsandSysprep.cmd file. 2024-08-02 10:53:50 -07:00
Doctair 213da61389 Fix REad-Host Prompt message for FFU selecion 2024-08-02 12:20:17 -04:00
Doctair 9de55eb186 Comment Better 2024-08-02 12:11:54 -04:00
Doctair e3bec5ff45 Clean up some Remmed Lines and Added some Comments
for explanation
2024-08-02 12:02:58 -04:00
Doctair 1bfc4735d3 Sync arm64 changes and Rem $Capture False 2024-08-02 11:52:51 -04:00
Doctair 49b742b47b Added Logic for FFU Selection to Check for Integer
or 'A'

Fix Write Message to Display all FFUs found if not
using -Verbose, currently displays nothing so numbering
of FFUs is unkown for selection prompt

Added Simple total Runtime and Start and Finish Time
2024-08-02 11:35:18 -04:00
rbalsleyMSFT 7f79e50f72 Merge pull request #44 from HedgeComp/2408.1
External Disk Selection
2024-07-31 10:56:55 -07:00
Doctair 39b9d06d21 Correct Logic for Dirve letters and add Dirve Info
to the write-host selection for Disks.
2024-07-30 16:11:07 -04:00
Doctair 047881934a Add Logic to catch the disk selection of USB
External drives so that it will not accept a Letter
2024-07-30 13:57:54 -04:00
rbalsleyMSFT 689808eca7 commented some variables 2024-07-26 16:22:31 -07:00
rbalsleyMSFT 70571a3b49 Fixed an issue where Efisys_noprompt.bin was being used for deployment media. This should only be used for capture media 2024-07-26 16:04:53 -07:00
rbalsleyMSFT 06138ebaff Added $PromptExternalHardDiskMedia as a new variable defaulted to True to prevent accidentental data loss if external hard disks are detected 2024-07-24 17:16:30 -07:00
rbalsleyMSFT 81a3b10a06 added $AllowExternalHardDiskMedia variable and modified USB drive creation code to allow for External hard disks 2024-07-24 10:37:41 -07:00
rbalsleyMSFT 8ba88f4626 Fixed an issue with RAW disks and Clear-Disk 2024-07-23 16:31:16 -07:00
rbalsleyMSFT 9d4b66851a Merge pull request #42 from rbalsleyMSFT/2407.2
Fixed Lenovo driver download issues
2024-07-23 12:41:32 -07:00
rbalsleyMSFT 3ba0da19f8 Fixed Lenovo driver download issues 2024-07-23 12:38:17 -07:00
rbalsleyMSFT 6826f854ae updated drivers info 2024-07-22 14:45:35 -07:00
rbalsleyMSFT afa524091c adding authentication info when downloading store apps via Winget 2024-07-22 14:42:41 -07:00
rbalsleyMSFT f14c7f2b00 Update README.md 2024-07-22 14:19:24 -07:00
rbalsleyMSFT e1aac7ba9d Merge pull request #40 from rbalsleyMSFT/2407.1
2407.1
2024-07-22 13:48:34 -07:00
rbalsleyMSFT 2e7ab9a052 change log updates for 2407.1 2024-07-22 13:46:53 -07:00
rbalsleyMSFT 0a9de96d03 Potential path fix for downloading defender defs for ARM64 2024-07-22 10:55:24 -07:00
rbalsleyMSFT 50c61dd328 Added AppList_InboxAppsSample.json 2024-07-22 10:34:33 -07:00
rbalsleyMSFT 39a919bada Changed AppList.json file name to AppList_Sample.json to not force the sample apps to install automatically. 2024-07-22 10:31:53 -07:00
rbalsleyMSFT 5600b2fbbd fixed issues creating deploy media for VMs, cleaned up some old commented code in ApplyFFU.ps1 2024-07-19 19:17:02 -07:00
rbalsleyMSFT 1d26781dc1 Merge branch '2407.1' of https://github.com/rbalsleyMSFT/FFU into 2407.1 2024-07-18 21:35:18 -07:00
rbalsleyMSFT f29e3c4349 added additional winget app logging, removed static linenumber references 2024-07-18 21:35:15 -07:00
rbalsleyMSFT bd8d0efd66 Merge pull request #39 from zehadialam/minor-fixes
Minor Fixes
2024-07-17 14:27:09 -07:00
Zehadi Alam 5616082275 Add conditional check to not run clear-disk on new drives that are uninitialized 2024-07-17 00:14:00 -04:00
Zehadi Alam 8100df3d24 Add diskpart commands to assign GPT attributes to recovery partition 2024-07-16 23:43:35 -04:00
rbalsleyMSFT a5c38fd09b modified VM deployment iso cmd scripts and fixed appx license file issue 2024-07-16 18:48:43 -07:00
rbalsleyMSFT 88ef8f70a1 Merge branch '2407.1' of https://github.com/rbalsleyMSFT/FFU into 2407.1 2024-07-15 22:55:33 -07:00
rbalsleyMSFT 74fd71161b Added files for VM Deployment for testing 2024-07-15 22:55:24 -07:00
rbalsleyMSFT 8aa79dd134 Merge branch '2407.1' of https://github.com/rbalsleyMSFT/FFU into 2407.1 2024-07-15 09:40:16 -07:00
rbalsleyMSFT e4e499e796 create unattend files for x64 and arm64 2024-07-15 09:36:14 -07:00
rbalsleyMSFT f6c3c0b6c3 create unattend files for x64 and arm64 depending on windows architecture 2024-07-13 08:38:09 -07:00
rbalsleyMSFT 60ac2e4af0 Merge pull request #38 from zehadialam/feature-app-download-automation
Improve WinGet Integration for Automated App Downloads and Installs
2024-07-12 22:49:22 -07:00
Zehadi Alam ddf9c1f986 Fix Get-Apps function parameter name 2024-07-12 23:46:01 -04:00
Zehadi Alam ab58b27a1d Removed checking of appId using result parsing, since appId is already a parameter, added command to remove unprovisioned Notepad++ package, which breaks Sysprep 2024-07-12 23:40:59 -04:00
Zehadi Alam 191c30dd65 Remove New-WinGetSettings, since stable release of WinGet now supports MSStore app downloads 2024-07-12 22:43:10 -04:00
Zehadi Alam 1a444d8e0f Refactor Install-WinGet function and add architecture parameter and stable WinGet download, modify Confirm-WinGetInstallation to check for stable release, refactor Get-WinGetApp for improved maintainability and readability 2024-07-12 22:40:43 -04:00
Zehadi Alam f7f52903a4 Refactor Get-StoreApp for improved readability 2024-07-12 00:38:48 -04:00
Zehadi Alam a9afba9185 Refactor Install-WinGet and New-WinGetSettings for improved readability 2024-07-11 23:32:58 -04:00
rbalsleyMSFT ecf3794f92 Merge pull request #37 from MKellyCBSD/USBImagingToolCreator.ps1
Update to USBImagingToolCreator.ps1
2024-07-10 12:56:28 -07:00
Mike Kelly c0bcfd8bf2 Update USBImagingToolCreator.ps1
Changed the way the DisableAutoplay switch runs. Now it only changes the registry setting if it the current value is set to "0". then it restores the setting back to the previous value
2024-07-10 15:52:09 -04:00
rbalsleyMSFT 98babb3ad2 Merge pull request #36 from MKellyCBSD/USBImagingToolCreator.ps1
Feature Proposal: USBImagingToolCreator.ps1
2024-07-10 09:45:51 -07:00
Mike Kelly ab0b7f67ec Update USBImagingToolCreator.ps1 2024-07-09 15:40:22 -04:00
Mike Kelly 6d85e3ef62 Rename BuildUSBDrives.ps1 to USBImagingToolCreator.ps1
Update Script name
2024-07-09 15:38:33 -04:00
rbalsleyMSFT a91a417a08 Merge pull request #35 from mhaley/patch-1
Assign drive letter to recovery partition before modification
2024-07-09 09:28:30 -07:00
Mike Kelly 67cc8c1225 Update BuildUSBDrives.ps1
Update code
2024-07-09 11:29:58 -04:00
Matthew Haley 3f0377fbf9 Assign drive letter to recovery partition before modification
Assign drive letter so copy succeeds, remove when finished.
2024-07-08 13:45:44 -07:00
Zehadi Alam 325413de13 Moved code into separate functions, refactored existing functions, fixed logical errors in if-statements 2024-07-07 22:27:27 -04:00
Mike Kelly 174c16ecb6 Add files via upload
Upload BuildUSBDrives.ps1
2024-07-05 11:48:39 -04:00
Zehadi Alam 146c1601bd Improved handling of store apps that can't be downloaded 2024-07-05 00:01:06 -04:00
Zehadi Alam 8c897e93fe Added support for AppList to be in JSON format. WinGet searches now use app ID. Modified InstallAppsandSysprep.cmd to handle packages with no dependencies 2024-07-04 22:57:14 -04:00
rbalsleyMSFT 2423814cc2 changed unattend files for naming the PC for arm64 and modified arm64 store app download logic for dependency handling 2024-07-03 16:30:12 -07:00
rbalsleyMSFT c39c30c970 Merge pull request #34 from zehadialam/feature-app-download-automation
Handle Win32 Apps of MSStore Type & Update InstallAppsandSysprep.cmd
2024-07-02 19:04:14 -07:00
Zehadi Alam 95a4664b26 Added handling of win32 apps using the msstore source in winget download command, updated InstallAppsandSysprep.cmd file to use store app license files, and updated AppList.txt with winget prefix, instead of win32 2024-07-02 20:45:14 -04:00
rbalsleyMSFT 0e6d65bf2f Merge pull request #33 from zehadialam/feature-app-download-automation
WinGet Download Architecture Handling
2024-07-01 22:19:10 -07:00
Zehadi Alam 0010c8ad81 Fix typo 2024-07-01 22:39:43 -04:00
Zehadi Alam d16acce0ab Add condition to use winget download command without architecture parameter if specifying it leads to no app result 2024-07-01 22:34:03 -04:00
rbalsleyMSFT dd20eceb55 comment change 2024-07-01 16:23:04 -07:00
rbalsleyMSFT c30aa90e8b added architecture and other minor changes for winget app downloads 2024-07-01 16:22:56 -07:00
rbalsleyMSFT bd4e3a1913 Merge branch '2407.1' of https://github.com/rbalsleyMSFT/FFU into 2407.1 2024-07-01 10:09:34 -07:00
rbalsleyMSFT 7a0dd3435c Fixed a logic issue when downloading ARM KBs 2024-07-01 10:09:11 -07:00
rbalsleyMSFT df33e89e37 Merge pull request #32 from zehadialam/feature-app-download-automation
Automated Win32 and Store App Downloads and Installs
2024-07-01 09:33:34 -07:00
Zehadi Alam 4af808c939 Invoke Get-Apps function with AppList.txt argument 2024-06-30 20:15:13 -04:00
Zehadi Alam 205b58aaa7 Added cleanup of Win32 and MSStore folders 2024-06-30 19:45:43 -04:00
Zehadi Alam 1729eaddd6 Add AppsList, modified InstallAppsandSysprep.cmd file with store apps installation, and updated Clear-InstallAppsandSysprep function 2024-06-30 19:42:06 -04:00
Zehadi Alam cafff0b484 Add Get-Apps function 2024-06-30 19:34:03 -04:00
Zehadi Alam 5c77b171f1 Add Get-StoreApp function 2024-06-30 19:33:26 -04:00
Zehadi Alam 36f5350f12 Add Get-Win32App function 2024-06-30 19:32:54 -04:00
Zehadi Alam 45a2c0c29d Add New-WinGetSettings function 2024-06-30 19:32:18 -04:00
Zehadi Alam 6cfe41f963 Add Install-WinGet function 2024-06-30 19:31:40 -04:00
rbalsleyMSFT 3d13774ee4 initial arm64 support 2024-06-29 21:28:33 -07:00
18 changed files with 1828 additions and 260 deletions
+85
View File
@@ -1,5 +1,90 @@
# Change Log # Change Log
## **2408.1**
### External Drive Support
Up until now, the USB build process has supported using drives identified by Windows as removable drives. Most USB sticks will identify as removable, however faster drives may show up as external hard disk media. You may also have a smaller, portable SSD drive that you'd like to use for imaging since these are typically much faster than regular USB 3.x thumb drives.
In adding this support, I do realize that there is potential for data loss for those that might have external hard drives attached to their machines.
To handle this, with help from [HedgeComp](https://github.com/HedgeComp), we've refactored the `Get-USBDrives` function. Two new variables have been created:
| Parameter | Type | Description |
| --------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AllowExternalHardDiskMedia | Bool | If `$true`, will allow the use of media identified as External Hard Disk media via WMI class Win32_DiskDrive. Default is not defined. |
| PromptExternalHardDiskMedia | Bool | If `$true` and AllowExternalHardDiskMedia is `$true`, the script will prompt to select which drive to use. When set to `$true`, only a single drive will be created. If `$false`, the script won't prompt for which external hard disk to use and can use multiple external hard disks, similar to how removable USB drives function. |
By default, this functionality won't effect previous USB drive creation behavior. However if you want to take advantage of the new functionality, set `-AllowExternalHardDiskMedia $true`
Fixes/misc
- Fixed a display issue where if multiple FFU files were in the FFU folder, the script wouldn't display which FFUs to choose from when running the script without -verbose. This will now display a table with the last modified date whether you run with the -verbose switch or not.
- Added start/end/duration time (thanks [HedgeComp](https://github.com/HedgeComp))
- Fixed an issue where deployment media wasn't prompting for a key to be pressed as expected
- Fixed an issue when creating the USB drive and the drive had a RAW partition style that clear-disk would generate an error
- Cleaned up some commented code
- Added Create-PEMedia.ps1 as a helper script to quickly generate Deploy or Capture media
- Fixed an issue with clean up of Defender/OneDrive/Edge
- Fixed an issue with the formatting of InstallAppsandSysprep.cmd file
- Updated parameter documentation in the script to include newly added parameters
## **2407.1**
This is another major release that includes:
* Initial ARM64 support
* Winget support
### ARM64 Support
To support the newly released Copilot+ PCs, we now support the creation and deployment of FFUs created with ARM64 media. There are some caveats to this:
* The -WindowsArch parameter must be set to ARM64 (by default this parameter is set to x64)
* If you do not pass -ISOPath with a path to the ARM64 ISO, it will download an ARM64 ESD file from the Media Creation Tool (which is about 7-8 months old now). ARM64 ISOs are available via VLSC, but are not available via Visual Studio Downloads (Yet - unknown if they will ever be made available).
* The host machine you're building the FFU from must be ARM64
* Office/M365 apps don't currently support installing the ARM64 native bits from an offline system. If you pass `-InstallOffice $true` the script will change the value to false. You can install office after the fact when connected to the internet. I'm investigating this behavior and will issue a fix if/when this gets resolved. I still don't recommend building the FFU VM on the internet.
* The [Defender Updates Site](https://www.microsoft.com/en-us/wdsi/defenderupdates) provides download links for Defender definitions. The ARM link doesn't work for ARM64 and mpam-fe.exe fails to install. However there might be an undocumented ARM64 URL that may work. I've included it, but haven't tested it as I'm writing these notes. So we'll see if that works out.
* Drivers - Surface Laptop 7 and Pro 11 don't have ARM64 drivers available yet (there are entries, but they just point to a .txt file). Other OEMs may have drivers available.
In all, testing has gone very well.
### Winget Support
Big thanks to [Zehadi Alam](https://github.com/zehadialam) for his contributions to get this added to the project. You can now add any application in the msstore or winget source via the Winget command line utility. In the 1.8 Winget release the ability to download apps from the msstore source was added, which means being able to download apps like the Company Portal. For those of you that have been asking for Company Portal to be inbox in Windows, this is the next best thing. The script will check if Winget 1.8 is installed and if not, it'll install it.
The way this works is if `-InstallApps $true` and the FFUDevelopment\Apps\AppList.json file exists, whatever apps defined in that json file will be downloaded via Winget and will be installed in the FFU VM prior to capture. We've included two files: AppList_InboxAppsSample.json and AppList_Sample.json. The AppList_InboxAppsSample.json contains all of the apps that are installed in Windows by default and are searchable via `winget search AppID` . Some of these apps do not download and we're investigating why they come up via search, but fail to download. The AppList_Sample.json has Company Portal and New Teams.
![1721678632154](image/ChangeLog/1721678632154.png)
In sticking with the idea of having the most up to date Windows build, inbox store/UWP apps are notoriously out of date and use a lot of bandwidth. By updating all of the UWP apps, bandwidth reductions of ~70% can be achieved.
| | Total Data usage before updating store apps | Total Data usage after updating store apps | Total Data usage after updating Windows Update |
| --------------------------------------------------------------- | ------------------------------------------- | ------------------------------------------ | ---------------------------------------------- |
| July 2024 Windows 11 23H2 Stock ISO Captured as FFU (7.5GB FFU) | 261MB | 1.82GB | 2.09GB |
| July 2024 Windows 11 23H2 Updated FFU (10.5GB) | 13MB | 558MB | 646MB |
Updated means latest .NET, Defender (definition and platform updates), Edge, OneDrive, and all updates available via Winget for Store Apps have been provisioned in the FFU. The numbers in the table are cumulative, meaning the FFU was laid down, store apps were updated via running Get Apps from the Microsoft Store app and data usage was gathered from Settings, then Windows Update was manually kicked off via Settings and data usage was gathered.
In order to get apps to help build your AppList.json file, just run `winget search "AppName"`
![1721679421727](image/ChangeLog/1721679421727.png)
In this example we see that Firefox is published to both the msstore and winget sources. It's up to you which one you'd like to pick (I assume the msstore and the 128 version from the winget source are both the same version, but that may not be the case). You'll want to use the Name, ID, and Source values to help create your AppList.json file.
When downloading msstore apps, it does require an Entra ID. If you're building your FFUs from a machine that is not signed in with an Entra ID, you will be prompted for credentials for each app you download AND for the license file for each app (2 prompts per app). If downloading many store apps is something you plan on doing, I highly recommend signing in with an Entra ID to prevent the authentication prompts.
Other improvements
* [mhaley](https://github.com/mhaley) made their first contribution to [assign the drive letter to the recovery partition when copying in a custom WinRE.wim](https://github.com/rbalsleyMSFT/FFU/pull/35)
* [MKellyCBSD](https://github.com/MKellyCBSD) submitted a PR for a stand-alone USBImagingToolCreator.ps1 script which will create USB drives separate from the main BuildFUVM.ps1 script. This is helpful if you have technicans that need to build USB drives, or would like to make concurrent USB drives at the same time instead of one at a time. [His PR has all the details.](https://github.com/rbalsleyMSFT/FFU/pull/36)
* The WinPE_FFU_Deploy.iso will now work on VMs. This made ARM64 testing a lot easier :) If you're looking to test your FFU on a VM, you'll want to build a new VHDX and add your FFU to it and boot from the WinPE_FFU_Deploy.iso. Make sure to eject the VHDX before adding/booting the new VM. When attaching the new VHDX with your FFU on it, make sure it's not the first SCSI device (it should be 1 or 2, most likely 2 as 0 should be the hard drive you want to install Windows to, and 1 will be the DVD drive). By default the WinPE_FFU_Deploy.iso file is removed after the script completes. Make sure to set `-CreateDeploymentMedia $true` and `-CleanupDeployISO $false` so the ISO remains in the FFUDevelopment folder after the script completes.
The below screenshot should help in understanding what the SCSI config should look like.
![1721681140638](image/ChangeLog/1721681140638.png)
* Cleaned up some old commented code from the ApplyFFU.ps1 file and other files.
## **2406.1** ## **2406.1**
This is a major release that includes the ability to download drivers from the 4 major OEMs (Microsoft, Dell, HP, Lenovo) by simply passing the -Make and -Model parameters to the command line. This is a major release that includes the ability to download drivers from the 4 major OEMs (Microsoft, Dell, HP, Lenovo) by simply passing the -Make and -Model parameters to the command line.
@@ -0,0 +1,209 @@
{
"apps": [
{
"name": "Windows Terminal",
"id": "9N0DX20HK701",
"source": "msstore"
},
{
"name": "Cross Device Experience Host",
"id": "9NTXGKQ8P7N0",
"source": "msstore"
},
{
"name": "Movies & TV",
"id": "9WZDNCRFJ3P2",
"source": "msstore"
},
{
"name": "Microsoft Photos",
"id": "9WZDNCRFJBH4",
"source": "msstore"
},
{
"name": "Mail and Calendar",
"id": "9WZDNCRFHVQM",
"source": "msstore"
},
{
"name": "Microsoft Sticky Notes",
"id": "9NBLGGH4QGHW",
"source": "msstore"
},
{
"name": "Power Automate",
"id": "9NFTCH6J7FHV",
"source": "msstore"
},
{
"name": "Snipping Tool",
"id": "9MZ95KL8MR0L",
"source": "msstore"
},
{
"name": "Phone Link",
"id": "9NMPJ99VJBWV",
"source": "msstore"
},
{
"name": "Microsoft 365 (Office Hub)",
"id": "9WZDNCRFJBH4",
"source": "msstore"
},
{
"name": "App Installer",
"id": "9NBLGGH4NNS1",
"source": "msstore"
},
{
"name": "Microsoft Clipchamp",
"id": "9P1J8S7CCWWT",
"source": "msstore"
},
{
"name": "Webp Image Extensions",
"id": "9PG2DK419DRG",
"source": "msstore"
},
{
"name": "Windows Web Experience Pack",
"id": "9MSSGKG348SP",
"source": "msstore"
},
{
"name": "Xbox",
"id": "9MV0B5HZVK9Z",
"source": "msstore"
},
{
"name": "Paint",
"id": "9PCFS5B6T72H",
"source": "msstore"
},
{
"name": "Windows Camera",
"id": "9WZDNCRFJBBG",
"source": "msstore"
},
{
"name": "Windows Notepad",
"id": "9MSMLRH6LZF3",
"source": "msstore"
},
{
"name": "Windows Sound Recorder",
"id": "9WZDNCRFHWKN",
"source": "msstore"
},
{
"name": "Windows Calculator",
"id": "9WZDNCRFHVN5",
"source": "msstore"
},
{
"name": "Feedback Hub",
"id": "9NBLGGH4R32N",
"source": "msstore"
},
{
"name": "Xbox Identity Provider",
"id": "9WZDNCRD1HKW",
"source": "msstore"
},
{
"name": "Windows Media Player",
"id": "9WZDNCRFJ3PT",
"source": "msstore"
},
{
"name": "MSN Weather",
"id": "9WZDNCRFJ3Q2",
"source": "msstore"
},
{
"name": "Game Bar",
"id": "9NZKPSTSNW4P",
"source": "msstore"
},
{
"name": "Web Media Extensions",
"id": "9N5TDP8VCMHS",
"source": "msstore"
},
{
"name": "Get Help",
"id": "9PKDZBMV1H3T",
"source": "msstore"
},
{
"name": "Raw Image Extension",
"id": "9NCTDW2W1BH8",
"source": "msstore"
},
{
"name": "Store Experience Host",
"id": "9NBLGGH4LS1F",
"source": "msstore"
},
{
"name": "Windows Maps",
"id": "9WZDNCRDTBVB",
"source": "msstore"
},
{
"name": "Windows Clock",
"id": "9WZDNCRFJ3PR",
"source": "msstore"
},
{
"name": "Microsoft To Do",
"id": "9NBLGGH5R558",
"source": "msstore"
},
{
"name": "Cortana",
"id": "9NFFX4SZZ23L",
"source": "msstore"
},
{
"name": "Quick Assist",
"id": "9P7BP5VNWKX5",
"source": "msstore"
},
{
"name": "HEIF Image Extensions",
"id": "9PMMSR1CGPWG",
"source": "msstore"
},
{
"name": "VP9 Video Extensions",
"id": "9N4D0MSMP0PT",
"source": "msstore"
},
{
"name": "Xbox Live in-game experience",
"id": "9NKNC0LD5NN6",
"source": "msstore"
},
{
"name": "Xbox Game Speech Window",
"id": "9P086NHDNB9W",
"source": "msstore"
},
{
"name": "Microsoft News",
"id": "9WZDNCRFHVFW",
"source": "msstore"
},
{
"name": "Microsoft Store",
"id": "9WZDNCRFJBMP",
"source": "msstore"
},
{
"name": "Microsoft Tips",
"id": "9WZDNCRDTBJJ",
"source": "msstore"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
"apps": [
{
"name": "Company Portal",
"id": "9WZDNCRFJ3PZ",
"source": "msstore"
},
{
"name": "Microsoft Teams",
"id": "Microsoft.Teams",
"source": "winget"
}
]
}
@@ -1,3 +1,4 @@
setlocal enabledelayedexpansion
REM Put each app install on a separate line REM Put each app install on a separate line
REM M365 Apps/Office ProPlus REM M365 Apps/Office ProPlus
REM d:\Office\setup.exe /configure d:\office\DeployFFU.xml REM d:\Office\setup.exe /configure d:\office\DeployFFU.xml
@@ -6,9 +7,59 @@ REM Install Defender Definitions
REM Install Windows Security Platform Update REM Install Windows Security Platform Update
REM Install OneDrive Per Machine REM Install OneDrive Per Machine
REM Install Edge Stable REM Install Edge Stable
REM Winget Win32 Apps
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
set "INSTALL_STOREAPPS=false"
if /i "%INSTALL_STOREAPPS%"=="false" (
echo Skipping MS Store installation due to INSTALL_STOREAPPS flag.
goto :remaining
)
set "basepath=D:\MSStore"
for /d %%D in ("%basepath%\*") do (
set "appfolder=%%D"
set "mainpackage="
set "dependenciesfolder=!appfolder!\Dependencies"
for %%F in ("!appfolder!\*") do (
if not "%%~dpF"=="!dependenciesfolder!\" (
if /i not "%%~xF"==".xml" (
if /i not "%%~xF"==".yaml" (
set "mainpackage=%%F"
)
)
)
)
@REM for %%F in ("!appfolder!\*.xml") do (
@REM set "licensefile=%%F"
@REM )
if defined mainpackage (
set "dism_command=DISM /Online /Add-ProvisionedAppxPackage /PackagePath:"!mainpackage!""
if exist "!dependenciesfolder!" (
for %%G in ("!dependenciesfolder!\*") do (
set "dism_command=!dism_command! /DependencyPackagePath:"%%G""
)
)
for %%F in ("!appfolder!\*.xml") do (
set "licensefile=%%F"
)
if defined licensefile (
set "dism_command=!dism_command! /LicensePath:"!licensefile!""
) else (
set "dism_command=!dism_command! /SkipLicense"
)
set "dism_command=!dism_command! /Region:All"
echo !dism_command!
!dism_command!
)
)
:remaining
endlocal
for /r "D:\" %%G in (.) do (
if exist "%%G\Notepad++" (
powershell -Command "Remove-AppxPackage -Package NotepadPlusPlus_1.0.0.0_neutral__7njy0v32s6xk6"
)
)
REM The below lines will remove the unattend.xml that gets the machine into audit mode. If not removed, the OS will get stuck booting to audit mode each time. REM The below lines will remove the unattend.xml that gets the machine into audit mode. If not removed, the OS will get stuck booting to audit mode each time.
REM Also kills the sysprep process in order to automate sysprep generalize REM Also kills the sysprep process in order to automate sysprep generalize
del c:\windows\panther\unattend\unattend.xml /F /Q del c:\windows\panther\unattend\unattend.xml /F /Q
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="auditUser">
<component name="Microsoft-Windows-Deployment" 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">
<RunAsynchronous>
<RunAsynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>d:\InstallAppsandSysprep.cmd</Path>
</RunAsynchronousCommand>
</RunAsynchronous>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Deployment" 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">
<Reseal>
<Mode>Audit</Mode>
</Reseal>
</component>
</settings>
<cpi:offlineImage cpi:source="wim:c:/wimtoffu/win11_22h2_feb2023_consumer.wim#Windows 11 Pro" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
</unattend>
File diff suppressed because it is too large Load Diff
+209
View File
@@ -0,0 +1,209 @@
param (
[string]$FFUDevelopmentPath = $PSScriptRoot,
[string]$adkPath = 'C:\Program Files (x86)\Windows Kits\10\',
[string]$WindowsArch = 'x64',
[bool]$CopyPEDrivers = $false,
[string]$CaptureISO = "$PSScriptRoot\WinPE_FFU_Capture_x64.iso",
[string]$DeployISO = "$PSScriptRoot\WinPE_FFU_Deploy_x64.iso",
[string]$LogFile = "$PSScriptRoot\Create-PEMedia.log",
[bool]$Capture,
[bool]$Deploy = $true
)
function WriteLog($LogText) {
Add-Content -path $LogFile -value "$((Get-Date).ToString()) $LogText" -Force -ErrorAction SilentlyContinue
Write-Verbose $LogText
}
function Invoke-Process {
[CmdletBinding(SupportsShouldProcess)]
param
(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$FilePath,
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]$ArgumentList
)
$ErrorActionPreference = 'Stop'
try {
$stdOutTempFile = "$env:TEMP\$((New-Guid).Guid)"
$stdErrTempFile = "$env:TEMP\$((New-Guid).Guid)"
$startProcessParams = @{
FilePath = $FilePath
ArgumentList = $ArgumentList
RedirectStandardError = $stdErrTempFile
RedirectStandardOutput = $stdOutTempFile
Wait = $true;
PassThru = $true;
NoNewWindow = $true;
}
if ($PSCmdlet.ShouldProcess("Process [$($FilePath)]", "Run with args: [$($ArgumentList)]")) {
$cmd = Start-Process @startProcessParams
$cmdOutput = Get-Content -Path $stdOutTempFile -Raw
$cmdError = Get-Content -Path $stdErrTempFile -Raw
if ($cmd.ExitCode -ne 0) {
if ($cmdError) {
throw $cmdError.Trim()
}
if ($cmdOutput) {
throw $cmdOutput.Trim()
}
}
else {
if ([string]::IsNullOrEmpty($cmdOutput) -eq $false) {
WriteLog $cmdOutput
}
}
}
}
catch {
#$PSCmdlet.ThrowTerminatingError($_)
WriteLog $_
Write-Host "Script failed - $Logfile for more info"
throw $_
}
finally {
Remove-Item -Path $stdOutTempFile, $stdErrTempFile -Force -ErrorAction Ignore
}
}
function New-PEMedia {
param (
[Parameter()]
[bool]$Capture,
[Parameter()]
[bool]$Deploy
)
#Need to use the Demployment and Imaging tools environment to create winPE media
$DandIEnv = "$adkPath`Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"
$WinPEFFUPath = "$FFUDevelopmentPath\WinPE"
If (Test-path -Path "$WinPEFFUPath") {
WriteLog "Removing old WinPE path at $WinPEFFUPath"
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force | out-null
}
WriteLog "Copying WinPE files to $WinPEFFUPath"
if($WindowsArch -eq 'x64') {
& cmd /c """$DandIEnv"" && copype amd64 $WinPEFFUPath" | Out-Null
}
elseif($WindowsArch -eq 'arm64') {
& cmd /c """$DandIEnv"" && copype arm64 $WinPEFFUPath" | Out-Null
}
#Invoke-Process cmd "/c ""$DandIEnv"" && copype amd64 $WinPEFFUPath"
WriteLog 'Files copied successfully'
WriteLog 'Mounting WinPE media to add WinPE optional components'
Mount-WindowsImage -ImagePath "$WinPEFFUPath\media\sources\boot.wim" -Index 1 -Path "$WinPEFFUPath\mount" | Out-Null
WriteLog 'Mounting complete'
$Packages = @(
"WinPE-WMI.cab",
"en-us\WinPE-WMI_en-us.cab",
"WinPE-NetFX.cab",
"en-us\WinPE-NetFX_en-us.cab",
"WinPE-Scripting.cab",
"en-us\WinPE-Scripting_en-us.cab",
"WinPE-PowerShell.cab",
"en-us\WinPE-PowerShell_en-us.cab",
"WinPE-StorageWMI.cab",
"en-us\WinPE-StorageWMI_en-us.cab",
"WinPE-DismCmdlets.cab",
"en-us\WinPE-DismCmdlets_en-us.cab"
)
if($WindowsArch -eq 'x64'){
$PackagePathBase = "$adkPath`Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\"
}
elseif($WindowsArch -eq 'arm64'){
$PackagePathBase = "$adkPath`Assessment and Deployment Kit\Windows Preinstallation Environment\arm64\WinPE_OCs\"
}
foreach ($Package in $Packages) {
$PackagePath = Join-Path $PackagePathBase $Package
WriteLog "Adding Package $Package"
Add-WindowsPackage -Path "$WinPEFFUPath\mount" -PackagePath $PackagePath | Out-Null
WriteLog "Adding package complete"
}
If ($Capture) {
WriteLog "Copying $FFUDevelopmentPath\WinPECaptureFFUFiles\* to WinPE capture media"
Copy-Item -Path "$FFUDevelopmentPath\WinPECaptureFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force | out-null
WriteLog "Copy complete"
#Remove Bootfix.bin - for BIOS systems, shouldn't be needed, but doesn't hurt to remove for our purposes
#Remove-Item -Path "$WinPEFFUPath\media\boot\bootfix.bin" -Force | Out-null
# $WinPEISOName = 'WinPE_FFU_Capture.iso'
$WinPEISOFile = $CaptureISO
# $Capture = $false
}
If ($Deploy) {
WriteLog "Copying $FFUDevelopmentPath\WinPEDeployFFUFiles\* to WinPE deploy media"
Copy-Item -Path "$FFUDevelopmentPath\WinPEDeployFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force | Out-Null
WriteLog 'Copy complete'
#If $CopyPEDrivers = $true, add drivers to WinPE media using dism
if ($CopyPEDrivers) {
WriteLog "Adding drivers to WinPE media"
try {
Add-WindowsDriver -Path "$WinPEFFUPath\Mount" -Driver "$FFUDevelopmentPath\PEDrivers" -Recurse -ErrorAction SilentlyContinue | Out-null
}
catch {
WriteLog 'Some drivers failed to be added to the FFU. This can be expected. Continuing.'
}
WriteLog "Adding drivers complete"
}
# $WinPEISOName = 'WinPE_FFU_Deploy.iso'
$WinPEISOFile = $DeployISO
# $Deploy = $false
}
WriteLog 'Dismounting WinPE media'
Dismount-WindowsImage -Path "$WinPEFFUPath\mount" -Save | Out-Null
WriteLog 'Dismount complete'
#Make ISO
if ($WindowsArch -eq 'x64') {
$OSCDIMGPath = "$adkPath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg"
}
elseif ($WindowsArch -eq 'arm64') {
$OSCDIMGPath = "$adkPath`Assessment and Deployment Kit\Deployment Tools\arm64\Oscdimg"
}
$OSCDIMG = "$OSCDIMGPath\oscdimg.exe"
WriteLog "Creating WinPE ISO at $WinPEISOFile"
# & "$OSCDIMG" -m -o -u2 -udfver102 -bootdata:2`#p0,e,b$OSCDIMGPath\etfsboot.com`#pEF,e,b$OSCDIMGPath\Efisys_noprompt.bin $WinPEFFUPath\media $FFUDevelopmentPath\$WinPEISOName | Out-null
if($WindowsArch -eq 'x64'){
if($Capture){
$OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:2`#p0,e,b`"$OSCDIMGPath\etfsboot.com`"`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`""
}
if($Deploy){
$OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:2`#p0,e,b`"$OSCDIMGPath\etfsboot.com`"`#pEF,e,b`"$OSCDIMGPath\Efisys.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`""
}
}
elseif($WindowsArch -eq 'arm64'){
if($Capture){
$OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:1`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`""
}
if($Deploy){
$OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:1`#pEF,e,b`"$OSCDIMGPath\Efisys.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`""
}
}
Invoke-Process $OSCDIMG $OSCDIMGArgs
WriteLog "ISO created successfully"
WriteLog "Cleaning up $WinPEFFUPath"
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force
WriteLog 'Cleanup complete'
}
if($Capture){
New-PEMedia -Capture $Capture
}
if($Deploy){
New-PEMedia -Deploy $Deploy
}
Binary file not shown.
+223
View File
@@ -0,0 +1,223 @@
[CmdletBinding()]
param(
[Parameter(Mandatory = $True, Position = 0)]
$DeployISOPath,
[Switch]$DisableAutoPlay
)
$Host.UI.RawUI.WindowTitle = 'USB Imaging Tool Creator'
if($DeployISOPath){
$DevelopmentPath = $DeployISOPath | Split-Path
function WriteLog($LogText) {
$LogFileName = '\Script.log'
$LogFile = $DevelopmentPath + $LogFilename
Add-Content -path $LogFile -value "$((Get-Date).ToString()) $LogText" -Force -ErrorAction SilentlyContinue
Write-Verbose $LogText
}
Function Get-USBDrive {
$USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'")
If ($USBDrives -and ($null -eq $USBDrives.count)) {
$USBDrivesCount = 1
}
else {
$USBDrivesCount = $USBDrives.Count
}
WriteLog "Found $USBDrivesCount USB drives"
if ($null -eq $USBDrives) {
WriteLog "No removable USB drive found. Exiting"
Write-Error "No removable USB drive found. Exiting"
exit 1
}
return $USBDrives, $USBDrivesCount
}
Function Build-DeploymentUSB{
param(
[Array]$Drives
)
writelog "Checking if ffu files are present in the ffu folder"
$Images = Get-ChildItem -Path $FFUPath -Filter "*.ffu" -File -Recurse
writelog "Checking if drivers are present in the drivers folder"
$Drivers = Get-ChildItem -Path $DriversPath -Recurse
$DrivesCount = $Drives.Count
Writelog "Creating partitions..."
foreach ($USBDrive in $Drives) {
$DriveNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "")
$Model = $USBDrive.model
$ScriptBlock = {
param($DriveNumber)
Clear-Disk -Number $DriveNumber -RemoveData -RemoveOEM -Confirm:$false
$Disk = Get-Disk -Number $DriveNumber
$PartitionStyle = $Disk.PartitionStyle
if($PartitionStyle -ne 'MBR'){
$Disk | Set-Disk -PartitionStyle MBR
}
$BootPartition = New-Partition -DiskNumber $DriveNumber -Size 2GB -IsActive -AssignDriveLetter
$DeployPartition = New-Partition -DiskNumber $DriveNumber -UseMaximumSize -AssignDriveLetter
Format-Volume -Partition $BootPartition -FileSystem FAT32 -NewFileSystemLabel "Boot" -Confirm:$false
Format-Volume -Partition $DeployPartition -FileSystem NTFS -NewFileSystemLabel "Deploy" -Confirm:$false
}
WriteLog "Start job to create BOOT and Deploy partitions on drive number $DriveNumber"
Start-Job -ScriptBlock $ScriptBlock -ArgumentList $DriveNumber | Out-Null
}
writelog "Wait for partitioning jobs to complete"
Get-Job | Wait-Job | Out-Null
if($DrivesCount -gt 1){
writelog "Get file system information for all drives"
$Partitions = Get-Partition | Get-Volume
}else{
writelog "Get file system information for drive number $DiskNumber"
$Partitions = Get-Partition -DiskNumber $DriveNumber | Get-Volume
}
writelog "Get drive letter for all volumes labeled:BOOT"
$BootDrives = ($Partitions | Where-Object { $_.FileSystemLabel -eq "BOOT"}).DriveLetter
writelog "Get drive letter for all volumes labeled:Deploy"
$DeployDrives = ($Partitions | Where-Object { $_.FileSystemLabel -eq "Deploy"}).DriveLetter
writelog "Mount Deployment .iso image"
$ISOMountPoint = (Mount-DiskImage -ImagePath "$DeployISOPath" -PassThru | Get-Volume).DriveLetter + ":\"
writelog "Copying boot files to all drives labeled BOOT concurrently"
foreach ($Drive in $BootDrives) {
$Destination = $Drive + ":\"
$jobScriptBlock = {
param (
[string]$SFolder,
[string]$DFolder
)
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
}
WriteLog "Start job to copy all boot files to $Destination"
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $ISOMountPoint, $Destination | Out-Null
}
if($Images){
writelog "Copying FFU image files to all drives labeled deploy concurrently"
foreach ($Drive in $DeployDrives) {
$Destination = $Drive + ":\"
$jobScriptBlock = {
param (
[string]$SFolder,
[string]$DFolder
)
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
}
WriteLog "Start job to copy all FFU files to $Destination"
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $FFUPath, $Destination | Out-Null
}
}
if($Drivers){
writelog "Copying driver files to all drives labeled deploy concurrently"
foreach ($Drive in $DeployDrives) {
$Destination = $Drive + ":\Drivers"
$jobScriptBlock = {
param (
[string]$SFolder,
[string]$DFolder
)
New-Item -Path $DFolder -ItemType Directory -Force -Confirm: $false | Out-Null
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
}
WriteLog "Start job to copy all drivers to $Destination"
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $DriversPath, $Destination | Out-Null
}
}
if(!($Drivers)){
foreach ($Drive in $DeployDrives) {
WriteLog "Create drivers directory"
$drivepath = $Drive + ":\"
New-Item -Path "$drivepath" -Name Drivers -ItemType Directory -Force -Confirm: $false | Out-Null
}
}
if($DrivesCount -gt 1){
Writelog "Building $DrivesCount drives concurrently...Please be patient..."
}else{
Writelog "Building the imaging tool on $model...Please be patient..."
}
Get-Job | Wait-Job | Out-Null
Dismount-DiskImage -ImagePath $DeployISOPath | Out-Null
Writelog "Drive creation jobs completed..."
}
Function New-DeploymentUSB {
param(
[Array]$Drives,
[int]$Count,
[String]$FFUPath = "$DevelopmentPath\FFU",
[String]$DriversPath = "$DevelopmentPath\Drivers"
)
$Drivelist = @()
writelog "Creating a USB drive selection list"
for($i=0;$i -le $Count -1;$i++){
$DriveModel = $Drives[$i].Model
$DriveSize = [math]::round($Drives[$i].size/1GB, 2)
$DiskNumber = $Drives[$i].DeviceID.Replace("\\.\PHYSICALDRIVE", "")
$Properties = [ordered]@{Number = $i + 1 ; DriveNumber = $DiskNumber ; DriveModel = $driveModel ; 'Size (GB)' = $DriveSize}
$Drivelist += New-Object PSObject -Property $Properties
}
if($Count -gt 1){
$Last = $Count+1
$Drivelist += New-Object -TypeName PSObject -Property @{ Number = "$last"; DriveModel = "Select this option to use all ($count) inserted USB Drives" }
}
$Drivelist | Format-Table -AutoSize -Property Number, DriveModel , 'Size (GB)'
do {
try {
$var = $true
$DriveSelected = Read-Host 'Enter the drive number to apply the .iso to'
$DriveSelected = ($DriveSelected -as [int]) -1
if($Last){
writelog "All drives selected"
}else{
writelog "Drive $DriveSelected selected"}
}
catch {
Write-Host 'Input was not in correct format. Please enter a valid FFU number'
$var = $false
}
} until (($DriveSelected -le $Count -1 -or $last) -and $var)
$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"
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value 1 -Type DWORD
}
WriteLog "Closing all MMC windows to prevent drive lock errors"
Stop-Process -Name mmc -ErrorAction SilentlyContinue
WriteLog "Closing all Diskpart windows to prevent drive lock errors"
Stop-Process -Name diskpart -ErrorAction SilentlyContinue
$Selection = $Drivelist[$DriveSelected].Number
$totalSteps = 5
if($Selection -eq $last){
Read-Host -Prompt "ALL DRIVES SELECTED! WILL ERASE ALL CURRENTLY CONNECTED USB DRIVES!! Press ENTER to continue"
Build-DeploymentUSB -Drives $Drives
}else{
Read-Host -Prompt "Drive number $Selection was selected. Press ENTER to continue"
Build-DeploymentUSB -Drives $Drives[$DriveSelected]
}
WriteLog "Setting the registry key to re-enable autoplay for all drives"
if($DisableAutoPlay){
Writelog "Setting disable autoplay setting back to $DisableAutoPlayCurrentSetting"
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value $DisableAutoPlayCurrentSetting -Type DWORD
}
Writelog "Completed!"
}
#Get USB Drive and create log file
if(Test-Path "$DevelopmentPath\Script.log"){
Remove-Item -Path "$DevelopmentPath\Script.log" -Force -Confirm:$false
New-item -Path $DevelopmentPath -Name 'Script.log' -ItemType "file" -Force | Out-Null
}
WriteLog 'Begin Logging'
WriteLog 'Getting USB drive information and usb drive count'
$USBDrives,$USBDrivesCount = Get-USBDrive
New-DeploymentUSB -Drives $USBDrives -Count $USBDrivesCount
read-host -Prompt "USB drive creation complete. Press ENTER to exit"
Exit
}else{
Write-Host "No .ISO file selected..."
read-host "Press ENTER to Exit..."
Exit
}
+64 -92
View File
@@ -15,8 +15,34 @@ function Get-USBDrive(){
} }
function Get-HardDrive(){ function Get-HardDrive(){
$DeviceID = (Get-WmiObject -Class 'Win32_DiskDrive' | Where-Object {$_.MediaType -eq 'Fixed hard disk media' -and $_.Model -ne 'Microsoft Virtual Disk'}).DeviceID $SystemInfo = Get-WmiObject -Class 'Win32_ComputerSystem'
return $DeviceID $Manufacturer = $SystemInfo.Manufacturer
$Model = $SystemInfo.Model
WriteLog "Device Manufacturer: $Manufacturer"
WriteLog "Device Model: $Model"
WriteLog 'Getting Hard Drive info'
if ($Manufacturer -eq 'Microsoft Corporation' -and $Model -eq 'Virtual Machine'){
WriteLog 'Running in a Hyper-V VM. Getting virtual disk on Index 0 and SCSILogicalUnit 0'
$DiskDrive = Get-WmiObject -Class 'Win32_DiskDrive' | Where-Object {$_.MediaType -eq 'Fixed hard disk media' `
-and $_.Model -eq 'Microsoft Virtual Disk' `
-and $_.Index -eq 0 `
-and $_.SCSILogicalUnit -eq 0
}
}
else{
WriteLog 'Not running in a VM. Getting physical disk drive'
$DiskDrive = Get-WmiObject -Class 'Win32_DiskDrive' | Where-Object {$_.MediaType -eq 'Fixed hard disk media' -and $_.Model -ne 'Microsoft Virtual Disk'}
}
$DeviceID = $DiskDrive.DeviceID
$BytesPerSector = $Diskdrive.BytesPerSector
# Create a custom object to return both values
$result = New-Object PSObject -Property @{
DeviceID = $DeviceID
BytesPerSector = $BytesPerSector
}
return $result
} }
function WriteLog($LogText){ function WriteLog($LogText){
@@ -97,60 +123,27 @@ function Invoke-Process {
} }
# This function can be used in instances where battery level might matter (e.g. installing firmware for Surface). The problem is that WinPE doesn't have
# a driver for the battery installed, so you'll need to inject drivers, which can be tricky because just injecting the battery driver might not be enough,
# you might also need other drivers that the battery driver is dependent on.
# function Get-Battery(){
# while (($BattLev = (Get-CimInstance win32_battery).EstimatedChargeRemaining) -lt "35")
# {
# WriteLog "Battery is currently at $BattLev`%. Waiting for 35`% to proceed..."
# Write-Host "Battery is currently at $BattLev`%. Waiting for 35`% to proceed..."
# Start-Sleep 60
# }
# WriteLog "Battery level is $BattLev `%, which is greater than 35'% applying FFU"
# Write-Host "Battery level is $BattLev `%, which is greater than 35'% applying FFU"
# }
#Get USB Drive and create log file #Get USB Drive and create log file
$LogFileName = 'ScriptLog.txt' $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 = '2406.1' $version = '2408.1'
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
$PhysicalDeviceID = $hardDrive.DeviceID
$BytesPerSector = $hardDrive.BytesPerSector
WriteLog "Physical BytesPerSector is $BytesPerSector"
WriteLog "Physical DeviceID is $PhysicalDeviceID" WriteLog "Physical DeviceID is $PhysicalDeviceID"
#Parse DiskID Number #Parse DiskID Number
$DiskID = $PhysicalDeviceID.substring($PhysicalDeviceID.length - 1,1) $DiskID = $PhysicalDeviceID.substring($PhysicalDeviceID.length - 1,1)
WriteLog "DiskID is $DiskID" WriteLog "DiskID is $DiskID"
#COMMENT THIS WHOLE BLOCK OUT ONCE FFUPROVIDER FIX IS IN
# #Modify diskpart answer files if DiskID not 0
# # $UEFIFFUPartitions = 'x:\CreateUEFI-FFU-Partitions.txt'
# $ExtendPartition = 'x:\ExtendPartition-UEFI.txt'
# If ($DiskID -ne '0'){
# WriteLog 'DiskID is not 0. Need to modify diskpart answer files'
# # try {
# # Set-DiskpartAnswerFiles $UEFIFFUPartitions $DiskID
# # }
# # catch {
# # WriteLog "Modifying $UEFIFFUPartitions failed with error: $_"
# # }
# try {
# Set-DiskpartAnswerFiles $ExtendPartition $DiskID
# }
# catch {
# WriteLog "Modifying $ExtendPartition failed with error: $_"
# }
# }
#Find FFU Files #Find FFU Files
[array]$FFUFiles = @(Get-ChildItem -Path $USBDrive*.ffu) [array]$FFUFiles = @(Get-ChildItem -Path $USBDrive*.ffu)
$FFUCount = $FFUFiles.Count $FFUCount = $FFUFiles.Count
@@ -420,17 +413,13 @@ If (Test-Path -Path $Drivers)
Writelog 'No driver folders found' Writelog 'No driver folders found'
} }
} }
#If you want to enable battery level checking, uncomment the line below as well as the Get-Battery function near the top of the script
#Get-Battery
#Partition drive #Partition drive
Writelog 'Clean Disk' Writelog 'Clean Disk'
#Start-Process -FilePath diskpart.exe -ArgumentList "/S $UEFIFFUPartitions" -Wait -ErrorAction Stop | Out-File $Logfile -Append
#Invoke-Process diskpart.exe "/S $UEFIFFUPartitions"
try { try {
$Disk = Get-Disk -Number $DiskID $Disk = Get-Disk -Number $DiskID
if ($Disk.PartitionStyle -ne "RAW") {
$Disk | clear-disk -RemoveData -RemoveOEM -Confirm:$false $Disk | clear-disk -RemoveData -RemoveOEM -Confirm:$false
}
} }
catch { catch {
WriteLog 'Cleaning disk failed. Exiting' WriteLog 'Cleaning disk failed. Exiting'
@@ -444,50 +433,41 @@ WriteLog "Applying FFU to $PhysicalDeviceID"
WriteLog "Running command dism /apply-ffu /ImageFile:$FFUFileToInstall /ApplyDrive:$PhysicalDeviceID" WriteLog "Running command dism /apply-ffu /ImageFile:$FFUFileToInstall /ApplyDrive:$PhysicalDeviceID"
#In order for Applying Image progress bar to show up, need to call dism directly. Might be a better way to handle, but must have progress bar show up on screen. #In order for Applying Image progress bar to show up, need to call dism directly. Might be a better way to handle, but must have progress bar show up on screen.
dism /apply-ffu /ImageFile:$FFUFileToInstall /ApplyDrive:$PhysicalDeviceID dism /apply-ffu /ImageFile:$FFUFileToInstall /ApplyDrive:$PhysicalDeviceID
$recoveryPartition = Get-Partition -Disk $Disk | Where-Object PartitionNumber -eq 4
if ($recoveryPartition) {
WriteLog 'Setting recovery partition attributes'
$diskpartScript = @(
"SELECT DISK $($Disk.Number)",
"SELECT PARTITION $($recoveryPartition.PartitionNumber)",
"GPT ATTRIBUTES=0x8000000000000001",
"EXIT"
)
$diskpartScript | diskpart.exe | Out-Null
WriteLog 'Setting recovery partition attributes complete'
}
if($LASTEXITCODE -eq 0){ if($LASTEXITCODE -eq 0){
WriteLog 'Successfully applied FFU' WriteLog 'Successfully applied FFU'
} }
elseif($LASTEXITCODE -eq 1393){
WriteLog "Failed to apply FFU - LastExitCode = $LastExitCode"
WriteLog "This is likely due to a mismatched LogicalSectorByteSize"
WriteLog "BytesPerSector value from Win32_Diskdrive is $BytesPerSector"
if ($BytesPerSector -eq 4096){
WriteLog "The FFU build process by default uses a 512 LogicalSectorByteSize. Rebuild the FFU by adding -LogicalSectorByteSize 4096 to the command line"
}
elseif($BytesPerSector -eq 512){
WriteLog "This FFU was likely built with a LogicalSectorByteSize of 4096. Rebuild the FFU by adding -LogicalSectorByteSize 512 to the command line"
}
#Copy DISM log to USBDrive
invoke-process xcopy.exe "X:\Windows\logs\dism\dism.log $USBDrive /Y"
exit
}
else{ else{
Writelog "Failed to apply FFU - LastExitCode = $LASTEXITCODE also check dism.log on the USB drive for more info" Writelog "Failed to apply FFU - LastExitCode = $LASTEXITCODE also check dism.log on the USB drive for more info"
#Copy DISM log to USBDrive #Copy DISM log to USBDrive
invoke-process xcopy.exe "X:\Windows\logs\dism\dism.log $USBDrive /Y" invoke-process xcopy.exe "X:\Windows\logs\dism\dism.log $USBDrive /Y"
exit exit
} }
#Remove recovery partition - this is needed in order to extend the Windows partition so it uses the full disk size. If dism /optimize-ffu worked, this wouldn't be needed
# $disk = get-disk -Number $DiskID
# $RecoveryPartition = $disk | get-partition | Where-Object {$_.type -eq 'Recovery'}
# if ($RecoveryPartition){
# $RecoveryPartitionNumber = $RecoveryPartition.PartitionNumber
# if ($RecoveryPartitionNumber -eq 4){
# try {
# WriteLog 'Removing recovery partition'
# Remove-partition -DiskNumber $DiskID -PartitionNumber $RecoveryPartitionNumber -Confirm:$false
# }
# catch {
# WriteLog 'Error removing recovery partition, exiting'
# throw $_
# }
# }
# else{
# WriteLog 'Recovery partition not partition 4. Script will exit. Please create the FFU with the recovery partition as the last partition. This is the default and recommended way.'
# exit
# }
# }
#COMMENT THIS WHOLE BLOCK OUT AFTER FFUPROVIDER FIX IS IN
# # Extend Windows partition and create recovery partition
# Writelog 'Extending Windows partition'
# Invoke-Process diskpart.exe "/S $ExtendPartition"
# if($LASTEXITCODE -eq 0){
# WriteLog 'Successfully extended Windows partition and created recovery partition'
# }
# else{
# Writelog "Failed to extend Windows partition and/or create recovery partition - LastExitCode = $LASTEXITCODE"
# }
#UNCOMMENT THIS AFTER FFUPROVIDER FIX IS IN
# Set W: drive letter to Windows partition
Get-Disk | Where-Object Number -eq $DiskID | Get-Partition | Where-Object PartitionNumber -eq 3 | Set-Partition -NewDriveLetter W Get-Disk | Where-Object Number -eq $DiskID | Get-Partition | Where-Object PartitionNumber -eq 3 | Set-Partition -NewDriveLetter W
#Copy modified WinRE if folder exists, else copy inbox WinRE #Copy modified WinRE if folder exists, else copy inbox WinRE
@@ -495,22 +475,14 @@ $WinRE = $USBDrive + "WinRE\winre.wim"
If (Test-Path -Path $WinRE) If (Test-Path -Path $WinRE)
{ {
WriteLog 'Copying modified WinRE to Recovery directory' WriteLog 'Copying modified WinRE to Recovery directory'
Get-Disk | Where-Object Number -eq $DiskID | Get-Partition | Where-Object Type -eq Recovery | Set-Partition -NewDriveLetter R
Invoke-Process xcopy.exe "/h $WinRE R:\Recovery\WindowsRE\ /Y" Invoke-Process xcopy.exe "/h $WinRE R:\Recovery\WindowsRE\ /Y"
WriteLog 'Copying WinRE to Recovery directory succeeded' WriteLog 'Copying WinRE to Recovery directory succeeded'
WriteLog 'Registering location of recovery tools' WriteLog 'Registering location of recovery tools'
Invoke-Process W:\Windows\System32\Reagentc.exe "/Setreimage /Path R:\Recovery\WindowsRE /Target W:\Windows" Invoke-Process W:\Windows\System32\Reagentc.exe "/Setreimage /Path R:\Recovery\WindowsRE /Target W:\Windows"
Get-Disk | Where-Object Number -eq $DiskID | Get-Partition | Where-Object Type -eq Recovery | Remove-PartitionAccessPath -AccessPath R:
WriteLog 'Registering location of recovery tools succeeded' WriteLog 'Registering location of recovery tools succeeded'
} }
# else
# {
# WriteLog 'Copying default WinRE to Recovery directory'
# Invoke-Process xcopy.exe "/h W:\Windows\System32\Recovery\Winre.wim R:\Recovery\WindowsRE\ /Y"
# WriteLog 'Copying WinRE to Recovery directory succeeded'
# WriteLog 'Registering location of recovery tools'
# Invoke-process W:\Windows\System32\Reagentc.exe "/Setreimage /Path R:\Recovery\WindowsRE /Target W:\Windows"
# WriteLog 'Registering location of recovery tools succeeded'
# }
#Autopilot JSON #Autopilot JSON
If ($APFileToInstall){ If ($APFileToInstall){
WriteLog "Copying $APFileToInstall to W:\windows\provisioning\autopilot" WriteLog "Copying $APFileToInstall to W:\windows\provisioning\autopilot"
@@ -1,10 +0,0 @@
select disk 0
select partition 3
Assign letter="W"
shrink minimum=1000
create partition primary
format quick fs=ntfs label="Recovery"
assign letter="R"
set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"
gpt attributes=0x8000000000000001
exit
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="specialize">
<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>
</component>
</settings>
</unattend>
+101 -7
View File
@@ -1,19 +1,113 @@
# Using Full Flash Update (FFU) files to speed up Windows deployment # Using Full Flash Update (FFU) files to speed up Windows deployment
This repo contains the full FFU process that we use in US Education at Microsoft to help customers with large deployments of Windows as they prepare for the new school year. This process isn't limited to only large deployments at the start of the year, but is the most common. What if you could have a Windows image that has:
This process will copy Windows in about 2-3 minutes to the target device, optionally copy drivers, provisioning packages, Autopilot, etc. School technicians have even given the USB sticks to teachers and teachers calling them their "Magic USB sticks" to quickly get student devices reimaged in the event of an issue with their Windows PC. - The latest Windows cumulative update
- The latest .NET cumulative update
- The latest Windows Defender Platform and Definition Updates
- The latest version of Microsoft Edge
- The latest version of OneDrive (Per-Machine)
- The latest version of Microsoft 365 Apps/Office
- The latest drivers from any of the major OEMs (Dell, HP, Lenovo, Microsoft) (yes, the latest, not some out of date enterprise CAB file from years ago)
- Winget support so you can integrate any app available from Winget directly in your image
- ARM64 support for the latest Copilot+ PCs
- The ability to bring your own drivers and apps if necessary
- Custom WinRE support
While we use this in Education at Microsoft, other industries can use it as well. We esepcially see a need for something like this with partners who do re-imaging on behalf of customers. The difference in Education is that they typically have large deployments that tend to happen at the beginning of the school year and any amount of time saved is helpful. Microsoft Deployment Toolkit, Configuration Manager, and other community solutions are all great solutions, but are typically slower due to WIM deployments being file-based while FFU files are sector-based. And the best part: it takes less than two minutes to apply the image, even with all of these updates added to the media. After setting Windows up and going through Autopilot or a provisioning package, total elapsed time ~10 minutes (depending on what Intune or your device management tool is deploying).
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 # Updates
2406.1 has been released! Check out the changes in the new [Change Log](ChangeLog.md) 2408.1 has been released! Check out the changes in the [Change Log](ChangeLog.md)
# Getting Started # Getting Started
If you're not familiar with Github, you can click the Green code button above and select download zip. Extract the zip file and make sure to copy the FFUDevelopment folder to the root of your C: drive. That will make it easy to follow the guide and allow the scripts to work properly. - Download the latest [release](https://github.com/rbalsleyMSFT/FFU/releases)
- Extract the FFUDevelopment folder from the ZIP file (recommend to C:\FFUDevelopment)
- Follow the doc: C:\FFUDevelopment\Docs\BuildDeployFFU.docx
If extracted correctly, your c:\FFUDevelopment folder should look like the following. If it does, go to c:\FFUDevelopment\Docs\BuildDeployFFU.docx to get started. ## YouTube Detailed Walkthrough
![image](https://github.com/rbalsleyMSFT/FFU/assets/53497092/5400a203-9c2e-42b2-b24c-ab8dfd922ba1) The first 15 minutes of the following video includes a quick start demo to get started. Below the video are a list of chapters. This video was taken with the 2407.2 build. Features released after that will not be demonstrated in the video.
[![Reimage Windows Fast with Full-Flash Update (FFU))](https://img.youtube.com/vi/rqXRbgeeKSQ/maxresdefault.jpg)](https://www.youtube.com/watch?v=rqXRbgeeKSQ "Reimage Windows Fast with Full-Flash Update (FFU))")
Chapters:
[00:00](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=0s) Begin
[03:21](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=201s) Quick Start Prereqs
[07:19](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=439s) Quick Start Demo
[14:12](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=852s) Script Parameters
[17:22](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=1042s) Obtaining Windows Media
[25:55](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=1555s) Adding Applications
[26:59](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=1619s) Adding M365 Apps/Office
[29:21](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=1761s) Adding Applications via Winget
[34:59](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=2099s) Bring your own Applications
[36:01](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=2161s) Customizing InstallAppsAndSysprep.cmd
[38:34](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=2314s) Demo - Application Configuration
[49:43](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=2983s) Drivers
[55:39](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=3339s) Automatically downloading drivers
[57:28](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=3448s) Microsoft Surface drivers
[58:55](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=3535s) Dell drivers
[01:01:45](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=3705s) Lenovo drivers
[01:03:16](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=3796s) HP drivers
[01:05:25](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=3925s) Bring your own drivers
[01:06:24](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=3984s) Demo - Drivers
[01:11:55](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=4315s) Multi-model driver support
[01:13:21](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=4401s) Device naming
[01:18:30](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=4710s) Device enrollment
[01:21:43](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=4903s) Autopilot
[01:24:57](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=5097s) Provisioning packages
[01:26:54](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=5214s) Custom WinRE
[01:29:59](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=5399s) Demo - Putting it all together (Deep dive)
[01:32:06](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=5526s) Downloading Lenovo 500w drivers
[01:33:28](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=5608s) Downloading apps via Winget
[01:36:54](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=5814s) Downloading Office, Defender, Edge, OneDrive
[01:38:15](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=5895s) Building the Apps.iso
[01:39:08](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=5948s) Applying Windows to the VHDX
[01:40:16](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=6016s) Downloading and applying cumulative updates
[01:41:44](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=6104s) Building the VM
[01:48:13](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=6493s) Capturing the FFU
[01:53:38](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=6818s) Creating USB drive
[01:58:41](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=7121s) Deploying FFU
[02:11:48](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=7908s) Troubleshooting
[02:14:30](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=8070s) EDU Endpoint Office Hours
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB