Merge pull request #12 from rbalsleyMSFT/9-24021-feature-list

2402.1 PR
This commit is contained in:
rbalsleyMSFT
2024-03-11 16:22:39 -07:00
committed by GitHub
8 changed files with 602 additions and 46 deletions
+10 -1
View File
@@ -1,6 +1,11 @@
REM Put each app install on a separate line REM Put each app install on a separate line
REM M365 Apps/Office ProPlus REM M365 Apps/Office ProPlus
d:\Office\setup.exe /configure d:\Office\DeployFFU.xml REM d:\Office\setup.exe /configure d:\office\DeployFFU.xml
REM Install Defender Platform Update
REM Install Defender Definitions
REM Install Windows Security Platform Update
REM Install OneDrive Per Machine
REM Install Edge Stable
REM Add additional apps below here REM Add additional apps below here
REM Contoso App (Example) REM Contoso App (Example)
REM msiexec /i d:\Contoso\setup.msi /qn /norestart REM msiexec /i d:\Contoso\setup.msi /qn /norestart
@@ -10,4 +15,8 @@ del c:\windows\panther\unattend\unattend.xml /F /Q
del c:\windows\panther\unattend.xml /F /Q del c:\windows\panther\unattend.xml /F /Q
taskkill /IM sysprep.exe taskkill /IM sysprep.exe
timeout /t 10 timeout /t 10
REM Run Component Cleanup since dism /online /cleanup-image /analyzecomponentcleanup recommends it
REM If adding latest CU, definitely need to do this to keep FFU size smaller
dism /online /cleanup-image /startcomponentcleanup /resetbase
REM Sysprep/Generalize
c:\windows\system32\sysprep\sysprep.exe /quiet /generalize /oobe c:\windows\system32\sysprep\sysprep.exe /quiet /generalize /oobe
View File
+560 -40
View File
@@ -1,3 +1,4 @@
#Requires -Modules Hyper-V, Storage #Requires -Modules Hyper-V, Storage
#Requires -PSEdition Desktop #Requires -PSEdition Desktop
#Requires -RunAsAdministrator #Requires -RunAsAdministrator
@@ -75,6 +76,9 @@ When set to $true, will partition and format a USB drive and copy the captured F
.PARAMETER WindowsRelease .PARAMETER WindowsRelease
Integer value of 10 or 11. This is used to identify which release of Windows to download. Default is 11. Integer value of 10 or 11. This is used to identify which release of Windows to download. Default is 11.
.PARAMETER WindowsVersion
String value of the Windows version to download. This is used to identify which version of Windows to download. Default is 23h2.
.PARAMETER WindowsArch .PARAMETER WindowsArch
String value of x86 or x64. This is used to identify which architecture of Windows to download. Default is x64. String value of x86 or x64. This is used to identify which architecture of Windows to download. Default is x64.
@@ -87,7 +91,58 @@ String value of either business or consumer. This is used to identify which medi
.PARAMETER LogicalSectorBytes .PARAMETER LogicalSectorBytes
unit32 value of 512 or 4096. Not recommended to change from 512. Might be useful for 4kn drives, but needs more testing. Default is 512. unit32 value of 512 or 4096. Not recommended to change from 512. Might be useful for 4kn drives, but needs more testing. Default is 512.
.PARAMETER Optimize
When set to $true, will optimize the FFU file. Default is $true.
.PARAMETER CopyDrivers
When set to $true, will copy the drivers from the $FFUDevelopmentPath\Drivers folder to the Drivers folder on the deploy partition of the USB drive. Default is $false.
.PARAMETER CopyPEDrivers
When set to $true, will copy the drivers from the $FFUDevelopmentPath\PEDrivers folder to the WinPE deployment media. Default is $false.
.PARAMETER RemoveFFU
When set to $true, will remove the FFU file from the $FFUDevelopmentPath\FFU folder after it has been copied to the USB drive. Default is $false.
.PARAMETER UpdateLatestCU
When set to $true, will download and install the latest cumulative update for Windows 10/11. Default is $false.
.PARAMETER UpdateLatestNet
When set to $true, will download and install the latest .NET Framework for Windows 10/11. Default is $false.
.PARAMETER UpdateLatestDefender
When set to $true, will download and install the latest Windows Defender definitions and Defender platform update. Default is $false.
.PARAMETER UpdateEdge
When set to $true, will download and install the latest Microsoft Edge for Windows 10/11. Default is $false.
.PARAMETER UpdateOneDrive
When set to $true, will download and install the latest OneDrive for Windows 10/11 and install it as a per machine installation instead of per user. Default is $false.
.PARAMETER CopyPPKG
When set to $true, will copy the provisioning package from the $FFUDevelopmentPath\PPKG folder to the Deployment partition of the USB drive. Default is $false.
.PARAMETER CopyUnattend
When set to $true, will copy the $FFUDevelopmentPath\Unattend folder to the Deployment partition of the USB drive. Default is $false.
.PARAMETER CopyAutopilot
When set to $true, will copy the $FFUDevelopmentPath\Autopilot folder to the Deployment partition of the USB drive. Default is $false.
.PARAMETER CompactOS
When set to $true, will compact the OS when building the FFU. Default is $true.
.PARAMETER CleanupCaptureISO
When set to $true, will remove the WinPE capture ISO after the FFU has been captured. Default is $true.
.PARAMETER CleanupDeployISO
When set to $true, will remove the WinPE deployment ISO after the FFU has been captured. Default is $true.
.PARAMETER CleanupAppsISO
When set to $true, will remove the Apps ISO after the FFU has been captured. Default is $true.
.EXAMPLE .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
Command line for most people who want to create an FFU with Office and drivers and have downloaded their own ISO. This assumes you have copied this script and associated files to the C:\FFUDevelopment folder. If you need to use another drive or folder, change the -FFUDevelopment parameter (e.g. -FFUDevelopment 'D:\FFUDevelopment') Command line for most people who want to create an FFU with Office and drivers and have downloaded their own ISO. This assumes you have copied this script and associated files to the C:\FFUDevelopment folder. If you need to use another drive or folder, change the -FFUDevelopment parameter (e.g. -FFUDevelopment 'D:\FFUDevelopment')
.\BuildFFUVM.ps1 -ISOPath 'C:\path_to_iso\Windows.iso' -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 -verbose .\BuildFFUVM.ps1 -ISOPath 'C:\path_to_iso\Windows.iso' -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 -verbose
@@ -100,11 +155,14 @@ Command line for those who just want a FFU with Apps and drivers, no Office and
Command line for those who want to download the latest Windows 11 Pro x64 media in English (US) and install the latest version of Office and drivers. Command line for those who want to download the latest Windows 11 Pro x64 media in English (US) and install the latest version of Office and drivers.
.\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 -verbose .\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 -verbose
Command line for those who want to download the latest Windows 11 Pro x64 media in English (US) and install the latest version of Office and drivers.
.\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 -verbose
Command line for those who want to download the latest Windows 11 Pro x64 media in French (CA) and install the latest version of Office and drivers. Command line for those who want to download the latest Windows 11 Pro x64 media in French (CA) and install the latest version of Office and drivers.
.\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 -WindowsRelease 11 -WindowsArch 'x64' -WindowsLang 'fr-ca' -MediaType 'consumer' -verbose .\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 -WindowsRelease 11 -WindowsArch 'x64' -WindowsLang 'fr-ca' -MediaType 'consumer' -verbose
Command line with all parameters for reference Command line for those who want to download the latest Windows 11 Pro x64 media in English (US) and install the latest version of Office and drivers.
.\BuildFFUVM.ps1 -ISOPath "C:\path_to_iso\Windows.iso" -WindowsSKU "Pro" -FFUDevelopmentPath "C:\FFUDevelopment" -InstallApps $true -InstallOffice $true -InstallDrivers $true -Memory 8GB -Disksize 30GB -Processors 4 -VMSwitchName "Your VM Switch Name" -VMLocation "C:\VMs" -FFUPrefix "_FFU" -FFUCaptureLocation "C:\FFUDevelopment\FFU" -ShareName "FFUCaptureShare" -Username "ffu_user" -VMHostIPAddress "Your IP Address" -CreateCaptureMedia $true -CreateDeploymentMedia $false -OptionalFeatures "NetFx3;TFTP" -ProductKey "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX -BuildUSBDrive $true -WindowsRelease 11 -WindowsArch 'x64' -WindowsLang 'en-us' -MediaType 'consumer' -verbose" .\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 -verbose
.NOTES .NOTES
Additional notes about your script. Additional notes about your script.
@@ -113,6 +171,7 @@ Command line with all parameters for reference
https://github.com/rbalsleyMSFT/FFU https://github.com/rbalsleyMSFT/FFU
#> #>
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(Mandatory = $false, Position = 0)] [Parameter(Mandatory = $false, Position = 0)]
@@ -125,7 +184,7 @@ param(
})] })]
[string]$WindowsSKU = 'Pro', [string]$WindowsSKU = 'Pro',
[ValidateScript({ Test-Path $_ })] [ValidateScript({ Test-Path $_ })]
[string]$FFUDevelopmentPath = 'C:\FFUDevelopment', [string]$FFUDevelopmentPath = $PSScriptRoot,
[bool]$InstallApps, [bool]$InstallApps,
[bool]$InstallOffice, [bool]$InstallOffice,
[Parameter(Mandatory = $false)] [Parameter(Mandatory = $false)]
@@ -185,7 +244,9 @@ param(
[ValidateSet(10, 11)] [ValidateSet(10, 11)]
[int]$WindowsRelease = 11, [int]$WindowsRelease = 11,
[Parameter(Mandatory = $false)] [Parameter(Mandatory = $false)]
[ValidateSet('x86', 'x64')] [string]$WindowsVersion = '23h2',
[Parameter(Mandatory = $false)]
[ValidateSet('x86', 'x64', 'arm64')]
[string]$WindowsArch = 'x64', [string]$WindowsArch = 'x64',
[ValidateScript({ [ValidateScript({
$allowedLang = @('ar-sa', 'bg-bg', 'cs-cz', 'da-dk', 'de-de', 'el-gr', 'en-gb', 'en-us', 'es-es', 'es-mx', 'et-ee', 'fi-fi', 'fr-ca', 'fr-fr', 'he-il', 'hr-hr', 'hu-hu', $allowedLang = @('ar-sa', 'bg-bg', 'cs-cz', 'da-dk', 'de-de', 'el-gr', 'en-gb', 'en-us', 'es-es', 'es-mx', 'et-ee', 'fi-fi', 'fr-ca', 'fr-fr', 'he-il', 'hr-hr', 'hu-hu',
@@ -210,12 +271,22 @@ param(
return $true return $true
})] })]
[bool]$CopyDrivers, [bool]$CopyDrivers,
#Will be used in future release [bool]$CopyPEDrivers,
[bool]$RemoveFFU,
[bool]$UpdateLatestCU,
[bool]$UpdateLatestNet,
[bool]$UpdateLatestDefender,
[bool]$UpdateEdge,
[bool]$UpdateOneDrive,
[bool]$CopyPPKG, [bool]$CopyPPKG,
[bool]$CopyUnattend, [bool]$CopyUnattend,
[bool]$RemoveFFU [bool]$CopyAutopilot,
[bool]$CompactOS = $true,
[bool]$CleanupCaptureISO = $true,
[bool]$CleanupDeployISO = $true,
[bool]$CleanupAppsISO = $true
) )
$version = '2401.1' $version = '2402.1'
#Check if Hyper-V feature is installed (requires only checks the module) #Check if Hyper-V feature is installed (requires only checks the module)
$osInfo = Get-WmiObject -Class Win32_OperatingSystem $osInfo = Get-WmiObject -Class Win32_OperatingSystem
@@ -239,6 +310,8 @@ else {
# Set default values for variables that depend on other parameters # Set default values for variables that depend on other parameters
if (-not $AppsISO) { $AppsISO = "$FFUDevelopmentPath\Apps.iso" } if (-not $AppsISO) { $AppsISO = "$FFUDevelopmentPath\Apps.iso" }
if (-not $AppsPath) { $AppsPath = "$FFUDevelopmentPath\Apps" } if (-not $AppsPath) { $AppsPath = "$FFUDevelopmentPath\Apps" }
if (-not $DeployISO) { $DeployISO = "$FFUDevelopmentPath\WinPE_FFU_Deploy.iso" }
if (-not $CaptureISO) { $CaptureISO = "$FFUDevelopmentPath\WinPE_FFU_Capture.iso" }
if (-not $OfficePath) { $OfficePath = "$AppsPath\Office" } if (-not $OfficePath) { $OfficePath = "$AppsPath\Office" }
if (-not $rand) { $rand = Get-Random } if (-not $rand) { $rand = Get-Random }
if (-not $VMLocation) { $VMLocation = "$FFUDevelopmentPath\VM" } if (-not $VMLocation) { $VMLocation = "$FFUDevelopmentPath\VM" }
@@ -247,6 +320,10 @@ if (-not $VMPath) { $VMPath = "$VMLocation\$VMName" }
if (-not $VHDXPath) { $VHDXPath = "$VMPath\$VMName.vhdx" } if (-not $VHDXPath) { $VHDXPath = "$VMPath\$VMName.vhdx" }
if (-not $FFUCaptureLocation) { $FFUCaptureLocation = "$FFUDevelopmentPath\FFU" } if (-not $FFUCaptureLocation) { $FFUCaptureLocation = "$FFUDevelopmentPath\FFU" }
if (-not $LogFile) { $LogFile = "$FFUDevelopmentPath\FFUDevelopment.log" } if (-not $LogFile) { $LogFile = "$FFUDevelopmentPath\FFUDevelopment.log" }
if (-not $KBPath) { $KBPath = "$FFUDevelopmentPath\KB" }
if (-not $DefenderPath) { $DefenderPath = "$AppsPath\Defender" }
if (-not $OneDrivePath) { $OneDrivePath = "$AppsPath\OneDrive" }
if (-not $EdgePath) { $EdgePath = "$AppsPath\Edge" }
#FUNCTIONS #FUNCTIONS
function WriteLog($LogText) { function WriteLog($LogText) {
@@ -500,6 +577,117 @@ function Get-Office {
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $content Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $content
} }
} }
function Get-KBLink {
param(
[Parameter(Mandatory)]
[string]$Name
)
$results = Invoke-WebRequest -Uri "http://www.catalog.update.microsoft.com/Search.aspx?q=$Name"
$kbids = $results.InputFields |
Where-Object { $_.type -eq 'Button' -and $_.Value -eq 'Download' } |
Select-Object -ExpandProperty ID
Write-Verbose -Message "$kbids"
if (-not $kbids) {
Write-Warning -Message "No results found for $Name"
return
}
$guids = $results.Links |
Where-Object ID -match '_link' |
Where-Object { $_.OuterHTML -match ( "(?=.*" + ( $Filter -join ")(?=.*" ) + ")" ) } |
ForEach-Object { $_.id.replace('_link', '') } |
Where-Object { $_ -in $kbids }
if (-not $guids) {
Write-Warning -Message "No file found for $Name"
return
}
foreach ($guid in $guids) {
Write-Verbose -Message "Downloading information for $guid"
$post = @{ size = 0; updateID = $guid; uidInfo = $guid } | ConvertTo-Json -Compress
$body = @{ updateIDs = "[$post]" }
$links = Invoke-WebRequest -Uri 'https://www.catalog.update.microsoft.com/DownloadDialog.aspx' -Method Post -Body $body |
Select-Object -ExpandProperty Content |
Select-String -AllMatches -Pattern "http[s]?://[^']*\.microsoft\.com/[^']*|http[s]?://[^']*\.windowsupdate\.com/[^']*" |
Select-Object -Unique
foreach ($link in $links) {
$link.matches.value
#Filter out cab files
# #if ($link -notmatch '\.cab') {
# $link.matches.value
# }
}
}
}
function Get-LatestWindowsKB {
param (
[ValidateSet(10, 11)]
[int]$WindowsRelease
)
# Define the URL of the update history page based on the Windows release
if ($WindowsRelease -eq 11) {
$updateHistoryUrl = 'https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information'
}
else {
$updateHistoryUrl = 'https://learn.microsoft.com/en-us/windows/release-health/release-information'
}
# Use Invoke-WebRequest to fetch the content of the page
$response = Invoke-WebRequest -Uri $updateHistoryUrl
# Use a regular expression to find the KB article number
$kbArticleRegex = 'KB\d+'
$kbArticle = [regex]::Match($response.Content, $kbArticleRegex).Value
return $kbArticle
}
function Save-KB {
[CmdletBinding()]
param(
[string[]]$Name,
[string]$Path
)
if ($WindowsArch -eq 'x64') {
[array]$WindowsArch = @("x64", "amd64")
}
foreach ($kb in $name) {
$links = Get-KBLink -Name $kb
foreach ($link in $links) {
#Check if $WindowsArch is an array
if ($WindowsArch -is [array]) {
#Some file names include either x64 or amd64
if ($link -match $WindowsArch[0] -or $link -match $WindowsArch[1]) {
Start-BitsTransfer -Source $link -Destination $Path
$fileName = ($link -split '/')[-1]
break
}
elseif (!($link -match 'x64' -or $link -match 'amd64' -or $link -match 'x86' -or $link -match 'arm64')) {
Write-Host "No architecture found in $link, assume it's for all architectures"
Start-BitsTransfer -Source $link -Destination $Path
$fileName = ($link -split '/')[-1]
break
}
}
else {
if ($link -match $WindowsArch) {
Start-BitsTransfer -Source $link -Destination $Path
$fileName = ($link -split '/')[-1]
break
}
}
}
}
return $fileName
}
function New-AppsISO { function New-AppsISO {
#Create Apps ISO file #Create Apps ISO file
@@ -515,7 +703,6 @@ function New-AppsISO {
Remove-Item -Path $OfficeDownloadPath -Recurse -Force Remove-Item -Path $OfficeDownloadPath -Recurse -Force
Remove-Item -Path "$ODTPath\setup.exe" Remove-Item -Path "$ODTPath\setup.exe"
} }
} }
function Get-WimFromISO { function Get-WimFromISO {
#Mount ISO, get Wim file #Mount ISO, get Wim file
@@ -706,9 +893,13 @@ function New-OSPartition {
if ((Get-CimInstance Win32_OperatingSystem).Caption -match "Server") { if ((Get-CimInstance Win32_OperatingSystem).Caption -match "Server") {
WriteLog (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\") WriteLog (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\")
} }
else { if ($CompactOS) {
WriteLog '$CompactOS is set to true, using -Compact switch to apply the WIM file to the OS partition.'
WriteLog (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\" -Compact) WriteLog (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\" -Compact)
} }
else {
WriteLog (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\")
}
WriteLog 'Done' WriteLog 'Done'
return $osPartition return $osPartition
@@ -952,8 +1143,17 @@ function New-PEMedia {
WriteLog "Copying $FFUDevelopmentPath\WinPEDeployFFUFiles\* to WinPE deploy media" WriteLog "Copying $FFUDevelopmentPath\WinPEDeployFFUFiles\* to WinPE deploy media"
Copy-Item -Path "$FFUDevelopmentPath\WinPEDeployFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force | Out-Null Copy-Item -Path "$FFUDevelopmentPath\WinPEDeployFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force | Out-Null
WriteLog 'Copy complete' WriteLog 'Copy complete'
# If you need to add drivers (storage/keyboard most likely), remove the '#' from the below line and change the /Driver:Path to a folder of drivers #If $CopyPEDrivers = $true, add drivers to WinPE media using dism
# & dism /image:$WinPEFFUPath\mount /Add-Driver /Driver:<Path to Drivers folder e.g c:\drivers> /Recurse 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' $WinPEISOName = 'WinPE_FFU_Deploy.iso'
$Deploy = $false $Deploy = $false
} }
@@ -979,13 +1179,10 @@ function New-FFU {
#If $InstallApps = $true, configure the VM #If $InstallApps = $true, configure the VM
If ($InstallApps) { If ($InstallApps) {
WriteLog 'Creating FFU from VM' WriteLog 'Creating FFU from VM'
#Mount the Capture ISO to the VM WriteLog "Setting $CaptureISO as first boot device"
$CaptureISOPath = "$FFUDevelopmentPath\WinPE_FFU_Capture.iso"
WriteLog "Setting $CaptureISOPath as first boot device"
$VMDVDDrive = Get-VMDvdDrive -VMName $VMName $VMDVDDrive = Get-VMDvdDrive -VMName $VMName
Set-VMFirmware -VMName $VMName -FirstBootDevice $VMDVDDrive Set-VMFirmware -VMName $VMName -FirstBootDevice $VMDVDDrive
Set-VMDvdDrive -VMName $VMName -Path $CaptureISOPath Set-VMDvdDrive -VMName $VMName -Path $CaptureISO
$VMSwitch = Get-VMSwitch -name $VMSwitchName $VMSwitch = Get-VMSwitch -name $VMSwitchName
WriteLog "Setting $($VMSwitch.Name) as VMSwitch" WriteLog "Setting $($VMSwitch.Name) as VMSwitch"
get-vm $VMName | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName $VMSwitch.Name get-vm $VMName | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName $VMSwitch.Name
@@ -1059,7 +1256,7 @@ function New-FFU {
WriteLog 'Folder removed' WriteLog 'Folder removed'
} }
#Optimize FFU #Optimize FFU
if($Optimize -eq $true){ if ($Optimize -eq $true) {
WriteLog 'Optimizing FFU - This will take a few minutes, please be patient' WriteLog 'Optimizing FFU - This will take a few minutes, please be patient'
#Invoke-Process cmd "/c ""$DandIEnv"" && dism /optimize-ffu /imagefile:$FFUFile" #Invoke-Process cmd "/c ""$DandIEnv"" && dism /optimize-ffu /imagefile:$FFUFile"
Invoke-Process cmd "/c dism /optimize-ffu /imagefile:$FFUFile" Invoke-Process cmd "/c dism /optimize-ffu /imagefile:$FFUFile"
@@ -1084,7 +1281,6 @@ function Remove-FFUVM {
WriteLog "Removing VM: $VMName" WriteLog "Removing VM: $VMName"
Remove-VM -Name $VMName -Force Remove-VM -Name $VMName -Force
WriteLog 'Removal complete' WriteLog 'Removal complete'
$VMPath = $FFUVM.Path
WriteLog "Removing $VMPath" WriteLog "Removing $VMPath"
Remove-Item -Path $VMPath -Force -Recurse Remove-Item -Path $VMPath -Force -Recurse
WriteLog 'Removal complete' WriteLog 'Removal complete'
@@ -1186,15 +1382,7 @@ Function Get-WindowsVersionInfo {
SKU = $SKU SKU = $SKU
} }
} }
Function New-DeploymentUSB { Function Get-USBDrive {
param(
[switch]$CopyFFU
)
WriteLog "CopyFFU is set to $CopyFFU"
$BuildUSBPath = $PSScriptRoot
WriteLog "BuildUSBPath is $BuildUSBPath"
$counter = 0
$USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'") $USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'")
If ($USBDrives -and ($null -eq $USBDrives.count)) { If ($USBDrives -and ($null -eq $USBDrives.count)) {
$USBDrivesCount = 1 $USBDrivesCount = 1
@@ -1205,9 +1393,19 @@ Function New-DeploymentUSB {
WriteLog "Found $USBDrivesCount USB drives" WriteLog "Found $USBDrivesCount USB drives"
if ($null -eq $USBDrives) { if ($null -eq $USBDrives) {
WriteLog "No removable USB drive found." WriteLog "No removable USB drive found. Exiting"
Write-Error "No removable USB drive found. Exiting"
exit 1 exit 1
} }
return $USBDrives, $USBDrivesCount
}
Function New-DeploymentUSB {
param(
[switch]$CopyFFU
)
WriteLog "CopyFFU is set to $CopyFFU"
$BuildUSBPath = $PSScriptRoot
WriteLog "BuildUSBPath is $BuildUSBPath"
$SelectedFFUFile = $null $SelectedFFUFile = $null
@@ -1239,6 +1437,7 @@ Function New-DeploymentUSB {
Return Return
} }
} }
$counter = 0
foreach ($USBDrive in $USBDrives) { foreach ($USBDrive in $USBDrives) {
$Counter++ $Counter++
@@ -1263,10 +1462,10 @@ Function New-DeploymentUSB {
WriteLog 'Done' 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
$ISOMountPoint = (Mount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" -PassThru | Get-Volume).DriveLetter + ":\" $ISOMountPoint = (Mount-DiskImage -ImagePath $DeployISO -PassThru | Get-Volume).DriveLetter + ":\"
WriteLog "Copying WinPE files to $BootPartitionDriveLetter" WriteLog "Copying WinPE files to $BootPartitionDriveLetter"
robocopy "$ISOMountPoint" "$BootPartitionDriveLetter" /E /COPYALL /R:5 /W:5 /J robocopy "$ISOMountPoint" "$BootPartitionDriveLetter" /E /COPYALL /R:5 /W:5 /J
Dismount-DiskImage -ImagePath "$BuildUSBPath\WinPE_FFU_Deploy.iso" | Out-Null Dismount-DiskImage -ImagePath $DeployISO | Out-Null
if ($CopyFFU.IsPresent) { if ($CopyFFU.IsPresent) {
if ($null -ne $SelectedFFUFile) { if ($null -ne $SelectedFFUFile) {
@@ -1281,10 +1480,26 @@ Function New-DeploymentUSB {
WriteLog ("Copying " + $SelectedFFUFile + " to $DeployPartitionDriveLetter. This could take a few minutes.") 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 robocopy $(Split-Path $SelectedFFUFile -Parent) $DeployPartitionDriveLetter $(Split-Path $SelectedFFUFile -Leaf) /COPYALL /R:5 /W:5 /J
} }
if ($CopyDrivers -eq $true) { #Copy drivers using robocopy due to potential size
if ($CopyDrivers) {
WriteLog "Copying drivers to $DeployPartitionDriveLetter\Drivers" WriteLog "Copying drivers to $DeployPartitionDriveLetter\Drivers"
robocopy "$FFUDevelopmentPath\Drivers" "$DeployPartitionDriveLetter\Drivers" /E /R:5 /W:5 /J robocopy "$FFUDevelopmentPath\Drivers" "$DeployPartitionDriveLetter\Drivers" /E /R:5 /W:5 /J
} }
#Copy Unattend folder in the FFU folder to the USB drive. Can use copy-item as it's a small folder
if ($CopyUnattend) {
WriteLog "Copying Unattend folder to $DeployPartitionDriveLetter"
Copy-Item -Path "$FFUDevelopmentPath\Unattend" -Destination $DeployPartitionDriveLetter -Recurse -Force
}
#Copy PPKG folder in the FFU folder to the USB drive. Can use copy-item as it's a small folder
if ($CopyPPKG) {
WriteLog "Copying PPKG folder to $DeployPartitionDriveLetter"
Copy-Item -Path "$FFUDevelopmentPath\PPKG" -Destination $DeployPartitionDriveLetter -Recurse -Force
}
#Copy Autopilot folder in the FFU folder to the USB drive. Can use copy-item as it's a small folder
if ($CopyAutopilot) {
WriteLog "Copying Autopilot folder to $DeployPartitionDriveLetter"
Copy-Item -Path "$FFUDevelopmentPath\Autopilot" -Destination $DeployPartitionDriveLetter -Recurse -Force
}
} }
else { else {
WriteLog "No FFU file selected. Skipping copy." WriteLog "No FFU file selected. Skipping copy."
@@ -1382,15 +1597,83 @@ function Get-FFUEnvironment {
WriteLog 'Complete' WriteLog 'Complete'
#Clean up registry #Clean up registry
if (Test-Path -Path 'HKLM:\FFU'){ if (Test-Path -Path 'HKLM:\FFU') {
Writelog 'Found HKLM:\FFU, removing it' Writelog 'Found HKLM:\FFU, removing it'
Invoke-Process reg "unload HKLM\FFU" Invoke-Process reg "unload HKLM\FFU"
} }
#Remove FFU User and Share
$UserExists = Get-LocalUser -Name $UserName -ErrorAction SilentlyContinue
if ($UserExists) {
WriteLog "Removing FFU User and Share"
Remove-FFUUserShare
WriteLog 'Removal complete'
}
#Clean up $KBPath
If (Test-Path -Path $KBPath) {
WriteLog "Removing $KBPath"
Remove-Item -Path $KBPath -Recurse -Force
WriteLog 'Removal complete'
}
#Clean up $DefenderPath
If (Test-Path -Path $DefenderPath) {
WriteLog "Removing $DefenderPath"
Remove-Item -Path $DefenderPath -Recurse -Force
WriteLog 'Removal complete'
}
#Clean up $OneDrivePath
If (Test-Path -Path $OneDrivePath) {
WriteLog "Removing $OneDrivePath"
Remove-Item -Path $OneDrivePath -Recurse -Force
WriteLog 'Removal complete'
}
#Clean up $EdgePath
If (Test-Path -Path $EdgePath) {
WriteLog "Removing $EdgePath"
Remove-Item -Path $EdgePath -Recurse -Force
WriteLog 'Removal complete'
}
Writelog 'Removing dirty.txt file' Writelog 'Removing dirty.txt file'
Remove-Item -Path "$FFUDevelopmentPath\dirty.txt" -Force Remove-Item -Path "$FFUDevelopmentPath\dirty.txt" -Force
WriteLog "Cleanup complete" WriteLog "Cleanup complete"
} }
function Remove-FFU {
#Remove all FFU files in the FFUCaptureLocation
WriteLog "Removing all FFU files in $FFUCaptureLocation"
Remove-Item -Path $FFUCaptureLocation\*.ffu -Force
WriteLog "Removal complete"
}
function Clear-InstallAppsandSysprep {
if ($UpdateLatestDefender) {
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"
}
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"
}
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"
}
}
###END FUNCTIONS ###END FUNCTIONS
@@ -1425,12 +1708,15 @@ if (($InstallApps -and ($VMHostIPAddress -eq ''))) {
if (-not ($ISOPath) -and ($OptionalFeatures -like '*netfx3*')) { if (-not ($ISOPath) -and ($OptionalFeatures -like '*netfx3*')) {
throw "netfx3 specified as an optional feature, however Windows ISO isn't defined. Unable to get netfx3 source files from downloaded ESD media. Please specify a Windows ISO in the ISOPath parameter." throw "netfx3 specified as an optional feature, however Windows ISO isn't defined. Unable to get netfx3 source files from downloaded ESD media. Please specify a Windows ISO in the ISOPath parameter."
} }
if (($LogicalSectorSizeBytes -eq 4096) -and ($installdrivers -eq $true)){ if (($LogicalSectorSizeBytes -eq 4096) -and ($installdrivers -eq $true)) {
$installdrivers = $false $installdrivers = $false
WriteLog 'LogicalSectorSizeBytes is set to 4096, which is not supported for driver injection. Setting $installdrivers to $false' WriteLog 'LogicalSectorSizeBytes is set to 4096, which is not supported for driver injection. Setting $installdrivers to $false'
WriteLog 'As a workaround, set -copydrivers $true to copy drivers to the deploy partition drivers folder' WriteLog 'As a workaround, set -copydrivers $true to copy drivers to the deploy partition drivers folder'
WriteLog 'We are investigating this issue and will update the script if/when we have a fix' WriteLog 'We are investigating this issue and will update the script if/when we have a fix'
} }
if ($BuildUSBDrive -eq $true) {
$USBDrives, $USBDrivesCount = Get-USBDrive
}
#Get script variable values #Get script variable values
LogVariableValues LogVariableValues
@@ -1447,9 +1733,11 @@ catch {
} }
#Check if environment is dirty #Check if environment is dirty
If(Test-Path -Path "$FFUDevelopmentPath\dirty.txt"){ If (Test-Path -Path "$FFUDevelopmentPath\dirty.txt") {
Get-FFUEnvironment Get-FFUEnvironment
} }
WriteLog 'Creating dirty.txt file'
New-Item -Path .\ -Name "dirty.txt" -ItemType "file" | Out-Null
#Create apps ISO for Office and/or 3rd party apps #Create apps ISO for Office and/or 3rd party apps
if ($InstallApps) { if ($InstallApps) {
@@ -1465,8 +1753,8 @@ if ($InstallApps) {
if (-not $InstallOffice) { if (-not $InstallOffice) {
#Modify InstallAppsandSysprep.cmd to REM out the office install command #Modify InstallAppsandSysprep.cmd to REM out the office install command
$cmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" $CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $cmdContent -replace '^(d:\\Office\\setup.exe /configure d:\\office\\DeployFFU.xml)', ("REM d:\Office\setup.exe /configure d:\office\DeployFFU.xml") $UpdatedcmdContent = $CmdContent -replace '^(d:\\Office\\setup.exe /configure d:\\office\\DeployFFU.xml)', ("REM d:\Office\setup.exe /configure d:\office\DeployFFU.xml")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
} }
@@ -1476,6 +1764,118 @@ if ($InstallApps) {
WriteLog 'Downloading M365 Apps/Office completed successfully' WriteLog 'Downloading M365 Apps/Office completed successfully'
} }
#Update Latest Defender Platform and Definitions - these can't be serviced into the VHDX, will be saved to AppsPath
if ($UpdateLatestDefender) {
WriteLog "`$UpdateLatestDefender is set to true, checking for latest Defender Platform and Definitions"
$Name = 'Update for Microsoft Defender Antivirus antimalware platform'
#Check if $DefenderPath exists, if not, create it
If (-not (Test-Path -Path $DefenderPath)) {
WriteLog "Creating $DefenderPath"
New-Item -Path $DefenderPath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $DefenderPath"
$KBFilePath = Save-KB -Name $Name -Path $DefenderPath
WriteLog "Latest Defender Platform and Definitions saved to $DefenderPath\$KBFilePath"
#Modify InstallAppsandSysprep.cmd to add in $KBFilePath on the line after REM Install Defender Update Platform
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Defender Platform Update"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install Defender Platform Update)', ("REM Install Defender Platform Update`r`nd:\Defender\$KBFilePath")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
#Get Windows Security platform update
$Name = "Windows Security platform definition updates"
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $DefenderPath"
$KBFilePath = Save-KB -Name $Name -Path $DefenderPath
WriteLog "Latest Security Platform Update saved to $DefenderPath\$KBFilePath"
#Modify InstallAppsandSysprep.cmd to add in $KBFilePath on the line after REM Install Windows Security Platform Update
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Windows Security Platform Update"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install Windows Security Platform Update)', ("REM Install Windows Security Platform Update`r`nd:\Defender\$KBFilePath")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
#Download latest Defender Definitions
WriteLog "Downloading latest Defender Definitions"
# Defender def updates can be found https://www.microsoft.com/en-us/wdsi/defenderupdates
if ($WindowsArch -eq 'x64') {
$DefenderDefURL = 'https://go.microsoft.com/fwlink/?LinkID=121721&arch=x64'
}
if ($WindowsArch -eq 'ARM64') {
$DefenderDefURL = 'https://go.microsoft.com/fwlink/?LinkID=121721&arch=arm'
}
try {
Start-BitsTransfer -Source $DefenderDefURL -Destination "$DefenderPath\mpam-fe.exe"
WriteLog "Defender Definitions downloaded to $DefenderPath\mpam-fe.exe"
}
catch {
Write-Host "Downloading Defender Definitions Failed"
WriteLog "Downloading Defender Definitions Failed with error $_"
throw $_
}
#Modify InstallAppsandSysprep.cmd to add in $DefenderPath on the line after REM Install Defender Definitions
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Defender Definitions"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install Defender Definitions)', ("REM Install Defender Definitions`r`nd:\Defender\mpam-fe.exe")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
}
#Download and Install OneDrive Per Machine
if ($UpdateOneDrive) {
#Check if $OneDrivePath exists, if not, create it
If (-not (Test-Path -Path $OneDrivePath)) {
WriteLog "Creating $OneDrivePath"
New-Item -Path $OneDrivePath -ItemType Directory -Force | Out-Null
}
WriteLog "Downloading latest OneDrive client"
$OneDriveURL = 'https://go.microsoft.com/fwlink/?linkid=844652'
try {
Start-BitsTransfer -Source $OneDriveURL -Destination "$OneDrivePath\OneDriveSetup.exe"
WriteLog "Defender Definitions downloaded to $OneDrivePath\OneDriveSetup.exe"
}
catch {
Write-Host "Downloading OneDrive client Failed"
WriteLog "Downloading OneDrive client Failed with error $_"
throw $_
}
#Modify InstallAppsandSysprep.cmd to add in $OneDrivePath on the line after REM Install Defender Definitions
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include OneDrive client"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install OneDrive Per Machine)', ("REM Install OneDrive Per Machine`r`nd:\OneDrive\OneDriveSetup.exe /allusers")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
}
#Download and Install Edge Stable
if ($UpdateEdge) {
WriteLog "`$UpdateEdge is set to true, checking for latest Edge Stable $WindowsArch release"
$Name = "microsoft edge stable -extended $WindowsArch"
#Check if $EdgePath exists, if not, create it
If (-not (Test-Path -Path $EdgePath)) {
WriteLog "Creating $EdgePath"
New-Item -Path $EdgePath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $EdgePath"
$KBFilePath = Save-KB -Name $Name -Path $EdgePath
$EdgeCABFilePath = "$EdgePath\$KBFilePath"
WriteLog "Latest Edge Stable $WindowsArch release saved to $EdgeCABFilePath"
#Extract Edge cab file to same folder as $EdgeFilePath
$EdgeMSIFileName = "MicrosoftEdgeEnterprise$WindowsArch.msi"
$EdgeFullFilePath = "$EdgePath\$EdgeMSIFileName"
WriteLog "Extracting $EdgeCABFilePath"
Invoke-Process Expand "$EdgeCABFilePath -F:*.msi $EdgeFullFilePath"
WriteLog "Extraction complete"
#Modify InstallAppsandSysprep.cmd to add in $KBFilePath on the line after REM Install Edge Stable
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Edge Stable $WindowsArch release"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install Edge Stable)', ("REM Install Edge Stable`r`nd:\Edge\$EdgeMSIFileName /quiet /norestart")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
}
#Create Apps ISO #Create Apps ISO
WriteLog "Creating $AppsISO file" WriteLog "Creating $AppsISO file"
New-AppsISO New-AppsISO
@@ -1490,8 +1890,6 @@ if ($InstallApps) {
#Create VHDX #Create VHDX
try { 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) { if ($ISOPath) {
$wimPath = Get-WimFromISO $wimPath = Get-WimFromISO
@@ -1521,6 +1919,67 @@ try {
Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1] Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1]
#Update latest Cumulative Update
If ($UpdateLatestCU) {
WriteLog "`$UpdateLatestCU is set to true, checking for latest CU"
$LatestKB = Get-LatestWindowsKB -WindowsRelease $WindowsRelease
WriteLog "Latest KB for Windows $WindowsRelease found: $LatestKB"
$Name = $LatestKB + " " + $WindowsVersion
#Check if $KBPath exists, if not, create it
If (-not (Test-Path -Path $KBPath)) {
WriteLog "Creating $KBPath"
New-Item -Path $KBPath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $KBPath"
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "$LatestKB saved to $KBPath\$KBFilePath"
}
#Update Latest .NET Framework
if ($UpdateLatestNet) {
Writelog "`$UpdateLatestNet is set to true, checking for latest .NET Framework"
$Name = "Cumulative update for .net framework windows $WindowsRelease $WindowsVersion $Architecture"
#Check if $KBPath exists, if not, create it
If (-not (Test-Path -Path $KBPath)) {
WriteLog "Creating $KBPath"
New-Item -Path $KBPath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $name from Microsoft Update Catalog and saving to $KBPath"
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "Latest .NET saved to $KBPath\$KBFilePath"
}
#Update Latest Security Platform Update
if ($UpdateSecurityPlatform) {
WriteLog "`$UpdateSecurityPlatform is set to true, checking for latest Security Platform Update"
$Name = "Windows Security platform definition updates"
#Check if $KBPath exists, if not, create it
If (-not (Test-Path -Path $KBPath)) {
WriteLog "Creating $KBPath"
New-Item -Path $KBPath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $KBPath"
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "Latest Security Platform Update saved to $KBPath\$KBFilePath"
}
#Add Windows packages
if ($UpdateLatestCU -or $UpdateLatestNet) {
try {
WriteLog "Adding KBs to $WindowsPartition"
Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath | Out-Null
WriteLog "KBs added to $WindowsPartition"
WriteLog "Removing $KBPath"
Remove-Item -Path $KBPath -Recurse -Force | Out-Null
}
catch {
Write-Host "Adding KB to VHDX failed with error $_"
WriteLog "Adding KB to VHDX failed with error $_"
throw $_
}
}
#Enable Windows Optional Features (e.g. .Net3, etc) #Enable Windows Optional Features (e.g. .Net3, etc)
If ($OptionalFeatures) { If ($OptionalFeatures) {
$Source = Join-Path (Split-Path $wimpath) "sxs" $Source = Join-Path (Split-Path $wimpath) "sxs"
@@ -1674,6 +2133,17 @@ catch {
Writelog "VM or vhdx cleanup failed with error $_" Writelog "VM or vhdx cleanup failed with error $_"
throw $_ 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 $_
}
#Create Deployment Media #Create Deployment Media
If ($CreateDeploymentMedia) { If ($CreateDeploymentMedia) {
try { try {
@@ -1688,11 +2158,11 @@ If ($CreateDeploymentMedia) {
} }
If ($BuildUSBDrive) { If ($BuildUSBDrive) {
try { try {
If (Test-Path -Path "$FFUDevelopmentPath\WinPE_FFU_Deploy.iso") { If (Test-Path -Path $DeployISO) {
New-DeploymentUSB -CopyFFU New-DeploymentUSB -CopyFFU
} }
else { else {
WriteLog "$BuildUSBDrive set to true, however unable to find WinPE_FFU_Deploy.iso. USB drive not built." WriteLog "$BuildUSBDrive set to true, however unable to find $DeployISO. USB drive not built."
} }
} }
@@ -1702,6 +2172,56 @@ If ($BuildUSBDrive) {
throw $_ throw $_
} }
} }
If ($RemoveFFU) {
try {
Remove-FFU
}
catch {
Write-Host 'Removing FFU files failed'
Writelog "Removing FFU files failed with error $_"
throw $_
}
}
If ($CleanupCaptureISO) {
try {
If (Test-Path -Path $CaptureISO) {
WriteLog "Removing $CaptureISO"
Remove-Item -Path $CaptureISO -Force
WriteLog "Removal complete"
}
}
catch {
Writelog "Removing $CaptureISO failed with error $_"
throw $_
}
}
If ($CleanupDeployISO) {
try {
If (Test-Path -Path $DeployISO) {
WriteLog "Removing $DeployISO"
Remove-Item -Path $DeployISO -Force
WriteLog "Removal complete"
}
}
catch {
Writelog "Removing $DeployISO failed with error $_"
throw $_
}
}
If ($CleanupAppsISO) {
try {
If (Test-Path -Path $AppsISO) {
WriteLog "Removing $AppsISO"
Remove-Item -Path $AppsISO -Force
WriteLog "Removal complete"
}
}
catch {
Writelog "Removing $AppsISO failed with error $_"
throw $_
}
}
#Clean up dirty.txt file #Clean up dirty.txt file
Remove-Item -Path .\dirty.txt -Force | out-null Remove-Item -Path .\dirty.txt -Force | out-null
Write-Host "Script complete" Write-Host "Script complete"
Binary file not shown.
View File
View File
@@ -117,7 +117,7 @@ $LogFileName = 'ScriptLog.txt'
$USBDrive = Get-USBDrive $USBDrive = Get-USBDrive
New-item -Path $USBDrive -Name $LogFileName -ItemType "file" -Force | Out-Null New-item -Path $USBDrive -Name $LogFileName -ItemType "file" -Force | Out-Null
$LogFile = $USBDrive + $LogFilename $LogFile = $USBDrive + $LogFilename
$version = '2401.1' $version = '2402.1'
WriteLog 'Begin Logging' WriteLog 'Begin Logging'
WriteLog "Script version: $version" WriteLog "Script version: $version"
@@ -383,7 +383,7 @@ $Drivers = $USBDrive + "Drivers"
If (Test-Path -Path $Drivers) If (Test-Path -Path $Drivers)
{ {
#Check if multiple driver folders found, if so, just select one folder to save time/space #Check if multiple driver folders found, if so, just select one folder to save time/space
$DriverFolders = Get-ChildItem -Path $Drivers $DriverFolders = Get-ChildItem -Path $Drivers -directory
$DriverFoldersCount = $DriverFolders.count $DriverFoldersCount = $DriverFolders.count
If ($DriverFoldersCount -gt 1) If ($DriverFoldersCount -gt 1)
{ {
+27
View File
@@ -8,6 +8,33 @@ While we use this in Education at Microsoft, other industries can use it as well
# Updates # Updates
**2402.1**
**New functionality**
* If -BuildUSBDrve $true, script will now check for USB drive before continuing. If not present, script exits
* Added a number of new parameters.
| Parameter | Type | Description |
| -------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| CopyPEDrivers | Bool | When set to\$true, will copy the drivers from the \$FFUDevelopmentPath\PEDrivers folder to the WinPE deployment media. Default is \$false. |
| RemoveFFU | Bool | When set to\$true, will remove the FFU file from the\$FFUDevelopmentPath\FFU folder after it has been copied to the USB drive. Default is \$false. |
| UpdateLatestCU | Bool | When set to\$true, will download and install the latest cumulative update for Windows 10/11. Default is \$false. |
| UpdateLatestNet | Bool | When set to\$true, will download and install the latest .NET Framework for Windows 10/11. Default is \$false. |
| UpdateLatestDefender | Bool | When set to\$true, will download and install the latest Windows Defender definitions and Defender platform update. Default is \$false. |
| UpdateEdge | Bool | When set to\$true, will download and install the latest Microsoft Edge for Windows 10/11. Default is \$false. |
| UpdateOneDrive | Bool | When set to\$true, will download and install the latest OneDrive for Windows 10/11 and install it as a per machine installation instead of per user. Default is \$false. |
| CopyPPKG | Bool | When set to\$true, will copy the provisioning package from the \$FFUDevelopmentPath\PPKG folder to the Deployment partition of the USB drive. Default is \$false. |
| CopyUnattend | Bool | When set to\$true, will copy the \$FFUDevelopmentPath\Unattend folder to the Deployment partition of the USB drive. Default is \$false. |
| CopyAutopilot | Bool | When set to\$true, will copy the \$FFUDevelopmentPath\Autopilot folder to the Deployment partition of the USB drive. Default is \$false. |
| CompactOS | Bool | When set to\$true, will compact the OS when building the FFU. Default is \$true. |
| CleanupCaptureISO | Bool | When set to\$true, will remove the WinPE capture ISO after the FFU has been captured. Default is \$true. |
| CleanupDeployISO | Bool | When set to\$true, will remove the WinPE deployment ISO after the FFU has been captured. Default is \$true. |
| CleanupAppsISO | Bool | When set to\$true, will remove the Apps ISO after the FFU has been captured. Default is \$true. |
* Updated the docs with the new variables and made some minor modifications.
* Changed version variable to 2402.1
**2401.1** **2401.1**
- Added -CopyDrivers boolean parameter to control the ability to copy drivers to the USB drive in the deploy partition drivers folder. - Added -CopyDrivers boolean parameter to control the ability to copy drivers to the USB drive in the deploy partition drivers folder.