From 8ba88f46267e8b53aacaddeec26a41c4571a162c Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 23 Jul 2024 16:31:16 -0700 Subject: [PATCH 01/23] Fixed an issue with RAW disks and Clear-Disk --- FFUDevelopment/BuildFFUVM.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 3ca7362..1c33439 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -2963,9 +2963,13 @@ Function New-DeploymentUSB { $ScriptBlock = { param($DiskNumber) - Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false - Get-Disk $DiskNumber | Get-Partition | Remove-Partition $Disk = Get-Disk -Number $DiskNumber + # Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false + if ($Disk.PartitionStyle -ne "RAW") { + $Disk | Clear-Disk -RemoveData -RemoveOEM -Confirm:$false + } + # Get-Disk $DiskNumber | Get-Partition | Remove-Partition + $Disk | Get-Partition | Remove-Partition $Disk | Set-Disk -PartitionStyle MBR $BootPartition = $Disk | New-Partition -Size 2GB -IsActive -AssignDriveLetter $DeployPartition = $Disk | New-Partition -UseMaximumSize -AssignDriveLetter From 81a3b10a06796e9126b7ac2c098333dbea1e8571 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Wed, 24 Jul 2024 10:37:41 -0700 Subject: [PATCH 02/23] added $AllowExternalHardDiskMedia variable and modified USB drive creation code to allow for External hard disks --- FFUDevelopment/BuildFFUVM.ps1 | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 1c33439..b2f3249 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -308,9 +308,10 @@ param( "Sec-Fetch-Site" = "none" "Sec-Fetch-User" = "?1" "Upgrade-Insecure-Requests" = "1" - } + }, + [bool]$AllowExternalHardDiskMedia ) -$version = '2407.1' +$version = '2408.1' #Check if Hyper-V feature is installed (requires only checks the module) $osInfo = Get-WmiObject -Class Win32_OperatingSystem @@ -2899,7 +2900,14 @@ Function Get-WindowsVersionInfo { } } Function Get-USBDrive { - $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") + # $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") + + If ($AllowExternalHardDiskMedia) { + $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media' OR MediaType='External hard disk media'") + } + else { + $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") + } If ($USBDrives -and ($null -eq $USBDrives.count)) { $USBDrivesCount = 1 } @@ -2965,12 +2973,20 @@ Function New-DeploymentUSB { param($DiskNumber) $Disk = Get-Disk -Number $DiskNumber # Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false + # Clear-disk has an unusual behavior where it sets external hard disk media as RAW, however removable media is set as MBR. if ($Disk.PartitionStyle -ne "RAW") { $Disk | Clear-Disk -RemoveData -RemoveOEM -Confirm:$false + $Disk = Get-Disk -Number $DiskNumber } - # Get-Disk $DiskNumber | Get-Partition | Remove-Partition - $Disk | Get-Partition | Remove-Partition - $Disk | Set-Disk -PartitionStyle MBR + + if($Disk.PartitionStyle -eq "RAW") { + $Disk | Initialize-Disk -PartitionStyle MBR -Confirm:$false + } + elseif($Disk.PartitionStyle -ne "RAW"){ + $Disk | Get-Partition | Remove-Partition -Confirm:$false + $Disk | Set-Disk -PartitionStyle MBR + } + # Get-Disk $DiskNumber | Get-Partition | Remove-Partition $BootPartition = $Disk | New-Partition -Size 2GB -IsActive -AssignDriveLetter $DeployPartition = $Disk | New-Partition -UseMaximumSize -AssignDriveLetter Format-Volume -Partition $BootPartition -FileSystem FAT32 -NewFileSystemLabel "TempBoot" -Confirm:$false @@ -2981,7 +2997,8 @@ Function New-DeploymentUSB { Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $DiskNumber | Out-null WriteLog 'Done' - $BootPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempBoot' AND DriveType=2 AND DriveLetter IS NOT NULL").Name + # $BootPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempBoot' AND DriveType=2 AND DriveLetter IS NOT NULL").Name + $BootPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempBoot' AND DriveLetter IS NOT NULL").Name $ISOMountPoint = (Mount-DiskImage -ImagePath $DeployISO -PassThru | Get-Volume).DriveLetter + ":\" WriteLog "Copying WinPE files to $BootPartitionDriveLetter" robocopy "$ISOMountPoint" "$BootPartitionDriveLetter" /E /COPYALL /R:5 /W:5 /J @@ -2989,7 +3006,8 @@ Function New-DeploymentUSB { if ($CopyFFU.IsPresent) { if ($null -ne $SelectedFFUFile) { - $DeployPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempDeploy' AND DriveType=2 AND DriveLetter IS NOT NULL").Name + # $DeployPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempDeploy' AND DriveType=2 AND DriveLetter IS NOT NULL").Name + $DeployPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempDeploy' AND DriveLetter IS NOT NULL").Name if ($SelectedFFUFile -is [array]) { WriteLog "Copying multiple FFU files to $DeployPartitionDriveLetter. This could take a few minutes." foreach ($FFUFile in $SelectedFFUFile) { From 06138ebaff4ead0de6b7b827c18ec66efea4c4fd Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Wed, 24 Jul 2024 17:16:30 -0700 Subject: [PATCH 03/23] Added $PromptExternalHardDiskMedia as a new variable defaulted to True to prevent accidentental data loss if external hard disks are detected --- FFUDevelopment/BuildFFUVM.ps1 | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index b2f3249..088461a 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -309,7 +309,8 @@ param( "Sec-Fetch-User" = "?1" "Upgrade-Insecure-Requests" = "1" }, - [bool]$AllowExternalHardDiskMedia + [bool]$AllowExternalHardDiskMedia, + [bool]$PromptExternalHardDiskMedia = $true ) $version = '2408.1' @@ -2901,9 +2902,33 @@ Function Get-WindowsVersionInfo { } Function Get-USBDrive { # $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") - + WriteLog 'Checking for USB drives' If ($AllowExternalHardDiskMedia) { $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media' OR MediaType='External hard disk media'") + if ($PromptExternalHardDiskMedia){ + # List all drives with MediaType='External hard disk media' and have the end user pick which one to use + [array]$ExternalHardDiskDrives = $USBDrives | Where-Object { $_.MediaType -eq 'External hard disk media' } + if ($ExternalHardDiskDrives) { + if ($VerbosePreference -ne 'Continue'){ + Write-Warning 'Found external hard disk media drives' + Write-Warning 'Will prompt for user input to select the drive to use to prevent accidental data loss' + Write-Warning 'If you do not want to be prompted for this in the future, set -PromptExternalHardDiskMedia to $false' + } + WriteLog 'Found external hard disk media drives' + WriteLog 'Will prompt for user input to select the drive to use to prevent accidental data loss' + WriteLog 'If you do not want to be prompted for this in the future, set -PromptExternalHardDiskMedia to $false' + for ($i = 0; $i -lt $ExternalHardDiskDrives.Count; $i++) { + if ($VerbosePreference -ne 'Continue'){ + Write-Host ("{0}: {1}" -f ($i + 1), $ExternalHardDiskDrives[$i].Model) + } + WriteLog ("{0}: {1}" -f ($i + 1), $ExternalHardDiskDrives[$i].Model) + } + $inputChoice = Read-Host "Enter the number corresponding to the external hard disk media drive you want to use" + $selectedIndex = $inputChoice - 1 + $USBDrives = $ExternalHardDiskDrives[$selectedIndex] + } + } + } else { $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") From 70571a3b49267725815e643d68eb023c3ecdcad3 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Fri, 26 Jul 2024 16:04:53 -0700 Subject: [PATCH 04/23] Fixed an issue where Efisys_noprompt.bin was being used for deployment media. This should only be used for capture media --- FFUDevelopment/BuildFFUVM.ps1 | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 088461a..83cdb10 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -2652,11 +2652,21 @@ function New-PEMedia { 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'){ - $OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:2`#p0,e,b`"$OSCDIMGPath\etfsboot.com`"`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`"" - + 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'){ - $OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:1`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`"" + 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" From 689808eca776695e98ca4e02c5bb8497ad885def Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Fri, 26 Jul 2024 16:22:31 -0700 Subject: [PATCH 05/23] commented some variables --- FFUDevelopment/BuildFFUVM.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 83cdb10..7923cc0 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -2616,7 +2616,7 @@ function New-PEMedia { #Remove-Item -Path "$WinPEFFUPath\media\boot\bootfix.bin" -Force | Out-null # $WinPEISOName = 'WinPE_FFU_Capture.iso' $WinPEISOFile = $CaptureISO - $Capture = $false + # $Capture = $false } If ($Deploy) { WriteLog "Copying $FFUDevelopmentPath\WinPEDeployFFUFiles\* to WinPE deploy media" @@ -2636,7 +2636,7 @@ function New-PEMedia { # $WinPEISOName = 'WinPE_FFU_Deploy.iso' $WinPEISOFile = $DeployISO - $Deploy = $false + # $Deploy = $false } WriteLog 'Dismounting WinPE media' Dismount-WindowsImage -Path "$WinPEFFUPath\mount" -Save | Out-Null From 047881934af0aa9bc1f3ba8320eb7a196cefbb0d Mon Sep 17 00:00:00 2001 From: Doctair Date: Tue, 30 Jul 2024 13:57:54 -0400 Subject: [PATCH 06/23] Add Logic to catch the disk selection of USB External drives so that it will not accept a Letter --- FFUDevelopment/BuildFFUVM.ps1 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 7923cc0..b03eff3 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -2935,7 +2935,14 @@ Function Get-USBDrive { } $inputChoice = Read-Host "Enter the number corresponding to the external hard disk media drive you want to use" $selectedIndex = $inputChoice - 1 - $USBDrives = $ExternalHardDiskDrives[$selectedIndex] + + if ($selectedIndex -ge 0 -and $selectedIndex -lt $ExternalHardDiskDrives.Count) { + $USBDrives = $ExternalHardDiskDrives[$selectedIndex] + } else { + Write-Error "Invalid selection. Exiting." + exit 1 + } + } } From 39b9d06d21e4e932ee98cdf3e5db1cd5c0b1214b Mon Sep 17 00:00:00 2001 From: Doctair Date: Tue, 30 Jul 2024 16:11:07 -0400 Subject: [PATCH 07/23] Correct Logic for Dirve letters and add Dirve Info to the write-host selection for Disks. --- FFUDevelopment/BuildFFUVM.ps1 | 36 ++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index b03eff3..5d8b058 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -2927,22 +2927,44 @@ Function Get-USBDrive { WriteLog 'Found external hard disk media drives' WriteLog 'Will prompt for user input to select the drive to use to prevent accidental data loss' WriteLog 'If you do not want to be prompted for this in the future, set -PromptExternalHardDiskMedia to $false' + for ($i = 0; $i -lt $ExternalHardDiskDrives.Count; $i++) { + $ExternalDiskNumber = $ExternalHardDiskDrives[$i].DeviceID.Replace("\\.\PHYSICALDRIVE", "") + $ExternalDisk = Get-Disk -Number $ExternalDiskNumber if ($VerbosePreference -ne 'Continue'){ - Write-Host ("{0}: {1}" -f ($i + 1), $ExternalHardDiskDrives[$i].Model) + # Write-Host ("{0}: {1}" -f ($i + 1), $ExternalHardDiskDrives[$i].Model) + Write-Host ("Drive {0}: {1} SN/{2} PartitionStyle={3} Status={4}" -f ($i + 1), $ExternalDisk.FriendlyName , $ExternalHardDiskDrives[$i].serialnumber, $ExternalDisk.PartitionStyle,$ExternalDisk.OperationalStatus ) -ForegroundColor Green } - WriteLog ("{0}: {1}" -f ($i + 1), $ExternalHardDiskDrives[$i].Model) + WriteLog ("Drive {0}: {1} SN/{2} PartitionStyle={3} Status={4}" -f ($i + 1), $ExternalDisk.FriendlyName , $ExternalHardDiskDrives[$i].serialnumber, $ExternalDisk.PartitionStyle,$ExternalDisk.OperationalStatus ) } - $inputChoice = Read-Host "Enter the number corresponding to the external hard disk media drive you want to use" - $selectedIndex = $inputChoice - 1 - + while ($true) { + try { + # Ask the user for input + #$userInput = Read-Host "Please enter a number" + $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) + + # Convert the input to a float + $ISnumber = [float]$inputChoice + + # Display the entered number + Write-Host "You selected Disk: $ISnumber" + $selectedIndex = $inputChoice - 1 + break + } + catch { + # If the input is not a valid number, display an error message + Write-Host "Invalid input. Please try again." + } + } + + if ($selectedIndex -ge 0 -and $selectedIndex -lt $ExternalHardDiskDrives.Count) { $USBDrives = $ExternalHardDiskDrives[$selectedIndex] } else { - Write-Error "Invalid selection. Exiting." + Write-Warning "Invalid selection. Exiting." | Out-Null exit 1 } - + } } From 49b742b47b22679b9ae5f307a7a6e806dcda5269 Mon Sep 17 00:00:00 2001 From: Doctair Date: Fri, 2 Aug 2024 11:35:18 -0400 Subject: [PATCH 08/23] 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 --- FFUDevelopment/BuildFFUVM.ps1 | 139 +++++++++++++++++++++++----------- 1 file changed, 96 insertions(+), 43 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 5d8b058..50b3bb5 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -2616,7 +2616,7 @@ function New-PEMedia { #Remove-Item -Path "$WinPEFFUPath\media\boot\bootfix.bin" -Force | Out-null # $WinPEISOName = 'WinPE_FFU_Capture.iso' $WinPEISOFile = $CaptureISO - # $Capture = $false + $Capture = $false } If ($Deploy) { WriteLog "Copying $FFUDevelopmentPath\WinPEDeployFFUFiles\* to WinPE deploy media" @@ -2636,7 +2636,7 @@ function New-PEMedia { # $WinPEISOName = 'WinPE_FFU_Deploy.iso' $WinPEISOFile = $DeployISO - # $Deploy = $false + $Deploy = $false } WriteLog 'Dismounting WinPE media' Dismount-WindowsImage -Path "$WinPEFFUPath\mount" -Save | Out-Null @@ -2652,21 +2652,11 @@ function New-PEMedia { 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`"" - } + $OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:2`#p0,e,b`"$OSCDIMGPath\etfsboot.com`"`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.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`"" - } - + $OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:1`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`"" } Invoke-Process $OSCDIMG $OSCDIMGArgs WriteLog "ISO created successfully" @@ -2959,7 +2949,14 @@ Function Get-USBDrive { if ($selectedIndex -ge 0 -and $selectedIndex -lt $ExternalHardDiskDrives.Count) { - $USBDrives = $ExternalHardDiskDrives[$selectedIndex] + if ($ExternalDisk.OperationalStatus -eq 'Offline') { + Write-Warning "Selected Drive is in an Offline State. Please check the drive status in Disk Manager and try again." + exit 1 + } + else { + $USBDrives = $ExternalHardDiskDrives[$selectedIndex] + } + } else { Write-Warning "Invalid selection. Exiting." | Out-Null exit 1 @@ -2996,35 +2993,74 @@ Function New-DeploymentUSB { WriteLog "BuildUSBPath is $BuildUSBPath" $SelectedFFUFile = $null - + if ($CopyFFU.IsPresent) { $FFUFiles = Get-ChildItem -Path "$BuildUSBPath\FFU" -Filter "*.ffu" - if ($FFUFiles.Count -eq 1) { - $SelectedFFUFile = $FFUFiles.FullName - } - elseif ($FFUFiles.Count -gt 1) { - WriteLog 'Found multiple FFU files' - for ($i = 0; $i -lt $FFUFiles.Count; $i++) { - WriteLog ("{0}: {1}" -f ($i + 1), $FFUFiles[$i].Name) - } - $inputChoice = Read-Host "Enter the number corresponding to the FFU file you want to copy or 'A' to copy all FFU files" - - if ($inputChoice -eq 'A') { - $SelectedFFUFile = $FFUFiles.FullName - } - elseif ($inputChoice -ge 1 -and $inputChoice -le $FFUFiles.Count) { - $selectedIndex = $inputChoice - 1 - $SelectedFFUFile = $FFUFiles[$selectedIndex].FullName - } - WriteLog "$SelectedFFUFile was selected" - } - else { - WriteLog "No FFU files found in the current directory." - Write-Error "No FFU files found in the current directory." - Return - } - } + + if (-not $FFUFiles) { + # WriteLog "No FFU files found in the current directory." + Write-Error "No FFU files found in the current directory." + Return + } + + elseif ($FFUFiles.Count -eq 1) { + $SelectedFFUFile = $FFUFiles.FullName + } + elseif ($FFUFiles.Count -gt 1) { + WriteLog 'Found multiple FFU files' + Write-Warning 'Found multiple FFU files' + for ($i = 0; $i -lt $FFUFiles.Count; $i++) { + WriteLog ("FFU {0}: {1} Modified: {2}" -f ($i + 1), $FFUFiles[$i].Name, $FFUFiles[$i].LastWriteTime) + if ($VerbosePreference -ne 'Continue') { + Write-Host ("FFU {0}: {1} Modified: {2}" -f ($i + 1), $FFUFiles[$i].Name, $FFUFiles[$i].LastWriteTime) -ForegroundColor Green + } + + } + #$inputChoice = Read-Host "Enter the number corresponding to the FFU file you want to copy or 'A' to copy all FFU files" + $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) + + Write-Host "You selected FFU: $inputChoice" + WriteLog "You selected FFU: $inputChoice" + + while ($true) { + if ($inputChoice -eq 'A') { + $SelectedFFUFile = $FFUFiles.FullName + Write-Host "You selected $inputChoice" + break + } + + try { + + # $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) + + # Convert the input to a float + $ISnumber = [float]$inputChoice + + # Display the entered number for debuggin + #Write-Host "You selected Disk: $ISnumber" + + } + catch { + # If the input is not a valid number, display an error message + Write-Host "Invalid input. Please try again." + + } + if ($inputChoice -ge 1 -and $inputChoice -le $FFUFiles.Count) { + $selectedIndex = $inputChoice - 1 + Write-Host "You Selected FFU $selectedIndex" + $SelectedFFUFile = $FFUFiles[$selectedIndex].FullName + break + } + else{ + Write-Host "Invalid FFU Number. Please try again." + $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) + } + } + WriteLog "$SelectedFFUFile was selected" + Write-Host "$SelectedFFUFile was selected" + } + } $counter = 0 foreach ($USBDrive in $USBDrives) { @@ -3314,7 +3350,9 @@ function Clear-InstallAppsandSysprep { if (Test-Path -Path $Logfile) { Remove-item -Path $LogFile -Force } -Write-Host "FFU build process has begun. This process can take 20 minutes or more. Please do not close this window or any additional windows that pop up" +$startTime = Get-Date +Write-Host "FFU build process has begun at" $startTime -ForegroundColor DarkYellow +Write-Host "This process can take 20 minutes or more. Please do not close this window or any additional windows that pop up" Write-Host "To track progress, please open the log file $Logfile or use the -Verbose parameter next time" WriteLog 'Begin Logging' @@ -3968,4 +4006,19 @@ Remove-Item -Path .\dirty.txt -Force | out-null if ($VerbosePreference -ne 'Continue'){ Write-Host 'Script complete' } +# Record the end time +$endTime = Get-Date +Write-Host "FFU build process has completed at" $endTime -ForegroundColor DarkYellow + +# Calculate the total run time +$runTime = $endTime - $startTime +$runTimeInMinutes = [math]::Round($runTime.TotalMinutes, 2) + +# Format the runtime as minutes and seconds +$runTimeFormatted = 'Duration: {0:mm} min {0:ss} sec' -f $runTime + +Write-Host $runTimeFormatted -ForegroundColor DarkGreen + + + WriteLog 'Script complete' From 1bfc4735d3c4c18dae5628afc356ff6c9a905b61 Mon Sep 17 00:00:00 2001 From: Doctair Date: Fri, 2 Aug 2024 11:52:51 -0400 Subject: [PATCH 09/23] Sync arm64 changes and Rem $Capture False --- FFUDevelopment/BuildFFUVM.ps1 | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 50b3bb5..49f0429 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -2616,7 +2616,7 @@ function New-PEMedia { #Remove-Item -Path "$WinPEFFUPath\media\boot\bootfix.bin" -Force | Out-null # $WinPEISOName = 'WinPE_FFU_Capture.iso' $WinPEISOFile = $CaptureISO - $Capture = $false + # $Capture = $false } If ($Deploy) { WriteLog "Copying $FFUDevelopmentPath\WinPEDeployFFUFiles\* to WinPE deploy media" @@ -2636,7 +2636,7 @@ function New-PEMedia { # $WinPEISOName = 'WinPE_FFU_Deploy.iso' $WinPEISOFile = $DeployISO - $Deploy = $false + # $Deploy = $false } WriteLog 'Dismounting WinPE media' Dismount-WindowsImage -Path "$WinPEFFUPath\mount" -Save | Out-Null @@ -2652,11 +2652,21 @@ function New-PEMedia { 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'){ - $OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:2`#p0,e,b`"$OSCDIMGPath\etfsboot.com`"`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`"" - + 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'){ - $OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:1`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`"" + 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" From e3bec5ff4507a3424325208cda0c68564ed443f3 Mon Sep 17 00:00:00 2001 From: Doctair Date: Fri, 2 Aug 2024 12:02:58 -0400 Subject: [PATCH 10/23] Clean up some Remmed Lines and Added some Comments for explanation --- FFUDevelopment/BuildFFUVM.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 49f0429..1bf1021 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -2946,7 +2946,7 @@ Function Get-USBDrive { # Convert the input to a float $ISnumber = [float]$inputChoice - # Display the entered number + # Display the entered number used for Debugging Write-Host "You selected Disk: $ISnumber" $selectedIndex = $inputChoice - 1 break @@ -2959,7 +2959,8 @@ Function Get-USBDrive { if ($selectedIndex -ge 0 -and $selectedIndex -lt $ExternalHardDiskDrives.Count) { - if ($ExternalDisk.OperationalStatus -eq 'Offline') { + #Check if Selected Drive is in an Offline State. Useful when presenting the FFU Driv to Hyper-V VMs and forget to Online Again + if ($ExternalDisk.OperationalStatus -eq 'Offline') { Write-Warning "Selected Drive is in an Offline State. Please check the drive status in Disk Manager and try again." exit 1 } @@ -3041,9 +3042,7 @@ Function New-DeploymentUSB { } try { - - # $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) - + # Convert the input to a float $ISnumber = [float]$inputChoice @@ -3062,7 +3061,8 @@ Function New-DeploymentUSB { $SelectedFFUFile = $FFUFiles[$selectedIndex].FullName break } - else{ + else{ + #No correct input so prompt again and repeat Checks. Write-Host "Invalid FFU Number. Please try again." $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) } From 9de55eb18634881347889bd040f0b92b84dcb641 Mon Sep 17 00:00:00 2001 From: Doctair Date: Fri, 2 Aug 2024 12:11:54 -0400 Subject: [PATCH 11/23] Comment Better --- FFUDevelopment/BuildFFUVM.ps1 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 1bf1021..39a3b24 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -3035,6 +3035,7 @@ Function New-DeploymentUSB { WriteLog "You selected FFU: $inputChoice" while ($true) { + #If 'A' is selected copy all the FFUs found if ($inputChoice -eq 'A') { $SelectedFFUFile = $FFUFiles.FullName Write-Host "You selected $inputChoice" @@ -3043,7 +3044,7 @@ Function New-DeploymentUSB { try { - # Convert the input to a float + # Try to Convert the inputChoice to a float $ISnumber = [float]$inputChoice # Display the entered number for debuggin @@ -3051,10 +3052,11 @@ Function New-DeploymentUSB { } catch { - # If the input is not a valid number, display an error message + # If inputChoice is not a valid number, must have been a character, so display an error message Write-Host "Invalid input. Please try again." } + # If InputChoice is a number check that its withing the range of if ($inputChoice -ge 1 -and $inputChoice -le $FFUFiles.Count) { $selectedIndex = $inputChoice - 1 Write-Host "You Selected FFU $selectedIndex" @@ -3062,7 +3064,7 @@ Function New-DeploymentUSB { break } else{ - #No correct input so prompt again and repeat Checks. + #No correct input for FFU selection, so prompt again and repeat Checks. Write-Host "Invalid FFU Number. Please try again." $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) } From 213da613894e4ff76e75ad525ddf80c24bc107ac Mon Sep 17 00:00:00 2001 From: Doctair Date: Fri, 2 Aug 2024 12:20:17 -0400 Subject: [PATCH 12/23] Fix REad-Host Prompt message for FFU selecion --- FFUDevelopment/BuildFFUVM.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 39a3b24..a17af1d 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -3029,7 +3029,7 @@ Function New-DeploymentUSB { } #$inputChoice = Read-Host "Enter the number corresponding to the FFU file you want to copy or 'A' to copy all FFU files" - $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) + $inputChoice = $(Write-Host "Enter the number corresponding to the FFU file you want to copy or 'A' to copy all FFU files: " -ForegroundColor DarkYellow -NoNewline; Read-Host) Write-Host "You selected FFU: $inputChoice" WriteLog "You selected FFU: $inputChoice" @@ -3066,7 +3066,7 @@ Function New-DeploymentUSB { else{ #No correct input for FFU selection, so prompt again and repeat Checks. Write-Host "Invalid FFU Number. Please try again." - $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) + $inputChoice = $(Write-Host "Enter the number corresponding to the FFU file you want to copy or 'A' to copy all FFU files: " -ForegroundColor DarkYellow -NoNewline; Read-Host) } } WriteLog "$SelectedFFUFile was selected" From 7b59e3d0ecc687ea1f8799f0afba23fb1cb7b775 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Fri, 2 Aug 2024 10:53:50 -0700 Subject: [PATCH 13/23] Fixed an issue with clean up of Defender, OneDrive, and Edge. Fixed an issue with the formatting of InstallAppsandSysprep.cmd file. --- FFUDevelopment/BuildFFUVM.ps1 | 40 +++--- FFUDevelopment/Create-PEMedia.ps1 | 209 ++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 20 deletions(-) create mode 100644 FFUDevelopment/Create-PEMedia.ps1 diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 7923cc0..e675e49 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -1637,8 +1637,8 @@ function Get-Office { $officeCommand = "d:\Office\setup.exe /configure d:\Office\DeployFFU.xml" # Check if Office command is not commented out or missing and fix it if it is - if ($content[2] -ne $officeCommand) { - $content[2] = $officeCommand + if ($content[3] -ne $officeCommand) { + $content[3] = $officeCommand # Write the modified content back to the file Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $content @@ -3200,34 +3200,34 @@ function Get-FFUEnvironment { #Clean up $KBPath If (Test-Path -Path $KBPath) { WriteLog "Removing $KBPath" - Remove-Item -Path $KBPath -Recurse -Force + Remove-Item -Path $KBPath -Recurse -Force -ErrorAction SilentlyContinue WriteLog 'Removal complete' } #Clean up $DefenderPath If (Test-Path -Path $DefenderPath) { WriteLog "Removing $DefenderPath" - Remove-Item -Path $DefenderPath -Recurse -Force + Remove-Item -Path $DefenderPath -Recurse -Force -ErrorAction SilentlyContinue WriteLog 'Removal complete' } #Clean up $OneDrivePath If (Test-Path -Path $OneDrivePath) { WriteLog "Removing $OneDrivePath" - Remove-Item -Path $OneDrivePath -Recurse -Force + Remove-Item -Path $OneDrivePath -Recurse -Force -ErrorAction SilentlyContinue WriteLog 'Removal complete' } #Clean up $EdgePath If (Test-Path -Path $EdgePath) { WriteLog "Removing $EdgePath" - Remove-Item -Path $EdgePath -Recurse -Force + Remove-Item -Path $EdgePath -Recurse -Force -ErrorAction SilentlyContinue WriteLog 'Removal complete' } if (Test-Path -Path "$AppsPath\Win32" -PathType Container) { WriteLog "Cleaning up Win32 folder" - Remove-Item -Path "$AppsPath\Win32" -Recurse -Force + Remove-Item -Path "$AppsPath\Win32" -Recurse -Force -ErrorAction SilentlyContinue } if (Test-Path -Path "$AppsPath\MSStore" -PathType Container) { WriteLog "Cleaning up MSStore folder" - Remove-Item -Path "$AppsPath\MSStore" -Recurse -Force + Remove-Item -Path "$AppsPath\MSStore" -Recurse -Force -ErrorAction SilentlyContinue } Clear-InstallAppsandSysprep Writelog 'Removing dirty.txt file' @@ -3253,29 +3253,29 @@ function Clear-InstallAppsandSysprep { WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove Defender Platform Update" $CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" $CmdContent -notmatch 'd:\\Defender*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" - #Remove $DefenderPath - WriteLog "Removing $DefenderPath" - Remove-Item -Path $DefenderPath -Recurse -Force - WriteLog "Removal complete" + # #Remove $DefenderPath + # WriteLog "Removing $DefenderPath" + # Remove-Item -Path $DefenderPath -Recurse -Force + # WriteLog "Removal complete" } if ($UpdateOneDrive) { WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove OneDrive install" $CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" $CmdContent -notmatch 'd:\\OneDrive*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" - #Remove $OneDrivePath - WriteLog "Removing $OneDrivePath" - Remove-Item -Path $OneDrivePath -Recurse -Force - WriteLog "Removal complete" + # #Remove $OneDrivePath + # WriteLog "Removing $OneDrivePath" + # Remove-Item -Path $OneDrivePath -Recurse -Force + # WriteLog "Removal complete" } if ($UpdateEdge) { WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove Edge install" $CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" $CmdContent -notmatch 'd:\\Edge*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" - #Remove $EdgePath - WriteLog "Removing $EdgePath" - Remove-Item -Path $EdgePath -Recurse -Force - WriteLog "Removal complete" + # #Remove $EdgePath + # WriteLog "Removing $EdgePath" + # Remove-Item -Path $EdgePath -Recurse -Force + # WriteLog "Removal complete" } } diff --git a/FFUDevelopment/Create-PEMedia.ps1 b/FFUDevelopment/Create-PEMedia.ps1 new file mode 100644 index 0000000..2b641af --- /dev/null +++ b/FFUDevelopment/Create-PEMedia.ps1 @@ -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 +} \ No newline at end of file From e1ab74e5a3d1dbdc1433cf29075d97aacb80521e Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:43:23 -0700 Subject: [PATCH 14/23] 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. --- FFUDevelopment/BuildFFUVM.ps1 | 326 +++++++++++++++++++++------------- README.md | 71 +++++++- 2 files changed, 265 insertions(+), 132 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index d2d91c2..33870e2 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -2911,15 +2911,22 @@ Function Get-WindowsVersionInfo { } } Function Get-USBDrive { - # $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") + # Log the start of the USB drive check WriteLog 'Checking for USB drives' + + # Check if external hard disk media is allowed If ($AllowExternalHardDiskMedia) { - $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media' OR MediaType='External hard disk media'") - if ($PromptExternalHardDiskMedia){ - # List all drives with MediaType='External hard disk media' and have the end user pick which one to use - [array]$ExternalHardDiskDrives = $USBDrives | Where-Object { $_.MediaType -eq 'External hard disk media' } + # Get all removable and external hard disk media drives + [array]$USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media' OR MediaType='External hard disk media'") + [array]$ExternalHardDiskDrives = $USBDrives | Where-Object { $_.MediaType -eq 'External hard disk media' } + $ExternalCount = $ExternalHardDiskDrives.Count + $USBDrivesCount = $USBDrives.Count + + # Check if user should be prompted for external hard disk media + if ($PromptExternalHardDiskMedia) { if ($ExternalHardDiskDrives) { - if ($VerbosePreference -ne 'Continue'){ + # Log and warn about found external hard disk media drives + if ($VerbosePreference -ne 'Continue') { Write-Warning 'Found external hard disk media drives' Write-Warning 'Will prompt for user input to select the drive to use to prevent accidental data loss' Write-Warning 'If you do not want to be prompted for this in the future, set -PromptExternalHardDiskMedia to $false' @@ -2928,71 +2935,105 @@ Function Get-USBDrive { WriteLog 'Will prompt for user input to select the drive to use to prevent accidental data loss' WriteLog 'If you do not want to be prompted for this in the future, set -PromptExternalHardDiskMedia to $false' + # Prepare output for user selection + $Output = @() for ($i = 0; $i -lt $ExternalHardDiskDrives.Count; $i++) { - $ExternalDiskNumber = $ExternalHardDiskDrives[$i].DeviceID.Replace("\\.\PHYSICALDRIVE", "") - $ExternalDisk = Get-Disk -Number $ExternalDiskNumber - if ($VerbosePreference -ne 'Continue'){ - # Write-Host ("{0}: {1}" -f ($i + 1), $ExternalHardDiskDrives[$i].Model) - Write-Host ("Drive {0}: {1} SN/{2} PartitionStyle={3} Status={4}" -f ($i + 1), $ExternalDisk.FriendlyName , $ExternalHardDiskDrives[$i].serialnumber, $ExternalDisk.PartitionStyle,$ExternalDisk.OperationalStatus ) -ForegroundColor Green + $ExternalDiskNumber = $ExternalHardDiskDrives[$i].Index + $ExternalDisk = Get-Disk -Number $ExternalDiskNumber + $Index = $i + 1 + $Name = $ExternalDisk.FriendlyName + $SerialNumber = $ExternalHardDiskDrives[$i].serialnumber + $PartitionStyle = $ExternalDisk.PartitionStyle + $Status = $ExternalDisk.OperationalStatus + $Properties = [ordered]@{ + 'Drive Number' = $Index + 'Drive Name' = $Name + 'Serial Number' = $SerialNumber + 'Partition Style' = $PartitionStyle + 'Status' = $Status } - WriteLog ("Drive {0}: {1} SN/{2} PartitionStyle={3} Status={4}" -f ($i + 1), $ExternalDisk.FriendlyName , $ExternalHardDiskDrives[$i].serialnumber, $ExternalDisk.PartitionStyle,$ExternalDisk.OperationalStatus ) + $Output += New-Object PSObject -Property $Properties } - while ($true) { - try { - # Ask the user for input - #$userInput = Read-Host "Please enter a number" - $inputChoice = $(Write-Host "Enter the number corresponding to the external hard disk media drive you want to use: " -ForegroundColor DarkYellow -NoNewline; Read-Host) - # Convert the input to a float - $ISnumber = [float]$inputChoice + # Format and display the output + $FormattedOutput = $Output | Format-Table -AutoSize -Property 'Drive Number', 'Drive Name', 'Serial Number', 'Partition Style', 'Status' | Out-String + if ($VerbosePreference -ne 'Continue') { + $FormattedOutput | Out-Host + } + WriteLog $FormattedOutput - # Display the entered number used for Debugging - Write-Host "You selected Disk: $ISnumber" - $selectedIndex = $inputChoice - 1 - break + # Prompt user to select a drive + do { + $inputChoice = Read-Host "Enter the number corresponding to the external hard disk media drive you want to use" + if ($inputChoice -match '^\d+$') { + $inputChoice = [int]$inputChoice + if ($inputChoice -ge 1 -and $inputChoice -le $ExternalCount) { + $SelectedIndex = $inputChoice - 1 + $ExternalDiskNumber = $ExternalHardDiskDrives[$SelectedIndex].Index + $ExternalDisk = Get-Disk -Number $ExternalDiskNumber + $USBDrives = $ExternalHardDiskDrives[$SelectedIndex] + $USBDrivesCount = $USBDrives.Count + if ($VerbosePreference -ne 'Continue') { + Write-Host "Drive $inputChoice was selected" + } + WriteLog "Drive $inputChoice was selected" } - catch { - # If the input is not a valid number, display an error message - Write-Host "Invalid input. Please try again." + else { + # Handle invalid selection + if ($VerbosePreference -ne 'Continue') { + Write-Host "Invalid selection. Please try again." + } + WriteLog "Invalid selection. Please try again." + } + + # Check if the selected drive is offline + if ($ExternalDisk.OperationalStatus -eq 'Offline') { + if ($VerbosePreference -ne 'Continue') { + Write-Error "Selected Drive is in an Offline State. Please check the drive status in Disk Manager and try again." + } + WriteLog "Selected Drive is in an Offline State. Please check the drive status in Disk Manager and try again." + exit 1 } - } - - - if ($selectedIndex -ge 0 -and $selectedIndex -lt $ExternalHardDiskDrives.Count) { - #Check if Selected Drive is in an Offline State. Useful when presenting the FFU Driv to Hyper-V VMs and forget to Online Again - if ($ExternalDisk.OperationalStatus -eq 'Offline') { - Write-Warning "Selected Drive is in an Offline State. Please check the drive status in Disk Manager and try again." - exit 1 } else { - $USBDrives = $ExternalHardDiskDrives[$selectedIndex] + # Handle invalid input + if ($VerbosePreference -ne 'Continue') { + Write-Host "Invalid selection. Please try again." + } + WriteLog "Invalid selection. Please try again." } - - } else { - Write-Warning "Invalid selection. Exiting." | Out-Null - exit 1 - } - + } while ($null -eq $selectedIndex) + } + } + else { + # Log the count of found USB drives + if ($VerbosePreference -ne 'Continue') { + Write-Host "Found $USBDrivesCount total USB drives" + If ($ExternalCount -gt 0) { + Write-Host "$ExternalCount are external drives" + } + } + WriteLog "Found $USBDrivesCount total USB drives" + If ($ExternalCount -gt 0) { + WriteLog "$ExternalCount are external drives" } } - - } - else { - $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") - } - If ($USBDrives -and ($null -eq $USBDrives.count)) { - $USBDrivesCount = 1 } else { + # Get only removable media drives + [array]$USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") $USBDrivesCount = $USBDrives.Count + WriteLog "Found $USBDrivesCount Removable USB drives" } - WriteLog "Found $USBDrivesCount USB drives" - + + # Check if any USB drives were found if ($null -eq $USBDrives) { WriteLog "No removable USB drive found. Exiting" Write-Error "No removable USB drive found. Exiting" exit 1 } + + # Return the found USB drives and their count return $USBDrives, $USBDrivesCount } Function New-DeploymentUSB { @@ -3004,75 +3045,88 @@ Function New-DeploymentUSB { WriteLog "BuildUSBPath is $BuildUSBPath" $SelectedFFUFile = $null - + + # Check if the CopyFFU switch is present if ($CopyFFU.IsPresent) { + # Get all FFU files in the specified directory $FFUFiles = Get-ChildItem -Path "$BuildUSBPath\FFU" -Filter "*.ffu" + $FFUCount = $FFUFiles.count - - if (-not $FFUFiles) { - # WriteLog "No FFU files found in the current directory." - Write-Error "No FFU files found in the current directory." - Return - } - - elseif ($FFUFiles.Count -eq 1) { - $SelectedFFUFile = $FFUFiles.FullName - } - elseif ($FFUFiles.Count -gt 1) { - WriteLog 'Found multiple FFU files' - Write-Warning 'Found multiple FFU files' - for ($i = 0; $i -lt $FFUFiles.Count; $i++) { - WriteLog ("FFU {0}: {1} Modified: {2}" -f ($i + 1), $FFUFiles[$i].Name, $FFUFiles[$i].LastWriteTime) - if ($VerbosePreference -ne 'Continue') { - Write-Host ("FFU {0}: {1} Modified: {2}" -f ($i + 1), $FFUFiles[$i].Name, $FFUFiles[$i].LastWriteTime) -ForegroundColor Green - } - - } - #$inputChoice = Read-Host "Enter the number corresponding to the FFU file you want to copy or 'A' to copy all FFU files" - $inputChoice = $(Write-Host "Enter the number corresponding to the FFU file you want to copy or 'A' to copy all FFU files: " -ForegroundColor DarkYellow -NoNewline; Read-Host) - - Write-Host "You selected FFU: $inputChoice" - WriteLog "You selected FFU: $inputChoice" - - while ($true) { - #If 'A' is selected copy all the FFUs found - if ($inputChoice -eq 'A') { - $SelectedFFUFile = $FFUFiles.FullName - Write-Host "You selected $inputChoice" - break - } - - try { - - # Try to Convert the inputChoice to a float - $ISnumber = [float]$inputChoice - - # Display the entered number for debuggin - #Write-Host "You selected Disk: $ISnumber" - - } - catch { - # If inputChoice is not a valid number, must have been a character, so display an error message - Write-Host "Invalid input. Please try again." - - } - # If InputChoice is a number check that its withing the range of - if ($inputChoice -ge 1 -and $inputChoice -le $FFUFiles.Count) { - $selectedIndex = $inputChoice - 1 - Write-Host "You Selected FFU $selectedIndex" - $SelectedFFUFile = $FFUFiles[$selectedIndex].FullName - break - } - else{ - #No correct input for FFU selection, so prompt again and repeat Checks. - Write-Host "Invalid FFU Number. Please try again." - $inputChoice = $(Write-Host "Enter the number corresponding to the FFU file you want to copy or 'A' to copy all FFU files: " -ForegroundColor DarkYellow -NoNewline; Read-Host) - } - } - WriteLog "$SelectedFFUFile was selected" - Write-Host "$SelectedFFUFile was selected" - } - } + # If there is exactly one FFU file, select it + if ($FFUCount -eq 1) { + $SelectedFFUFile = $FFUFiles.FullName + } + # If there are multiple FFU files, prompt the user to select one + elseif ($FFUCount -gt 1) { + WriteLog "Found $FFUCount FFU files" + if($VerbosePreference -ne 'Continue'){ + Write-Host "Found $FFUCount FFU files" + } + $output = @() + # Create a table of FFU files with their index, name, and last modified date + for ($i = 0; $i -lt $FFUCount; $i++) { + $index = $i + 1 + $name = $FFUFiles[$i].Name + $modified = $FFUFiles[$i].LastWriteTime + $Properties = [ordered]@{ + 'FFU Number' = $index + 'FFU Name' = $name + 'Last Modified' = $modified + } + $output += New-Object PSObject -Property $Properties + } + $output | Format-Table -AutoSize -Property 'FFU Number', 'FFU Name', 'Last Modified' + + # Loop until a valid FFU file is selected + do { + $inputChoice = Read-Host "Enter the number corresponding to the FFU file you want to copy or 'A' to copy all FFU files" + # Check if the input is a valid number or 'A' + if ($inputChoice -match '^\d+$' -or $inputChoice -eq 'A') { + if ($inputChoice -eq 'A') { + # Select all FFU files + $SelectedFFUFile = $FFUFiles.FullName + if ($VerbosePreference -ne 'Continue') { + Write-Host 'Will copy all FFU files' + } + WriteLog 'Will copy all FFU Files' + } + else { + # Convert input to integer and validate the selection + $inputChoice = [int]$inputChoice + if ($inputChoice -ge 1 -and $inputChoice -le $FFUCount) { + $selectedIndex = $inputChoice - 1 + $SelectedFFUFile = $FFUFiles[$selectedIndex].FullName + if ($VerbosePreference -ne 'Continue') { + Write-Host "$SelectedFFUFile was selected" + } + WriteLog "$SelectedFFUFile was selected" + } + else { + # Handle invalid selection + if ($VerbosePreference -ne 'Continue') { + Write-Host "Invalid selection. Please try again." + } + WriteLog "Invalid selection. Please try again." + } + } + } + else { + # Handle invalid input + if ($VerbosePreference -ne 'Continue') { + Write-Host "Invalid selection. Please try again." + } + WriteLog "Invalid selection. Please try again." + } + } while ($null -eq $SelectedFFUFile) + + } + else { + # Handle case where no FFU files are found + WriteLog "No FFU files found in the current directory." + Write-Error "No FFU files found in the current directory." + Return + } + } $counter = 0 foreach ($USBDrive in $USBDrives) { @@ -3363,7 +3417,7 @@ if (Test-Path -Path $Logfile) { Remove-item -Path $LogFile -Force } $startTime = Get-Date -Write-Host "FFU build process has begun at" $startTime -ForegroundColor DarkYellow +Write-Host "FFU build process started at" $startTime Write-Host "This process can take 20 minutes or more. Please do not close this window or any additional windows that pop up" Write-Host "To track progress, please open the log file $Logfile or use the -Verbose parameter next time" @@ -3874,7 +3928,7 @@ Catch { throw $_ } -#Clean up ffu_user and Share +#Clean up ffu_user and Share and clean up apps If ($InstallApps) { try { Remove-FFUUserShare @@ -3885,6 +3939,30 @@ If ($InstallApps) { Remove-FFUVM -VMName $VMName throw $_ } + #Clean up InstallAppsandSysprep.cmd + try { + WriteLog "Cleaning up $AppsPath\InstallAppsandSysprep.cmd" + Clear-InstallAppsandSysprep + } + catch { + Write-Host 'Cleaning up InstallAppsandSysprep.cmd failed' + Writelog "Cleaning up InstallAppsandSysprep.cmd failed with error $_" + throw $_ + } + try { + if (Test-Path -Path "$AppsPath\Win32" -PathType Container) { + WriteLog "Cleaning up Win32 folder" + Remove-Item -Path "$AppsPath\Win32" -Recurse -Force + } + if (Test-Path -Path "$AppsPath\MSStore" -PathType Container) { + WriteLog "Cleaning up MSStore folder" + Remove-Item -Path "$AppsPath\MSStore" -Recurse -Force + } + } + catch { + WriteLog "$_" + throw $_ + } } #Clean up VM or VHDX try { @@ -4020,17 +4098,15 @@ if ($VerbosePreference -ne 'Continue'){ } # Record the end time $endTime = Get-Date -Write-Host "FFU build process has completed at" $endTime -ForegroundColor DarkYellow +Write-Host "FFU build process completed at" $endTime # Calculate the total run time $runTime = $endTime - $startTime -$runTimeInMinutes = [math]::Round($runTime.TotalMinutes, 2) # Format the runtime as minutes and seconds $runTimeFormatted = 'Duration: {0:mm} min {0:ss} sec' -f $runTime -Write-Host $runTimeFormatted -ForegroundColor DarkGreen - - - -WriteLog 'Script complete' +if ($VerbosePreference -ne 'Continue'){ + Write-Host $runTimeFormatted +} +WriteLog 'Script complete: ' + $runTimeFormatted diff --git a/README.md b/README.md index b2c697c..c1c05ac 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,76 @@ # 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 -2407.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 -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 + +[![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 From c049840baabe84c3bdb97bbd569598645e74bd2a Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:45:44 -0700 Subject: [PATCH 15/23] update readme.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c1c05ac..a069fe0 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,11 @@ The first 15 minutes of the following video includes a quick start demo to get s 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 From 13e2765c3f795ef70c1b1bf282cb45dca879ac55 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:46:42 -0700 Subject: [PATCH 16/23] update readme --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a069fe0..eb98ceb 100644 --- a/README.md +++ b/README.md @@ -38,14 +38,16 @@ 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 From 351c87ab9673132bcccc8c47e678c7132d53ea87 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:47:49 -0700 Subject: [PATCH 17/23] update readme --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index eb98ceb..c1c05ac 100644 --- a/README.md +++ b/README.md @@ -37,17 +37,11 @@ The first 15 minutes of the following video includes a quick start demo to get s 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 From eaa58e68042743f2d728dc4bedcc7411c7536f3c Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:49:26 -0700 Subject: [PATCH 18/23] update readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c1c05ac..4fb1438 100644 --- a/README.md +++ b/README.md @@ -30,17 +30,17 @@ The Full-Flash update (FFU) process can automatically download the latest releas ## YouTube Detailed Walkthrough -The first 15 minutes of the following video includes a quick start demo to get started. Below the video are a list of chapters +The first 15 minutes of the following video includes a quick start demo to get started. Below the video are a list of chapters [![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 +[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 From 94f74a194d24a7a2a028ba01cf333433338b64ba Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:50:32 -0700 Subject: [PATCH 19/23] update readme --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fb1438..590aae2 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,12 @@ The first 15 minutes of the following video includes a quick start demo to get s Chapters: -[00:00](https://www.youtube.com/watch?v=rqXRbgeeKSQ&t=0s) Begin +[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 From 31984e104e9d2aaa80e04a90c8f10b084cf58fd8 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:52:35 -0700 Subject: [PATCH 20/23] update readme.md --- README.md | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 590aae2..69b5df0 100644 --- a/README.md +++ b/README.md @@ -38,42 +38,76 @@ 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 +[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 +[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 -[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 From b20b614f5e18362fb6e14b618e5b589dbb5691a3 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:39:13 -0700 Subject: [PATCH 21/23] update changelog.md and ApplyFFU.ps1 to 2408.1 --- ChangeLog.md | 28 +++++++++++++++++++ .../WinPEDeployFFUFiles/ApplyFFU.ps1 | 25 +---------------- README.md | 2 +- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index f90c12d..3cc92fd 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,33 @@ # 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 + ## **2407.1** This is another major release that includes: diff --git a/FFUDevelopment/WinPEDeployFFUFiles/ApplyFFU.ps1 b/FFUDevelopment/WinPEDeployFFUFiles/ApplyFFU.ps1 index 0b38ee5..7240239 100644 --- a/FFUDevelopment/WinPEDeployFFUFiles/ApplyFFU.ps1 +++ b/FFUDevelopment/WinPEDeployFFUFiles/ApplyFFU.ps1 @@ -14,10 +14,6 @@ function Get-USBDrive(){ return $USBDriveLetter } -# function Get-HardDrive(){ -# $DeviceID = (Get-WmiObject -Class 'Win32_DiskDrive' | Where-Object {$_.MediaType -eq 'Fixed hard disk media' -and $_.Model -ne 'Microsoft Virtual Disk'}).DeviceID -# return $DeviceID -# } function Get-HardDrive(){ $SystemInfo = Get-WmiObject -Class 'Win32_ComputerSystem' $Manufacturer = $SystemInfo.Manufacturer @@ -127,27 +123,12 @@ 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 $LogFileName = 'ScriptLog.txt' $USBDrive = Get-USBDrive New-item -Path $USBDrive -Name $LogFileName -ItemType "file" -Force | Out-Null $LogFile = $USBDrive + $LogFilename -$version = '2407.1' +$version = '2408.1' WriteLog 'Begin Logging' WriteLog "Script version: $version" @@ -432,10 +413,6 @@ If (Test-Path -Path $Drivers) 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 Writelog 'Clean Disk' try { diff --git a/README.md b/README.md index 69b5df0..935b959 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ The Full-Flash update (FFU) process can automatically download the latest releas ## YouTube Detailed Walkthrough -The first 15 minutes of the following video includes a quick start demo to get started. Below the video are a list of chapters +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))") From cc383c84cb3b2e216d3c954cd8896a43a1d6c871 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:51:53 -0700 Subject: [PATCH 22/23] update docs --- ChangeLog.md | 1 + FFUDevelopment/BuildFFUVM.ps1 | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 3cc92fd..614c856 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -27,6 +27,7 @@ Fixes/misc - 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** diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 33870e2..da4434e 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -139,6 +139,30 @@ When set to $true, will remove the WinPE deployment ISO after the FFU has been c .PARAMETER CleanupAppsISO When set to $true, will remove the Apps ISO after the FFU has been captured. Default is $true. +.PARAMETER DriversFolder +Path to the drivers folder. Default is $FFUDevelopmentPath\Drivers. + +.PARAMETER CleanupDrivers +When set to $true, will remove the drivers folder after the FFU has been captured. Default is $true. + +.PARAMETER UserAgent +User agent string to use when downloading files. + +.PARAMETER Headers +Headers to use when downloading files. + +.PARAMETER AllowExternalHardDiskMedia +When set to $true, will allow the use of media identified as External Hard Disk media via WMI class Win32_DiskDrive. Default is not defined. + +.PARAMETER PromptExternalHardDiskMedia +When set to $true, will prompt the user to confirm the use of media identified as External Hard Disk media via WMI class Win32_DiskDrive. Default is $true. + +.PARAMETER Make +Make of the device to download drivers. Accepted values are: 'Microsoft', 'Dell', 'HP', 'Lenovo' + +.PARAMETER Model +Model of the device to download drivers. This is required if Make is set. + .EXAMPLE Command line for most people who want to download the latest Windows 11 Pro x64 media in English (US) with the latest Windows Cumulative Update, .NET Framework, Defender platform and definition updates, Edge, OneDrive, and Office/M365 Apps. It will also copy drivers to the FFU. This can take about 40 minutes to create the FFU due to the time it takes to download and install the updates. .\BuildFFUVM.ps1 -WindowsSKU 'Pro' -Installapps $true -InstallOffice $true -InstallDrivers $true -VMSwitchName 'Name of your VM Switch in Hyper-V' -VMHostIPAddress 'Your IP Address' -CreateCaptureMedia $true -CreateDeploymentMedia $true -BuildUSBDrive $true -UpdateLatestCU $true -UpdateLatestNet $true -UpdateLatestDefender $true -UpdateEdge $true -UpdateOneDrive $true -verbose From 94dd2568896657f9b5fa0fef6ab3679d42b81d2e Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:55:17 -0700 Subject: [PATCH 23/23] update docs --- FFUDevelopment/Docs/BuildDeployFFU.docx | Bin 2719286 -> 2718976 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/FFUDevelopment/Docs/BuildDeployFFU.docx b/FFUDevelopment/Docs/BuildDeployFFU.docx index 654003ec50eef62759d6759229cb265321857785..19d200efebde977a704c55928af4f301c39da4fa 100644 GIT binary patch delta 45616 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 DS9wUx