From 131d7920bf1085338a3b1961e5c3ccd3ec54d5e5 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT Date: Tue, 12 Sep 2023 13:12:48 -0700 Subject: [PATCH 1/3] Changed USB build functionality --- FFUDevelopment/BuildFFUVM.ps1 | 260 +++++++++++++----- .../WinPECaptureFFUFiles/CaptureFFU.ps1 | 4 +- .../WinPEDeployFFUFiles/ApplyFFU.ps1 | 2 +- 3 files changed, 189 insertions(+), 77 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 7ff3403..cacaac4 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -202,7 +202,7 @@ param( [ValidateSet(512, 4096)] [uint32]$LogicalSectorSizeBytes = 512 ) -$version = '2309.1' +$version = '2309.2' #Check if Hyper-V feature is installed (requires only checks the module) $osInfo = Get-WmiObject -Class Win32_OperatingSystem @@ -1149,8 +1149,8 @@ Function Get-WindowsVersionInfo { WriteLog "Unloading registry" Invoke-Process reg "unload HKLM\FFU" #This prevents Critical Process Died errors you can have during deployment of the FFU. Capturing from very fast disks (NVME) can cause the capture to happen faster than Windows is ready for. - WriteLog 'Sleep 15 seconds to allow registry to completely unload' - Start-sleep 15 + WriteLog 'Sleep 60 seconds to allow registry to completely unload' + Start-sleep 60 @@ -1162,96 +1162,208 @@ Function Get-WindowsVersionInfo { SKU = $SKU } } +# Function New-DeploymentUSB { +# param( +# [switch]$CopyFFU +# ) +# WriteLog "CopyFFU is set to $CopyFFU" +# # Set your FFUDevelopmentPath here +# $BuildUSBPath = $FFUDevelopmentPath + +# # Get the first removable USB drive +# $USBDrive = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") + +# if ($null -eq $USBDrive) { +# Writelog "No USB drive found" +# exit 1 +# } + +# # Format the USB drive +# $DiskNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "") +# $ScriptBlock = { +# param($DiskNumber) +# Clear-Disk -Number $DiskNumber -RemoveData -Confirm:$false +# Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false +# #Check for other partitions since, apparently, Clear-Disk doesn't remove all of them +# Get-Disk $disknumber | Get-Partition | Remove-Partition -Confirm:$false +# $Disk = Get-Disk -Number $DiskNumber +# $Disk | Set-Disk -PartitionStyle MBR +# $BootPartition = $Disk | New-Partition -Size 2GB -IsActive -AssignDriveLetter +# $DeployPartition = $Disk | New-Partition -UseMaximumSize -AssignDriveLetter +# Format-Volume -Partition $BootPartition -FileSystem FAT32 -NewFileSystemLabel "Boot" -Confirm:$false +# Format-Volume -Partition $DeployPartition -FileSystem NTFS -NewFileSystemLabel "Deploy" -Confirm:$false +# } +# WriteLog 'Partitioning USB Drive' +# Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $DiskNumber | Out-null +# WriteLog 'Done' + +# # Mount the ISO and copy the contents to the boot partition +# $BootPartitionDriveLetter = (get-volume -FileSystemLabel Boot).DriveLetter + ":\" +# $ISOMountPoint = (Mount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" -PassThru | Get-Volume).DriveLetter + ":\" +# WriteLog "Copying WinPE files to $BootPartitionDriveLetter" +# Copy-Item -Path "$ISOMountPoint\*" -Destination $BootPartitionDriveLetter -Recurse -Force | Out-Null +# Dismount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" | Out-Null + +# # Copy FFU files if switch is provided +# if ($CopyFFU.IsPresent) { +# WriteLog 'Copying FFU files' +# $DeployPartitionDriveLetter = (get-volume -FileSystemLabel Deploy).DriveLetter + ":\" +# $FFUFiles = Get-ChildItem -Path "$BuildUSBPath\FFU" -Filter "*.ffu" + +# if ($FFUFiles.Count -eq 1) { +# WriteLog "Copying $($FFUFiles.FullName) to $DeployPartitionDriveLetter this could take a few minutes" +# Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force | Out-Null +# Writelog 'Copy complete' +# } +# elseif ($FFUFiles.Count -gt 1) { +# WriteLog "Multiple FFU files found:" +# Write-Host "Multiple FFU files found:" +# for ($i = 0; $i -lt $FFUFiles.Count; $i++) { +# WriteLog ("{0}: {1}" -f ($i + 1), $FFUFiles[$i].Name) +# Write-Host ("{0}: {1}" -f ($i + 1), $FFUFiles[$i].Name) +# } +# WriteLog "A: Copy all FFU files" +# Write-Host "A: Copy all FFU files" +# $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') { +# WriteLog "Copying All FFU files to $DeployPartitionDriveLetter this could take a few minutes" +# Write-Host "Copying All FFU files to $DeployPartitionDriveLetter this could take a few minutes" +# Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force | Out-Null +# Writelog 'Copy complete' +# Write-Host 'Copy complete' +# } +# elseif ($inputChoice -ge 1 -and $inputChoice -le $FFUFiles.Count) { +# $selectedIndex = $inputChoice - 1 +# WriteLog "Copying $($FFUFiles[$selectedIndex].FullName) to $DeployPartitionDriveLetter this could take a few minutes" +# Write-Host "Copying $($FFUFiles[$selectedIndex].FullName) to $DeployPartitionDriveLetter this could take a few minutes" +# Copy-Item -Path $FFUFiles[$selectedIndex].FullName -Destination $DeployPartitionDriveLetter -Force | Out-Null +# Writelog 'Copy complete' +# Write-Host 'Copy complete' +# } +# else { +# WriteLog "Invalid choice. No FFU file copied" +# Write-Host 'Invalid choice. No FFU file copied' +# } +# } +# else { +# WriteLog "No FFU files found in the current directory." +# } +# } + +# WriteLog "USB drive prepared successfully." +# } + Function New-DeploymentUSB { param( [switch]$CopyFFU ) WriteLog "CopyFFU is set to $CopyFFU" # Set your FFUDevelopmentPath here - $BuildUSBPath = $FFUDevelopmentPath + $BuildUSBPath = $PSScriptRoot + WriteLog "BuildUSBPath is $BuildUSBPath" + $counter = 0 - # Get the first removable USB drive - $USBDrive = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") + # Get removable drives + $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 $USBDrive) { - Writelog "No USB drive found" + if ($null -eq $USBDrives) { + WriteLog "No removable USB drive found." exit 1 } - # Format the USB drive - $DiskNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "") - $ScriptBlock = { - param($DiskNumber) - Clear-Disk -Number $DiskNumber -RemoveData -Confirm:$false - Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false - #Check for other partitions since, apparently, Clear-Disk doesn't remove all of them - Get-Disk $disknumber | Get-Partition | Remove-Partition -Confirm:$false - $Disk = Get-Disk -Number $DiskNumber - $Disk | Set-Disk -PartitionStyle MBR - $BootPartition = $Disk | New-Partition -Size 2GB -IsActive -AssignDriveLetter - $DeployPartition = $Disk | New-Partition -UseMaximumSize -AssignDriveLetter - Format-Volume -Partition $BootPartition -FileSystem FAT32 -NewFileSystemLabel "Boot" -Confirm:$false - Format-Volume -Partition $DeployPartition -FileSystem NTFS -NewFileSystemLabel "Deploy" -Confirm:$false - } - WriteLog 'Partitioning USB Drive' - Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $DiskNumber | Out-null - WriteLog 'Done' - - # Mount the ISO and copy the contents to the boot partition - $BootPartitionDriveLetter = (get-volume -FileSystemLabel Boot).DriveLetter + ":\" - $ISOMountPoint = (Mount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" -PassThru | Get-Volume).DriveLetter + ":\" - WriteLog "Copying WinPE files to $BootPartitionDriveLetter" - Copy-Item -Path "$ISOMountPoint\*" -Destination $BootPartitionDriveLetter -Recurse -Force | Out-Null - Dismount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" | Out-Null - - # Copy FFU files if switch is provided - if ($CopyFFU.IsPresent) { - WriteLog 'Copying FFU files' - $DeployPartitionDriveLetter = (get-volume -FileSystemLabel Deploy).DriveLetter + ":\" - $FFUFiles = Get-ChildItem -Path "$BuildUSBPath\FFU" -Filter "*.ffu" - - if ($FFUFiles.Count -eq 1) { - WriteLog "Copying $($FFUFiles.FullName) to $DeployPartitionDriveLetter this could take a few minutes" - Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force | Out-Null - Writelog 'Copy complete' + foreach ($USBDrive in $USBDrives) { + $Counter++ + WriteLog "Fromatting drive $Counter out of $USBDrivesCount" + # Format the USB drive + $DiskNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "") + WriteLog "Disk number is $DiskNumber" + #Delete these two lines + # Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false + # Get-Disk -number $disknumber | select * + $ScriptBlock = { + param($DiskNumber) + Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false + #Check for other partitions since, apparently, Clear-Disk doesn't remove all of them + Get-Disk $disknumber | Get-Partition | Remove-Partition + $Disk = Get-Disk -Number $disknumber + $Disk | Set-Disk -PartitionStyle MBR + #Initialize-Disk -Number $DiskNumber -PartitionStyle MBR + $BootPartition = $Disk | New-Partition -Size 2GB -IsActive -AssignDriveLetter + $DeployPartition = $Disk | New-Partition -UseMaximumSize -AssignDriveLetter + Format-Volume -Partition $BootPartition -FileSystem FAT32 -NewFileSystemLabel "TempBoot" -Confirm:$false + Format-Volume -Partition $DeployPartition -FileSystem NTFS -NewFileSystemLabel "TempDeploy" -Confirm:$false } - elseif ($FFUFiles.Count -gt 1) { - WriteLog "Multiple FFU files found:" - Write-Host "Multiple FFU files found:" - for ($i = 0; $i -lt $FFUFiles.Count; $i++) { - WriteLog ("{0}: {1}" -f ($i + 1), $FFUFiles[$i].Name) - Write-Host ("{0}: {1}" -f ($i + 1), $FFUFiles[$i].Name) + WriteLog 'Partitioning USB Drive' + Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $DiskNumber | Out-null + WriteLog 'Done' + + # Mount the ISO and copy the contents to the boot partition + $BootPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempBoot' AND DriveType=2 AND DriveLetter IS NOT NULL").Name + $ISOMountPoint = (Mount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" -PassThru | Get-Volume).DriveLetter + ":\" + WriteLog "Copying WinPE files to $BootPartitionDriveLetter" + # Copy-Item -Path "$ISOMountPoint\*" -Destination $BootPartitionDriveLetter -Recurse -Force | Out-Null + robocopy "$ISOMountPoint" "$BootPartitionDriveLetter" /E /COPYALL /R:5 /W:5 /J + Dismount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" | Out-Null + + # Copy FFU files if switch is provided + if ($CopyFFU.IsPresent) { + WriteLog 'Copying FFU files' + #$DeployPartitionDriveLetter = (get-volume -FileSystemLabel Deploy).DriveLetter + ":\" + $DeployPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempDeploy' AND DriveType=2 AND DriveLetter IS NOT NULL").Name + $FFUFiles = Get-ChildItem -Path "$BuildUSBPath\FFU" -Filter "*.ffu" + + if ($FFUFiles.Count -eq 1) { + WriteLog ("Copying " + $FFUFiles.FullName + " to $DeployPartitionDriveLetter this could take a few minutes") + # Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force + robocopy $(Split-Path $FFUFiles.FullName -Parent) $DeployPartitionDriveLetter $(Split-Path $FFUFiles.FullName -Leaf) /COPYALL /R:5 /W:5 /J + } - WriteLog "A: Copy all FFU files" - Write-Host "A: Copy all FFU files" - $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') { - WriteLog "Copying All FFU files to $DeployPartitionDriveLetter this could take a few minutes" - Write-Host "Copying All FFU files to $DeployPartitionDriveLetter this could take a few minutes" - Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force | Out-Null - Writelog 'Copy complete' - Write-Host 'Copy complete' - } - elseif ($inputChoice -ge 1 -and $inputChoice -le $FFUFiles.Count) { - $selectedIndex = $inputChoice - 1 - WriteLog "Copying $($FFUFiles[$selectedIndex].FullName) to $DeployPartitionDriveLetter this could take a few minutes" - Write-Host "Copying $($FFUFiles[$selectedIndex].FullName) to $DeployPartitionDriveLetter this could take a few minutes" - Copy-Item -Path $FFUFiles[$selectedIndex].FullName -Destination $DeployPartitionDriveLetter -Force | Out-Null - Writelog 'Copy complete' - Write-Host 'Copy complete' + elseif ($FFUFiles.Count -gt 1) { + WriteLog "Multiple FFU files found:" + for ($i = 0; $i -lt $FFUFiles.Count; $i++) { + WriteLog ("{0}: {1}" -f ($i + 1), $FFUFiles[$i].Name) + } + WriteLog "A: Copy all FFU files" + $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') { + WriteLog "Copying All FFU files to $DeployPartitionDriveLetter this could take a few minutes" + # Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force + robocopy $(Split-Path $FFUFiles.FullName -Parent) $DeployPartitionDriveLetter $(Split-Path $FFUFiles.FullName -Leaf) /COPYALL /R:5 /W:5 /J + } + elseif ($inputChoice -ge 1 -and $inputChoice -le $FFUFiles.Count) { + $selectedIndex = $inputChoice - 1 + WriteLog ("Copying " + $FFUFiles[$selectedIndex].FullName + " to $DeployPartitionDriveLetter this could take a few minutes") + # Copy-Item -Path $FFUFiles[$selectedIndex].FullName -Destination $DeployPartitionDriveLetter -Force + robocopy $(Split-Path $FFUFiles[$selectedIndex].FullName -Parent) $DeployPartitionDriveLetter $(Split-Path $FFUFiles[$selectedIndex].FullName -Leaf) /COPYALL /R:5 /W:5 /J + } + else { + WriteLog "Invalid choice. No FFU file copied." + } } else { - WriteLog "Invalid choice. No FFU file copied" - Write-Host 'Invalid choice. No FFU file copied' + WriteLog "No FFU files found in the current directory." } } - else { - WriteLog "No FFU files found in the current directory." + Set-Volume -FileSystemLabel "TempBoot" -NewFileSystemLabel "Boot" + Set-Volume -FileSystemLabel "TempDeploy" -NewFileSystemLabel "Deploy" + #Remove drive letter (so we don't run out of drive letters) + If ($USBDrivesCount -gt 1) { + & mountvol $BootPartitionDriveLetter /D + & mountvol $DeployPartitionDriveLetter /D } + WriteLog "Drive $counter completed" } - - WriteLog "USB drive prepared successfully." + + WriteLog "USB Drives completed" } ###END FUNCTIONS diff --git a/FFUDevelopment/WinPECaptureFFUFiles/CaptureFFU.ps1 b/FFUDevelopment/WinPECaptureFFUFiles/CaptureFFU.ps1 index 13b95e4..a6ff14c 100644 --- a/FFUDevelopment/WinPECaptureFFUFiles/CaptureFFU.ps1 +++ b/FFUDevelopment/WinPECaptureFFUFiles/CaptureFFU.ps1 @@ -60,8 +60,8 @@ Remove-Variable DisplayVersion Remove-Variable Office reg unload "HKLM\FFU" #This prevents Critical Process Died errors you can have during deployment of the FFU - may not happen during capture from WinPE, but adding here to be consistent with VHDX capture -WriteLog 'Sleep 15 seconds to allow registry to completely unload' -Start-sleep 15 +WriteLog 'Sleep 60 seconds to allow registry to completely unload' +Start-sleep 60 Start-Process -FilePath dism.exe -ArgumentList $dismArgs -Wait -PassThru -ErrorAction Stop | Out-Null #Copy DISM log to Host diff --git a/FFUDevelopment/WinPEDeployFFUFiles/ApplyFFU.ps1 b/FFUDevelopment/WinPEDeployFFUFiles/ApplyFFU.ps1 index e73b1e0..7284a4a 100644 --- a/FFUDevelopment/WinPEDeployFFUFiles/ApplyFFU.ps1 +++ b/FFUDevelopment/WinPEDeployFFUFiles/ApplyFFU.ps1 @@ -117,7 +117,7 @@ $LogFileName = 'ScriptLog.txt' $USBDrive = Get-USBDrive New-item -Path $USBDrive -Name $LogFileName -ItemType "file" -Force | Out-Null $LogFile = $USBDrive + $LogFilename -$version = '2309.1' +$version = '2309.2' WriteLog 'Begin Logging' WriteLog "Script version: $version" From 6dee088139566caa55a82aab869aca27b8098300 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT Date: Tue, 12 Sep 2023 16:12:08 -0700 Subject: [PATCH 2/3] Fixed logging --- FFUDevelopment/BuildFFUVM.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index cacaac4..0507699 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -1281,10 +1281,10 @@ Function New-DeploymentUSB { foreach ($USBDrive in $USBDrives) { $Counter++ - WriteLog "Fromatting drive $Counter out of $USBDrivesCount" + WriteLog "Fromatting USB drive $Counter out of $USBDrivesCount" # Format the USB drive $DiskNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "") - WriteLog "Disk number is $DiskNumber" + WriteLog "Physical Disk number is $DiskNumber for USB drive $Counter out of $USBDrivesCount" #Delete these two lines # Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false # Get-Disk -number $disknumber | select * From 161e77720bd42380d0efdbf548f02126c644f5b2 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT Date: Thu, 14 Sep 2023 15:34:12 -0700 Subject: [PATCH 3/3] 2309.2 final commit --- FFUDevelopment/BuildFFUVM.ps1 | 277 +++++++++--------- .../WinPECaptureFFUFiles/CaptureFFU.ps1 | 2 - 2 files changed, 135 insertions(+), 144 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 0507699..926b5e0 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -1162,109 +1162,15 @@ Function Get-WindowsVersionInfo { SKU = $SKU } } -# Function New-DeploymentUSB { -# param( -# [switch]$CopyFFU -# ) -# WriteLog "CopyFFU is set to $CopyFFU" -# # Set your FFUDevelopmentPath here -# $BuildUSBPath = $FFUDevelopmentPath - -# # Get the first removable USB drive -# $USBDrive = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") - -# if ($null -eq $USBDrive) { -# Writelog "No USB drive found" -# exit 1 -# } - -# # Format the USB drive -# $DiskNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "") -# $ScriptBlock = { -# param($DiskNumber) -# Clear-Disk -Number $DiskNumber -RemoveData -Confirm:$false -# Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false -# #Check for other partitions since, apparently, Clear-Disk doesn't remove all of them -# Get-Disk $disknumber | Get-Partition | Remove-Partition -Confirm:$false -# $Disk = Get-Disk -Number $DiskNumber -# $Disk | Set-Disk -PartitionStyle MBR -# $BootPartition = $Disk | New-Partition -Size 2GB -IsActive -AssignDriveLetter -# $DeployPartition = $Disk | New-Partition -UseMaximumSize -AssignDriveLetter -# Format-Volume -Partition $BootPartition -FileSystem FAT32 -NewFileSystemLabel "Boot" -Confirm:$false -# Format-Volume -Partition $DeployPartition -FileSystem NTFS -NewFileSystemLabel "Deploy" -Confirm:$false -# } -# WriteLog 'Partitioning USB Drive' -# Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $DiskNumber | Out-null -# WriteLog 'Done' - -# # Mount the ISO and copy the contents to the boot partition -# $BootPartitionDriveLetter = (get-volume -FileSystemLabel Boot).DriveLetter + ":\" -# $ISOMountPoint = (Mount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" -PassThru | Get-Volume).DriveLetter + ":\" -# WriteLog "Copying WinPE files to $BootPartitionDriveLetter" -# Copy-Item -Path "$ISOMountPoint\*" -Destination $BootPartitionDriveLetter -Recurse -Force | Out-Null -# Dismount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" | Out-Null - -# # Copy FFU files if switch is provided -# if ($CopyFFU.IsPresent) { -# WriteLog 'Copying FFU files' -# $DeployPartitionDriveLetter = (get-volume -FileSystemLabel Deploy).DriveLetter + ":\" -# $FFUFiles = Get-ChildItem -Path "$BuildUSBPath\FFU" -Filter "*.ffu" - -# if ($FFUFiles.Count -eq 1) { -# WriteLog "Copying $($FFUFiles.FullName) to $DeployPartitionDriveLetter this could take a few minutes" -# Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force | Out-Null -# Writelog 'Copy complete' -# } -# elseif ($FFUFiles.Count -gt 1) { -# WriteLog "Multiple FFU files found:" -# Write-Host "Multiple FFU files found:" -# for ($i = 0; $i -lt $FFUFiles.Count; $i++) { -# WriteLog ("{0}: {1}" -f ($i + 1), $FFUFiles[$i].Name) -# Write-Host ("{0}: {1}" -f ($i + 1), $FFUFiles[$i].Name) -# } -# WriteLog "A: Copy all FFU files" -# Write-Host "A: Copy all FFU files" -# $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') { -# WriteLog "Copying All FFU files to $DeployPartitionDriveLetter this could take a few minutes" -# Write-Host "Copying All FFU files to $DeployPartitionDriveLetter this could take a few minutes" -# Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force | Out-Null -# Writelog 'Copy complete' -# Write-Host 'Copy complete' -# } -# elseif ($inputChoice -ge 1 -and $inputChoice -le $FFUFiles.Count) { -# $selectedIndex = $inputChoice - 1 -# WriteLog "Copying $($FFUFiles[$selectedIndex].FullName) to $DeployPartitionDriveLetter this could take a few minutes" -# Write-Host "Copying $($FFUFiles[$selectedIndex].FullName) to $DeployPartitionDriveLetter this could take a few minutes" -# Copy-Item -Path $FFUFiles[$selectedIndex].FullName -Destination $DeployPartitionDriveLetter -Force | Out-Null -# Writelog 'Copy complete' -# Write-Host 'Copy complete' -# } -# else { -# WriteLog "Invalid choice. No FFU file copied" -# Write-Host 'Invalid choice. No FFU file copied' -# } -# } -# else { -# WriteLog "No FFU files found in the current directory." -# } -# } - -# WriteLog "USB drive prepared successfully." -# } - Function New-DeploymentUSB { param( [switch]$CopyFFU ) WriteLog "CopyFFU is set to $CopyFFU" - # Set your FFUDevelopmentPath here $BuildUSBPath = $PSScriptRoot WriteLog "BuildUSBPath is $BuildUSBPath" $counter = 0 - # Get removable drives $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") If ($USBDrives -and ($null -eq $USBDrives.count)) { $USBDrivesCount = 1 @@ -1279,93 +1185,170 @@ Function New-DeploymentUSB { exit 1 } + $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." + } + } + foreach ($USBDrive in $USBDrives) { $Counter++ - WriteLog "Fromatting USB drive $Counter out of $USBDrivesCount" - # Format the USB drive + WriteLog "Formatting USB drive $Counter out of $USBDrivesCount" $DiskNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "") WriteLog "Physical Disk number is $DiskNumber for USB drive $Counter out of $USBDrivesCount" - #Delete these two lines - # Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false - # Get-Disk -number $disknumber | select * + $ScriptBlock = { param($DiskNumber) Clear-Disk -Number $DiskNumber -RemoveData -RemoveOEM -Confirm:$false - #Check for other partitions since, apparently, Clear-Disk doesn't remove all of them - Get-Disk $disknumber | Get-Partition | Remove-Partition - $Disk = Get-Disk -Number $disknumber + Get-Disk $DiskNumber | Get-Partition | Remove-Partition + $Disk = Get-Disk -Number $DiskNumber $Disk | Set-Disk -PartitionStyle MBR - #Initialize-Disk -Number $DiskNumber -PartitionStyle MBR $BootPartition = $Disk | New-Partition -Size 2GB -IsActive -AssignDriveLetter $DeployPartition = $Disk | New-Partition -UseMaximumSize -AssignDriveLetter Format-Volume -Partition $BootPartition -FileSystem FAT32 -NewFileSystemLabel "TempBoot" -Confirm:$false Format-Volume -Partition $DeployPartition -FileSystem NTFS -NewFileSystemLabel "TempDeploy" -Confirm:$false } + WriteLog 'Partitioning USB Drive' Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $DiskNumber | Out-null WriteLog 'Done' - - # Mount the ISO and copy the contents to the boot partition + $BootPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempBoot' AND DriveType=2 AND DriveLetter IS NOT NULL").Name $ISOMountPoint = (Mount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" -PassThru | Get-Volume).DriveLetter + ":\" WriteLog "Copying WinPE files to $BootPartitionDriveLetter" - # Copy-Item -Path "$ISOMountPoint\*" -Destination $BootPartitionDriveLetter -Recurse -Force | Out-Null robocopy "$ISOMountPoint" "$BootPartitionDriveLetter" /E /COPYALL /R:5 /W:5 /J Dismount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" | Out-Null - - # Copy FFU files if switch is provided + if ($CopyFFU.IsPresent) { - WriteLog 'Copying FFU files' - #$DeployPartitionDriveLetter = (get-volume -FileSystemLabel Deploy).DriveLetter + ":\" - $DeployPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempDeploy' AND DriveType=2 AND DriveLetter IS NOT NULL").Name - $FFUFiles = Get-ChildItem -Path "$BuildUSBPath\FFU" -Filter "*.ffu" - - if ($FFUFiles.Count -eq 1) { - WriteLog ("Copying " + $FFUFiles.FullName + " to $DeployPartitionDriveLetter this could take a few minutes") - # Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force - robocopy $(Split-Path $FFUFiles.FullName -Parent) $DeployPartitionDriveLetter $(Split-Path $FFUFiles.FullName -Leaf) /COPYALL /R:5 /W:5 /J - - } - elseif ($FFUFiles.Count -gt 1) { - WriteLog "Multiple FFU files found:" - for ($i = 0; $i -lt $FFUFiles.Count; $i++) { - WriteLog ("{0}: {1}" -f ($i + 1), $FFUFiles[$i].Name) - } - WriteLog "A: Copy all FFU files" - $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') { - WriteLog "Copying All FFU files to $DeployPartitionDriveLetter this could take a few minutes" - # Copy-Item -Path $FFUFiles.FullName -Destination $DeployPartitionDriveLetter -Force - robocopy $(Split-Path $FFUFiles.FullName -Parent) $DeployPartitionDriveLetter $(Split-Path $FFUFiles.FullName -Leaf) /COPYALL /R:5 /W:5 /J - } - elseif ($inputChoice -ge 1 -and $inputChoice -le $FFUFiles.Count) { - $selectedIndex = $inputChoice - 1 - WriteLog ("Copying " + $FFUFiles[$selectedIndex].FullName + " to $DeployPartitionDriveLetter this could take a few minutes") - # Copy-Item -Path $FFUFiles[$selectedIndex].FullName -Destination $DeployPartitionDriveLetter -Force - robocopy $(Split-Path $FFUFiles[$selectedIndex].FullName -Parent) $DeployPartitionDriveLetter $(Split-Path $FFUFiles[$selectedIndex].FullName -Leaf) /COPYALL /R:5 /W:5 /J + if ($null -ne $SelectedFFUFile) { + $DeployPartitionDriveLetter = (Get-WmiObject -Class win32_volume -Filter "Label='TempDeploy' AND DriveType=2 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) { + robocopy $(Split-Path $FFUFile -Parent) $DeployPartitionDriveLetter $(Split-Path $FFUFile -Leaf) /COPYALL /R:5 /W:5 /J + } } else { - WriteLog "Invalid choice. No FFU file copied." + WriteLog ("Copying " + $SelectedFFUFile + " to $DeployPartitionDriveLetter. This could take a few minutes.") + robocopy $(Split-Path $SelectedFFUFile -Parent) $DeployPartitionDriveLetter $(Split-Path $SelectedFFUFile -Leaf) /COPYALL /R:5 /W:5 /J } } else { - WriteLog "No FFU files found in the current directory." + WriteLog "No FFU file selected. Skipping copy." } } + Set-Volume -FileSystemLabel "TempBoot" -NewFileSystemLabel "Boot" Set-Volume -FileSystemLabel "TempDeploy" -NewFileSystemLabel "Deploy" - #Remove drive letter (so we don't run out of drive letters) - If ($USBDrivesCount -gt 1) { + + if ($USBDrivesCount -gt 1) { & mountvol $BootPartitionDriveLetter /D & mountvol $DeployPartitionDriveLetter /D } + WriteLog "Drive $counter completed" } - + WriteLog "USB Drives completed" } + +function Get-FFUEnvironment { + WriteLog 'Dirty.txt file detected. Last run did not complete succesfully. Will clean environment' + # Check for MSFT Virtual disks where location contains FFUDevelopment in the path + $disks = Get-Disk -FriendlyName *virtual* + foreach ($disk in $disks) { + $diskNumber = $disk.Number + $vhdLocation = $disk.Location + if ($vhdLocation -like "*FFUDevelopment*") { + WriteLog "Dismounting Virtual Disk $diskNumber with Location $vhdLocation" + Dismount-ScratchVhdx -VhdxPath $vhdLocation + $parentFolder = Split-Path -Parent $vhdLocation + WriteLog "Removing folder $parentFolder" + Remove-Item -Path $parentFolder -Recurse -Force + } + } + + # Check for mounted DiskImages + $volumes = Get-Volume | Where-Object { $_.DriveType -eq 'CD-ROM' } + foreach ($volume in $volumes) { + $letter = $volume.DriveLetter + WriteLog "Dismounting DiskImage for volume $letter" + Get-Volume $letter | Get-DiskImage | Dismount-DiskImage | Out-Null + WriteLog "Dismounting complete" + } + + # Remove unused mountpoints + WriteLog 'Remove unused mountpoints' + Invoke-Process cmd "/c mountvol /r" + WriteLog 'Removal complete' + + # Check for content in the VM folder and delete any folders that start with _FFU- + $folders = Get-ChildItem -Path $VMLocation -Directory + foreach ($folder in $folders) { + if ($folder.Name -like '_FFU-*') { + WriteLog "Removing folder $($folder.FullName)" + Remove-Item -Path $folder.FullName -Recurse -Force + } + } + + # Remove orphaned mounted images + $mountedImages = Get-WindowsImage -Mounted + if ($mountedImages) { + foreach ($image in $mountedImages) { + $mountPath = $image.Path + WriteLog "Dismounting image at $mountPath" + Dismount-WindowsImage -Path $mountPath -discard | Out-null + WriteLog "Successfully dismounted image at $mountPath" + } + } + + # Remove Mount folder if it exists + if (Test-Path -Path "$FFUDevelopmentPath\Mount") { + WriteLog "Remove $FFUDevelopmentPath\Mount folder" + Remove-Item -Path "$FFUDevelopmentPath\Mount" -Recurse -Force + WriteLog 'Folder removed' + } + + #Clear any corrupt Windows mount points + WriteLog 'Clearing any corrupt Windows mount points' + Clear-WindowsCorruptMountPoint | Out-null + WriteLog 'Complete' + + #Clean up registry + if (Test-Path -Path 'HKLM:\FFU'){ + Writelog 'Found HKLM:\FFU, removing it' + Invoke-Process reg "unload HKLM\FFU" + } + + Writelog 'Removing dirty.txt file' + Remove-Item -Path "$FFUDevelopmentPath\dirty.txt" -Force + WriteLog "Cleanup complete" +} + ###END FUNCTIONS #Remove old log file if found @@ -1414,6 +1397,11 @@ catch { throw $_ } +#Check if environment is dirty +If(Test-Path -Path "$FFUDevelopmentPath\dirty.txt"){ + Get-FFUEnvironment +} + #Create apps ISO for Office and/or 3rd party apps if ($InstallApps) { try { @@ -1453,6 +1441,9 @@ if ($InstallApps) { #Create VHDX try { + #Create dirty.txt file to track if environment is dirty or clean + New-Item -Path .\ -Name "dirty.txt" -ItemType "file" | Out-Null + if ($ISOPath) { $wimPath = Get-WimFromISO } @@ -1661,5 +1652,7 @@ If ($BuildUSBDrive) { throw $_ } } +#Clean up dirty.txt file +Remove-Item -Path .\dirty.txt -Force | out-null Write-Host "Script complete" WriteLog "Script complete" \ No newline at end of file diff --git a/FFUDevelopment/WinPECaptureFFUFiles/CaptureFFU.ps1 b/FFUDevelopment/WinPECaptureFFUFiles/CaptureFFU.ps1 index a6ff14c..c0021c9 100644 --- a/FFUDevelopment/WinPECaptureFFUFiles/CaptureFFU.ps1 +++ b/FFUDevelopment/WinPECaptureFFUFiles/CaptureFFU.ps1 @@ -60,9 +60,7 @@ Remove-Variable DisplayVersion Remove-Variable Office reg unload "HKLM\FFU" #This prevents Critical Process Died errors you can have during deployment of the FFU - may not happen during capture from WinPE, but adding here to be consistent with VHDX capture -WriteLog 'Sleep 60 seconds to allow registry to completely unload' Start-sleep 60 - Start-Process -FilePath dism.exe -ArgumentList $dismArgs -Wait -PassThru -ErrorAction Stop | Out-Null #Copy DISM log to Host xcopy X:\Windows\logs\dism\dism.log W:\ /Y | Out-Null