mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 10:19:36 -06:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 60d147c71d | |||
| cd36150ddc | |||
| 198a544dbb | |||
| 40616776eb | |||
| 20c9cf8ab3 | |||
| 17558f86aa | |||
| 7408dbb435 | |||
| 9c1fc59af9 | |||
| 31c785b5da | |||
| 5b93135ebb | |||
| 5f4cf0c66e | |||
| ddbf2b0339 | |||
| e62d481405 | |||
| 6c07ac8595 | |||
| 7d74feec0c | |||
| 6b2a4bcb27 | |||
| 6da9ece0d8 | |||
| dc4438dcf9 | |||
| e250e2a130 | |||
| dad51fdf80 | |||
| d60b0301c5 | |||
| db3e09650a | |||
| bcb9911cd0 |
@@ -1,5 +1,21 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## **2409.1**
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- Fix an issue with removal of Defender/OneDrive/Edge after FFU is complete
|
||||||
|
- Migrate Winget downloads to use [Export-WingetPackage cmdlet](https://github.com/microsoft/winget-cli/blob/master/doc/specs/%23658%20-%20WinGet%20Download.md#winget-powershell-cmdlet) as per issue #50
|
||||||
|
- Add support for preview updates https://github.com/rbalsleyMSFT/FFU/pull/51 - thanks to @HedgeComp
|
||||||
|
- Refactor validation of Unattend/prefixes, PPKG, Autopilot to check for these files early in the process, similar to how we check for drivers
|
||||||
|
- Add better logging when unable to find HDD when applying FFU. Will inform to add WinPE drivers to Deployment Media if HDD not found.
|
||||||
|
- Remove ValidateScript on InstallDrivers and break it out in a validation block so -Make and -Model can be specified anywhere in the command line
|
||||||
|
- Add validation for VMHostIPAddress and VMSwtichName and inform the user if these don't match. Should prevent issues where the FFU isn't getting created.
|
||||||
|
- Removed installation of the Windows Security Platform Update as it has been removed from the MU Catalog. See issue #58
|
||||||
|
- Thanks to w0 for PR #54 to change the validation set for WindowsSKU
|
||||||
|
- Thanks to @zehadialam for PR #60 to fix an issue with Windows boot loader for certain devices where Windows Boot Manager is not the first boot entry after the FFU is applied.
|
||||||
|
- Thanks to @HedgeComp for PR #64 and PR #65
|
||||||
|
|
||||||
## **2408.1**
|
## **2408.1**
|
||||||
|
|
||||||
### External Drive Support
|
### External Drive Support
|
||||||
|
|||||||
+485
-216
@@ -106,6 +106,9 @@ When set to $true, will remove the FFU file from the $FFUDevelopmentPath\FFU fol
|
|||||||
.PARAMETER UpdateLatestCU
|
.PARAMETER UpdateLatestCU
|
||||||
When set to $true, will download and install the latest cumulative update for Windows 10/11. Default is $false.
|
When set to $true, will download and install the latest cumulative update for Windows 10/11. Default is $false.
|
||||||
|
|
||||||
|
.PARAMETER UpdatePreviewCU
|
||||||
|
When set to $true, will download and install the latest Preview cumulative update for Windows 10/11. Default is $false.
|
||||||
|
|
||||||
.PARAMETER UpdateLatestNet
|
.PARAMETER UpdateLatestNet
|
||||||
When set to $true, will download and install the latest .NET Framework for Windows 10/11. Default is $false.
|
When set to $true, will download and install the latest .NET Framework for Windows 10/11. Default is $false.
|
||||||
|
|
||||||
@@ -198,11 +201,7 @@ param(
|
|||||||
[Parameter(Mandatory = $false, Position = 0)]
|
[Parameter(Mandatory = $false, Position = 0)]
|
||||||
[ValidateScript({ Test-Path $_ })]
|
[ValidateScript({ Test-Path $_ })]
|
||||||
[string]$ISOPath,
|
[string]$ISOPath,
|
||||||
[ValidateScript({
|
[ValidateSet('Home', 'Home N', 'Home Single Language', 'Education', 'Education N', 'Pro', 'Pro N', 'Pro Education', 'Pro Education N', 'Pro for Workstations', 'Pro N for Workstations', 'Enterprise', 'Enterprise N')]
|
||||||
$allowedSKUs = @('Home', 'Home N', 'Home Single Language', 'Education', 'Education N', 'Pro', 'Pro N', 'Pro Education', 'Pro Education N', 'Pro for Workstations', 'Pro N for Workstations', 'Enterprise', 'Enterprise N')
|
|
||||||
if ($allowedSKUs -contains $_) { $true } else { throw "Invalid WindowsSKU value. Allowed values: $($allowedSKUs -join ', ')" }
|
|
||||||
return $true
|
|
||||||
})]
|
|
||||||
[string]$WindowsSKU = 'Pro',
|
[string]$WindowsSKU = 'Pro',
|
||||||
[ValidateScript({ Test-Path $_ })]
|
[ValidateScript({ Test-Path $_ })]
|
||||||
[string]$FFUDevelopmentPath = $PSScriptRoot,
|
[string]$FFUDevelopmentPath = $PSScriptRoot,
|
||||||
@@ -211,16 +210,16 @@ param(
|
|||||||
[ValidateSet('Microsoft', 'Dell', 'HP', 'Lenovo')]
|
[ValidateSet('Microsoft', 'Dell', 'HP', 'Lenovo')]
|
||||||
[string]$Make,
|
[string]$Make,
|
||||||
[string]$Model,
|
[string]$Model,
|
||||||
[Parameter(Mandatory = $false)]
|
# [Parameter(Mandatory = $false)]
|
||||||
[ValidateScript({
|
# [ValidateScript({
|
||||||
if ($Make) {
|
# if ($Make) {
|
||||||
return $true
|
# return $true
|
||||||
}
|
# }
|
||||||
if ($_ -and (!(Test-Path -Path '.\Drivers') -or ((Get-ChildItem -Path '.\Drivers' -Recurse | Measure-Object -Property Length -Sum).Sum -lt 1MB))) {
|
# if ($_ -and (!(Test-Path -Path '.\Drivers') -or ((Get-ChildItem -Path '.\Drivers' -Recurse | Measure-Object -Property Length -Sum).Sum -lt 1MB))) {
|
||||||
throw 'InstallDrivers is set to $true, but either the Drivers folder is missing or empty'
|
# throw 'InstallDrivers is set to $true, but either the Drivers folder is missing or empty'
|
||||||
}
|
# }
|
||||||
return $true
|
# return $true
|
||||||
})]
|
# })]
|
||||||
[bool]$InstallDrivers,
|
[bool]$InstallDrivers,
|
||||||
[uint64]$Memory = 4GB,
|
[uint64]$Memory = 4GB,
|
||||||
[uint64]$Disksize = 30GB,
|
[uint64]$Disksize = 30GB,
|
||||||
@@ -304,6 +303,7 @@ param(
|
|||||||
[bool]$CopyPEDrivers,
|
[bool]$CopyPEDrivers,
|
||||||
[bool]$RemoveFFU,
|
[bool]$RemoveFFU,
|
||||||
[bool]$UpdateLatestCU,
|
[bool]$UpdateLatestCU,
|
||||||
|
[bool]$UpdatePreviewCU,
|
||||||
[bool]$UpdateLatestNet,
|
[bool]$UpdateLatestNet,
|
||||||
[bool]$UpdateLatestDefender,
|
[bool]$UpdateLatestDefender,
|
||||||
[bool]$UpdateEdge,
|
[bool]$UpdateEdge,
|
||||||
@@ -336,7 +336,7 @@ param(
|
|||||||
[bool]$AllowExternalHardDiskMedia,
|
[bool]$AllowExternalHardDiskMedia,
|
||||||
[bool]$PromptExternalHardDiskMedia = $true
|
[bool]$PromptExternalHardDiskMedia = $true
|
||||||
)
|
)
|
||||||
$version = '2408.1'
|
$version = '2409.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
|
||||||
@@ -375,6 +375,11 @@ if (-not $DefenderPath) { $DefenderPath = "$AppsPath\Defender" }
|
|||||||
if (-not $OneDrivePath) { $OneDrivePath = "$AppsPath\OneDrive" }
|
if (-not $OneDrivePath) { $OneDrivePath = "$AppsPath\OneDrive" }
|
||||||
if (-not $EdgePath) { $EdgePath = "$AppsPath\Edge" }
|
if (-not $EdgePath) { $EdgePath = "$AppsPath\Edge" }
|
||||||
if (-not $DriversFolder) { $DriversFolder = "$FFUDevelopmentPath\Drivers" }
|
if (-not $DriversFolder) { $DriversFolder = "$FFUDevelopmentPath\Drivers" }
|
||||||
|
if (-not $PPKGFolder) { $PPKGFolder = "$FFUDevelopmentPath\PPKG" }
|
||||||
|
if (-not $UnattendFolder) { $UnattendFolder = "$FFUDevelopmentPath\Unattend" }
|
||||||
|
if (-not $AutopilotFolder) { $AutopilotFolder = "$FFUDevelopmentPath\Autopilot" }
|
||||||
|
if (-not $PEDriversFolder) { $PEDriversFolder = "$FFUDevelopmentPath\PEDrivers" }
|
||||||
|
|
||||||
|
|
||||||
#FUNCTIONS
|
#FUNCTIONS
|
||||||
function WriteLog($LogText) {
|
function WriteLog($LogText) {
|
||||||
@@ -1683,33 +1688,82 @@ function Install-WinGet {
|
|||||||
WriteLog "Downloading $($package.Name) from $($package.Url) to $destination"
|
WriteLog "Downloading $($package.Name) from $($package.Url) to $destination"
|
||||||
Start-BitsTransferWithRetry -Source $package.Url -Destination $destination
|
Start-BitsTransferWithRetry -Source $package.Url -Destination $destination
|
||||||
WriteLog "Installing $($package.Name)..."
|
WriteLog "Installing $($package.Name)..."
|
||||||
|
# Don't show progress bar for Add-AppxPackage - there's a weird issue where the progress stays on the screen after the apps are installed
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
Add-AppxPackage -Path $destination -ErrorAction SilentlyContinue
|
Add-AppxPackage -Path $destination -ErrorAction SilentlyContinue
|
||||||
|
# Set progress preference back to default
|
||||||
|
$ProgressPreference = 'Continue'
|
||||||
WriteLog "Removing $($package.Name)..."
|
WriteLog "Removing $($package.Name)..."
|
||||||
Remove-Item -Path $destination -Force -ErrorAction SilentlyContinue
|
Remove-Item -Path $destination -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
WriteLog "WinGet installation complete."
|
WriteLog "WinGet installation complete."
|
||||||
}
|
}
|
||||||
|
# function Confirm-WinGetInstallation {
|
||||||
|
# WriteLog 'Checking if WinGet is installed...'
|
||||||
|
# $wingetPath = "$env:LOCALAPPDATA\Microsoft\WindowsApps\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\winget.exe"
|
||||||
|
# $minVersion = [version]"1.8.1911"
|
||||||
|
# if (-not (Test-Path -Path $wingetPath -PathType Leaf)) {
|
||||||
|
# WriteLog "WinGet is not installed. Downloading WinGet..."
|
||||||
|
# Install-WinGet -Architecture $WindowsArch
|
||||||
|
# }
|
||||||
|
# if (-not (Get-Command -Name winget -ErrorAction SilentlyContinue)) {
|
||||||
|
# WriteLog "WinGet not found. Downloading WinGet..."
|
||||||
|
# Install-WinGet -Architecture $WindowsArch
|
||||||
|
# }
|
||||||
|
# $wingetVersion = & winget.exe --version
|
||||||
|
# WriteLog "Installed version of WinGet: $wingetVersion"
|
||||||
|
# if ($wingetVersion -match 'v?(\d+\.\d+\.\d+)' -and [version]$matches[1] -lt $minVersion) {
|
||||||
|
# WriteLog "The installed version of WinGet $($matches[1]) does not support downloading MSStore apps. Downloading the latest version of WinGet..."
|
||||||
|
# Install-WinGet -Architecture $WindowsArch
|
||||||
|
# }
|
||||||
|
|
||||||
|
# # Check if Winget PowerShell module version 1.8.1911 or later is installed
|
||||||
|
# $wingetModule = Get-InstalledModule -Name Microsoft.Winget.Client -ErrorAction SilentlyContinue
|
||||||
|
# if ($wingetModule.Version -lt $minVersion -or -not $wingetModule) {
|
||||||
|
# WriteLog 'Microsoft.Winget.Client module is not installed or is an older version. Installing the latest version...'
|
||||||
|
# #Check if PSGallery is a trusted repository
|
||||||
|
# $PSGalleryTrust = (Get-PSRepository -Name 'PSGallery').InstallationPolicy
|
||||||
|
# if($PSGalleryTrust -eq 'Untrusted'){
|
||||||
|
# WriteLog 'Temporarily setting PSGallery as a trusted repository...'
|
||||||
|
# Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted
|
||||||
|
# }
|
||||||
|
# Install-Module -Name Microsoft.Winget.Client -Force -Repository 'PSGallery'
|
||||||
|
# if($PSGalleryTrust -eq 'Untrusted'){
|
||||||
|
# WriteLog 'Setting PSGallery back to untrusted repository...'
|
||||||
|
# Set-PSRepository -Name 'PSGallery' -InstallationPolicy Untrusted
|
||||||
|
# WriteLog 'Done'
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
function Confirm-WinGetInstallation {
|
function Confirm-WinGetInstallation {
|
||||||
WriteLog 'Checking if WinGet is installed...'
|
WriteLog 'Checking if WinGet is installed...'
|
||||||
$wingetPath = "$env:LOCALAPPDATA\Microsoft\WindowsApps\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\winget.exe"
|
|
||||||
$minVersion = [version]"1.8.1911"
|
$minVersion = [version]"1.8.1911"
|
||||||
if (-not (Test-Path -Path $wingetPath -PathType Leaf)) {
|
# Check if Winget PowerShell module version 1.8.1911 or later is installed
|
||||||
WriteLog "WinGet is not installed. Downloading WinGet..."
|
$wingetModule = Get-InstalledModule -Name Microsoft.Winget.Client -ErrorAction SilentlyContinue
|
||||||
Install-WinGet -Architecture $WindowsArch
|
if ($wingetModule.Version -lt $minVersion -or -not $wingetModule) {
|
||||||
return
|
WriteLog 'Microsoft.Winget.Client module is not installed or is an older version. Installing the latest version...'
|
||||||
|
#Check if PSGallery is a trusted repository
|
||||||
|
$PSGalleryTrust = (Get-PSRepository -Name 'PSGallery').InstallationPolicy
|
||||||
|
if($PSGalleryTrust -eq 'Untrusted'){
|
||||||
|
WriteLog 'Temporarily setting PSGallery as a trusted repository...'
|
||||||
|
Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted
|
||||||
|
}
|
||||||
|
Install-Module -Name Microsoft.Winget.Client -Force -Repository 'PSGallery'
|
||||||
|
if($PSGalleryTrust -eq 'Untrusted'){
|
||||||
|
WriteLog 'Setting PSGallery back to untrusted repository...'
|
||||||
|
Set-PSRepository -Name 'PSGallery' -InstallationPolicy Untrusted
|
||||||
|
WriteLog 'Done'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (-not (Get-Command -Name winget -ErrorAction SilentlyContinue)) {
|
$wingetVersion = Get-WinGetVersion
|
||||||
WriteLog "WinGet not found. Downloading WinGet..."
|
if (-not $wingetVersion) {
|
||||||
|
WriteLog "WinGet is not installed. Installing WinGet..."
|
||||||
Install-WinGet -Architecture $WindowsArch
|
Install-WinGet -Architecture $WindowsArch
|
||||||
return
|
|
||||||
}
|
}
|
||||||
$wingetVersion = & winget.exe --version
|
if (($wingetVersion -match 'v?(\d+\.\d+\.\d+)' -and [version]$matches[1] -lt $minVersion)) {
|
||||||
WriteLog "Installed version of WinGet: $wingetVersion"
|
WriteLog "The installed version of WinGet $($matches[1]) does not support downloading MSStore apps. Installing the latest version of WinGet..."
|
||||||
if ($wingetVersion -match 'v?(\d+\.\d+\.\d+)' -and [version]$matches[1] -lt $minVersion) {
|
|
||||||
WriteLog "The installed version of WinGet $($matches[1]) does not support downloading MSStore apps. Downloading the latest version of WinGet..."
|
|
||||||
Install-WinGet -Architecture $WindowsArch
|
Install-WinGet -Architecture $WindowsArch
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1757,43 +1811,106 @@ function Set-InstallStoreAppsFlag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# function Get-WinGetApp {
|
||||||
|
# param (
|
||||||
|
# [string]$WinGetAppName,
|
||||||
|
# [string]$WinGetAppId
|
||||||
|
# )
|
||||||
|
# $wingetSearchResult = & winget.exe search --id "$WinGetAppId" --exact --accept-source-agreements --source winget
|
||||||
|
# if ($wingetSearchResult -contains "No package found matching input criteria.") {
|
||||||
|
# if ($VerbosePreference -ne 'Continue'){
|
||||||
|
# Write-Error "$WinGetAppName not found in WinGet repository. Skipping download."
|
||||||
|
# Write-Error "Check the AppList.json file and make sure the AppID is correct."
|
||||||
|
# Write-Error "If OS language is not English, winget download may fail. We hope to have this addressed in a future release."
|
||||||
|
# }
|
||||||
|
# WriteLog "$WinGetAppName not found in WinGet repository. Exiting."
|
||||||
|
# WriteLog "Check the AppList.json file and make sure the AppID is correct."
|
||||||
|
# WriteLog "If OS language is not English, winget download may fail. We hope to have this addressed in a future release."
|
||||||
|
# Exit 1
|
||||||
|
# }
|
||||||
|
# $appFolderPath = Join-Path -Path "$AppsPath\Win32" -ChildPath $WinGetAppName
|
||||||
|
# WriteLog "Creating $appFolderPath"
|
||||||
|
# New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null
|
||||||
|
# WriteLog "Downloading $WinGetAppName to $appFolderPath"
|
||||||
|
# $downloadParams = @(
|
||||||
|
# "download",
|
||||||
|
# "--id", "$WinGetAppId",
|
||||||
|
# "--exact",
|
||||||
|
# "--download-directory", "$appFolderPath",
|
||||||
|
# "--accept-package-agreements",
|
||||||
|
# "--accept-source-agreements",
|
||||||
|
# "--source", "winget",
|
||||||
|
# "--scope", "machine",
|
||||||
|
# "--architecture", "$WindowsArch"
|
||||||
|
# )
|
||||||
|
# WriteLog "winget command: winget.exe $downloadParams"
|
||||||
|
# $wingetDownloadResult = & winget.exe @downloadParams | Out-String
|
||||||
|
# if ($wingetDownloadResult -match "No applicable installer found") {
|
||||||
|
# WriteLog "No installer found for $WindowsArch architecture. Attempting to download without specifying architecture..."
|
||||||
|
# $downloadParams = $downloadParams | Where-Object { $_ -notmatch "--architecture" -and $_ -notmatch "$WindowsArch" }
|
||||||
|
# $wingetDownloadResult = & winget.exe @downloadParams | Out-String
|
||||||
|
# if ($wingetDownloadResult -match "Installer downloaded") {
|
||||||
|
# WriteLog "Downloaded $WinGetAppName without specifying architecture."
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# if ($wingetDownloadResult -notmatch "Installer downloaded") {
|
||||||
|
# WriteLog "No installer found for $WinGetAppName. Skipping download."
|
||||||
|
# Remove-Item -Path $appFolderPath -Recurse -Force
|
||||||
|
# }
|
||||||
|
# WriteLog "$WinGetAppName downloaded to $appFolderPath"
|
||||||
|
# $installerPath = Get-ChildItem -Path "$appFolderPath\*" -Exclude "*.yaml", "*.xml" -File -ErrorAction Stop
|
||||||
|
# $uwpExtensions = @(".appx", ".appxbundle", ".msix", ".msixbundle")
|
||||||
|
# if ($uwpExtensions -contains $installerPath.Extension) {
|
||||||
|
# $NewAppPath = "$AppsPath\MSStore\$WinGetAppName"
|
||||||
|
# Writelog "$WinGetAppName is a UWP app. Moving to $NewAppPath"
|
||||||
|
# WriteLog "Creating $NewAppPath"
|
||||||
|
# New-Item -Path "$AppsPath\MSStore\$WinGetAppName" -ItemType Directory -Force | Out-Null
|
||||||
|
# WriteLog "Moving $WinGetAppName to $NewAppPath"
|
||||||
|
# Move-Item -Path "$appFolderPath\*" -Destination "$AppsPath\MSStore\$WinGetAppName" -Force
|
||||||
|
# WriteLog "Removing $appFolderPath"
|
||||||
|
# Remove-Item -Path $appFolderPath -Force
|
||||||
|
# WriteLog "$WinGetAppName moved to $NewAppPath"
|
||||||
|
# Set-InstallStoreAppsFlag
|
||||||
|
# }
|
||||||
|
# else {
|
||||||
|
# Add-Win32SilentInstallCommand -AppFolder $WinGetAppName -AppFolderPath $appFolderPath
|
||||||
|
# }
|
||||||
|
# }
|
||||||
function Get-WinGetApp {
|
function Get-WinGetApp {
|
||||||
param (
|
param (
|
||||||
[string]$WinGetAppName,
|
[string]$WinGetAppName,
|
||||||
[string]$WinGetAppId
|
[string]$WinGetAppId
|
||||||
)
|
)
|
||||||
$wingetSearchResult = & winget.exe search --id "$WinGetAppId" --exact --accept-source-agreements --source winget
|
$Source = 'winget'
|
||||||
if ($wingetSearchResult -contains "No package found matching input criteria.") {
|
$wingetSearchResult = Find-WinGetPackage -id $WinGetAppId -MatchOption Equals -Source $Source
|
||||||
WriteLog "$WinGetAppName not found in WinGet repository. Skipping download."
|
if (-not $wingetSearchResult) {
|
||||||
|
if ($VerbosePreference -ne 'Continue'){
|
||||||
|
Write-Error "$WinGetAppName not found in WinGet repository. Exiting."
|
||||||
|
Write-Error "Check the AppList.json file and make sure the AppID is correct."
|
||||||
|
}
|
||||||
|
WriteLog "$WinGetAppName not found in WinGet repository. Exiting."
|
||||||
|
WriteLog "Check the AppList.json file and make sure the AppID is correct."
|
||||||
|
Exit 1
|
||||||
}
|
}
|
||||||
$appFolderPath = Join-Path -Path "$AppsPath\Win32" -ChildPath $WinGetAppName
|
$appFolderPath = Join-Path -Path "$AppsPath\Win32" -ChildPath $WinGetAppName
|
||||||
WriteLog "Creating $appFolderPath"
|
WriteLog "Creating $appFolderPath"
|
||||||
New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null
|
New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null
|
||||||
WriteLog "Downloading $WinGetAppName to $appFolderPath"
|
WriteLog "Downloading $WinGetAppName to $appFolderPath"
|
||||||
$downloadParams = @(
|
|
||||||
"download",
|
WriteLog "WinGet command: Export-WinGetPackage -id $WinGetAppId -DownloadDirectory $appFolderPath -Architecture $WindowsArch -Source $Source"
|
||||||
"--id", "$WinGetAppId",
|
$wingetDownloadResult = Export-WinGetPackage -id $WinGetAppId -DownloadDirectory $appFolderPath -Architecture $WindowsArch -Source $Source
|
||||||
"--exact",
|
if ($wingetDownloadResult.status -eq 'NoApplicableInstallers') {
|
||||||
"--download-directory", "$appFolderPath",
|
# If no applicable installer is found, try downloading without specifying architecture
|
||||||
"--accept-package-agreements",
|
|
||||||
"--accept-source-agreements",
|
|
||||||
"--source", "winget",
|
|
||||||
"--scope", "machine",
|
|
||||||
"--architecture", "$WindowsArch"
|
|
||||||
)
|
|
||||||
WriteLog "winget command: winget.exe $downloadParams"
|
|
||||||
$wingetDownloadResult = & winget.exe @downloadParams | Out-String
|
|
||||||
if ($wingetDownloadResult -match "No applicable installer found") {
|
|
||||||
WriteLog "No installer found for $WindowsArch architecture. Attempting to download without specifying architecture..."
|
WriteLog "No installer found for $WindowsArch architecture. Attempting to download without specifying architecture..."
|
||||||
$downloadParams = $downloadParams | Where-Object { $_ -notmatch "--architecture" -and $_ -notmatch "$WindowsArch" }
|
$wingetDownloadResult = Export-WinGetPackage -id $WinGetAppId -DownloadDirectory $appFolderPath -Source $Source
|
||||||
$wingetDownloadResult = & winget.exe @downloadParams | Out-String
|
if ($wingetDownloadResult.status -eq 'Ok') {
|
||||||
if ($wingetDownloadResult -match "Installer downloaded") {
|
|
||||||
WriteLog "Downloaded $WinGetAppName without specifying architecture."
|
WriteLog "Downloaded $WinGetAppName without specifying architecture."
|
||||||
}
|
}
|
||||||
}
|
else{
|
||||||
if ($wingetDownloadResult -notmatch "Installer downloaded") {
|
WriteLog "No installer found for $WinGetAppName. Exiting."
|
||||||
WriteLog "No installer found for $WinGetAppName. Skipping download."
|
Remove-Item -Path $appFolderPath -Recurse -Force
|
||||||
Remove-Item -Path $appFolderPath -Recurse -Force
|
Exit 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WriteLog "$WinGetAppName downloaded to $appFolderPath"
|
WriteLog "$WinGetAppName downloaded to $appFolderPath"
|
||||||
$installerPath = Get-ChildItem -Path "$appFolderPath\*" -Exclude "*.yaml", "*.xml" -File -ErrorAction Stop
|
$installerPath = Get-ChildItem -Path "$appFolderPath\*" -Exclude "*.yaml", "*.xml" -File -ErrorAction Stop
|
||||||
@@ -1815,15 +1932,105 @@ function Get-WinGetApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# function Get-StoreApp {
|
||||||
|
# param (
|
||||||
|
# [string]$StoreAppName,
|
||||||
|
# [string]$StoreAppId
|
||||||
|
# )
|
||||||
|
# $wingetSearchResult = & winget.exe search "$StoreAppId" --accept-source-agreements --source msstore
|
||||||
|
# if ($wingetSearchResult -contains "No package found matching input criteria.") {
|
||||||
|
# WriteLog "$StoreAppName not found in WinGet repository. Skipping download."
|
||||||
|
# return
|
||||||
|
# }
|
||||||
|
# WriteLog "Checking if $StoreAppName is a win32 app..."
|
||||||
|
# $appIsWin32 = $StoreAppId.StartsWith("XP")
|
||||||
|
# if ($appIsWin32) {
|
||||||
|
# WriteLog "$StoreAppName is a win32 app. Adding to $AppsPath\win32 folder"
|
||||||
|
# $appFolderPath = Join-Path -Path "$AppsPath\win32" -ChildPath $StoreAppName
|
||||||
|
# }
|
||||||
|
# else {
|
||||||
|
# WriteLog "$StoreAppName is not a win32 app."
|
||||||
|
# $appFolderPath = Join-Path -Path "$AppsPath\MSStore" -ChildPath $StoreAppName
|
||||||
|
# }
|
||||||
|
# New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null
|
||||||
|
# WriteLog "Downloading $StoreAppName for $WindowsArch architecture..."
|
||||||
|
# $downloadParams = @(
|
||||||
|
# "download", "$StoreAppId",
|
||||||
|
# "--download-directory", "$appFolderPath",
|
||||||
|
# "--accept-package-agreements",
|
||||||
|
# "--accept-source-agreements",
|
||||||
|
# "--source", "msstore",
|
||||||
|
# "--scope", "machine",
|
||||||
|
# "--architecture", "$WindowsArch"
|
||||||
|
# )
|
||||||
|
# WriteLog 'MSStore app downloads require authentication with an Entra ID account. You may be prompted twice for credentials, once for the app and another for the license file.'
|
||||||
|
# WriteLog "Attempting to download $StoreAppName and dependencies for $WindowsArch architecture..."
|
||||||
|
# $wingetDownloadResult = & winget.exe @downloadParams | Out-String
|
||||||
|
# # For some apps, specifying the architecture leads to no results found for the app. In those cases, the command will be run without the architecture parameter.
|
||||||
|
# if ($wingetDownloadResult -match "No applicable installer found") {
|
||||||
|
# WriteLog "No installer found for $WindowsArch architecture. Attempting to download without specifying architecture..."
|
||||||
|
# $downloadParams = $downloadParams | Where-Object { $_ -notmatch "--architecture" -and $_ -notmatch "$WindowsArch" }
|
||||||
|
# $wingetDownloadResult = & winget.exe @downloadParams | Out-String
|
||||||
|
# if ($wingetDownloadResult -match "Microsoft Store package download completed") {
|
||||||
|
# WriteLog "Downloaded $StoreAppName without specifying architecture."
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# if ($wingetDownloadResult -notmatch "Installer downloaded|Microsoft Store package download completed") {
|
||||||
|
# WriteLog "Download not supported for $StoreAppName. Skipping download."
|
||||||
|
# Remove-Item -Path $appFolderPath -Recurse -Force
|
||||||
|
# return
|
||||||
|
# }
|
||||||
|
# if ($appIsWin32) {
|
||||||
|
# Add-Win32SilentInstallCommand -AppFolder $StoreAppName -AppFolderPath $appFolderPath
|
||||||
|
# }
|
||||||
|
# Set-InstallStoreAppsFlag
|
||||||
|
# # If $WindowsArch -eq 'ARM64', remove all dependency files that are not ARM64
|
||||||
|
# if ($WindowsArch -eq 'ARM64') {
|
||||||
|
# WriteLog 'Windows architecture is ARM64. Removing dependencies that are not ARM64.'
|
||||||
|
# $dependencies = Get-ChildItem -Path "$appFolderPath\Dependencies" -ErrorAction SilentlyContinue
|
||||||
|
# if ($dependencies) {
|
||||||
|
# foreach ($dependency in $dependencies) {
|
||||||
|
# if ($dependency.Name -notmatch 'ARM64') {
|
||||||
|
# WriteLog "Removing dependency file $($dependency.FullName)"
|
||||||
|
# Remove-Item -Path $dependency.FullName -Recurse -Force
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# WriteLog "$StoreAppName has completed downloading. Identifying the latest version of $StoreAppName."
|
||||||
|
# $packages = Get-ChildItem -Path "$appFolderPath\*" -Exclude "Dependencies\*", "*.xml", "*.yaml" -File -ErrorAction Stop
|
||||||
|
# # WinGet downloads multiple versions of certain store apps. The latest version of the package will be determined based on the date of the file signature.
|
||||||
|
# $latestPackage = $packages | Sort-Object { (Get-AuthenticodeSignature $_.FullName).SignerCertificate.NotBefore } -Descending | Select-Object -First 1
|
||||||
|
# # Removing all packages that are not the latest version
|
||||||
|
# WriteLog "Latest version of $StoreAppName has been identified as $latestPackage. Removing old versions of $StoreAppName that may have downloaded."
|
||||||
|
# foreach ($package in $packages) {
|
||||||
|
# if ($package.FullName -ne $latestPackage) {
|
||||||
|
# try {
|
||||||
|
# WriteLog "Removing $($package.FullName)"
|
||||||
|
# Remove-Item -Path $package.FullName -Force
|
||||||
|
# }
|
||||||
|
# catch {
|
||||||
|
# WriteLog "Failed to delete: $($package.FullName) - $_"
|
||||||
|
# throw $_
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
function Get-StoreApp {
|
function Get-StoreApp {
|
||||||
param (
|
param (
|
||||||
[string]$StoreAppName,
|
[string]$StoreAppName,
|
||||||
[string]$StoreAppId
|
[string]$StoreAppId
|
||||||
)
|
)
|
||||||
$wingetSearchResult = & winget.exe search "$StoreAppId" --accept-source-agreements --source msstore
|
$Source = 'msstore'
|
||||||
if ($wingetSearchResult -contains "No package found matching input criteria.") {
|
$wingetSearchResult = Find-WinGetPackage -id $StoreAppId -MatchOption Equals -Source $Source
|
||||||
WriteLog "$StoreAppName not found in WinGet repository. Skipping download."
|
if (-not $wingetSearchResult) {
|
||||||
return
|
if ($VerbosePreference -ne 'Continue'){
|
||||||
|
Write-Error "$WinGetAppName not found in WinGet repository. Exiting."
|
||||||
|
Write-Error "Check the AppList.json file and make sure the AppID is correct."
|
||||||
|
}
|
||||||
|
WriteLog "$WinGetAppName not found in WinGet repository. Exiting."
|
||||||
|
WriteLog "Check the AppList.json file and make sure the AppID is correct."
|
||||||
|
Exit 1
|
||||||
}
|
}
|
||||||
WriteLog "Checking if $StoreAppName is a win32 app..."
|
WriteLog "Checking if $StoreAppName is a win32 app..."
|
||||||
$appIsWin32 = $StoreAppId.StartsWith("XP")
|
$appIsWin32 = $StoreAppId.StartsWith("XP")
|
||||||
@@ -1837,31 +2044,22 @@ function Get-StoreApp {
|
|||||||
}
|
}
|
||||||
New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null
|
New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null
|
||||||
WriteLog "Downloading $StoreAppName for $WindowsArch architecture..."
|
WriteLog "Downloading $StoreAppName for $WindowsArch architecture..."
|
||||||
$downloadParams = @(
|
|
||||||
"download", "$StoreAppId",
|
|
||||||
"--download-directory", "$appFolderPath",
|
|
||||||
"--accept-package-agreements",
|
|
||||||
"--accept-source-agreements",
|
|
||||||
"--source", "msstore",
|
|
||||||
"--scope", "machine",
|
|
||||||
"--architecture", "$WindowsArch"
|
|
||||||
)
|
|
||||||
WriteLog 'MSStore app downloads require authentication with an Entra ID account. You may be prompted twice for credentials, once for the app and another for the license file.'
|
WriteLog 'MSStore app downloads require authentication with an Entra ID account. You may be prompted twice for credentials, once for the app and another for the license file.'
|
||||||
WriteLog "Attempting to download $StoreAppName and dependencies for $WindowsArch architecture..."
|
WriteLog "Attempting to download $StoreAppName and dependencies for $WindowsArch architecture..."
|
||||||
$wingetDownloadResult = & winget.exe @downloadParams | Out-String
|
WriteLog "WinGet command: Export-WinGetPackage -id $StoreAppId -DownloadDirectory $appFolderPath -Architecture $WindowsArch -Source $Source"
|
||||||
# For some apps, specifying the architecture leads to no results found for the app. In those cases, the command will be run without the architecture parameter.
|
$wingetDownloadResult = Export-WinGetPackage -id $StoreAppId -DownloadDirectory $appFolderPath -Architecture $WindowsArch -Source $Source
|
||||||
if ($wingetDownloadResult -match "No applicable installer found") {
|
if ($wingetDownloadResult.status -eq 'NoApplicableInstallerFound') {
|
||||||
|
# If no applicable installer is found, try downloading without specifying architecture
|
||||||
WriteLog "No installer found for $WindowsArch architecture. Attempting to download without specifying architecture..."
|
WriteLog "No installer found for $WindowsArch architecture. Attempting to download without specifying architecture..."
|
||||||
$downloadParams = $downloadParams | Where-Object { $_ -notmatch "--architecture" -and $_ -notmatch "$WindowsArch" }
|
$wingetDownloadResult = Export-WinGetPackage -id $StoreAppId -DownloadDirectory $appFolderPath -Source $Source
|
||||||
$wingetDownloadResult = & winget.exe @downloadParams | Out-String
|
if ($wingetDownloadResult.status -eq 'Ok') {
|
||||||
if ($wingetDownloadResult -match "Microsoft Store package download completed") {
|
WriteLog "Downloaded $WinGetAppName without specifying architecture."
|
||||||
WriteLog "Downloaded $StoreAppName without specifying architecture."
|
}
|
||||||
|
else{
|
||||||
|
WriteLog "No installer found for $WinGetAppName. Exiting"
|
||||||
|
Remove-Item -Path $appFolderPath -Recurse -Force
|
||||||
|
Exit 1
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if ($wingetDownloadResult -notmatch "Installer downloaded|Microsoft Store package download completed") {
|
|
||||||
WriteLog "Download not supported for $StoreAppName. Skipping download."
|
|
||||||
Remove-Item -Path $appFolderPath -Recurse -Force
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if ($appIsWin32) {
|
if ($appIsWin32) {
|
||||||
Add-Win32SilentInstallCommand -AppFolder $StoreAppName -AppFolderPath $appFolderPath
|
Add-Win32SilentInstallCommand -AppFolder $StoreAppName -AppFolderPath $appFolderPath
|
||||||
@@ -2050,68 +2248,6 @@ function Save-KB {
|
|||||||
if ($WindowsArch -eq 'x64') {
|
if ($WindowsArch -eq 'x64') {
|
||||||
[array]$WindowsArch = @("x64", "amd64")
|
[array]$WindowsArch = @("x64", "amd64")
|
||||||
}
|
}
|
||||||
#Keep for now, will remove in future
|
|
||||||
# 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-BitsTransferWithRetry -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
|
|
||||||
# # }
|
|
||||||
# elseif (!($link -match 'x64' -or $link -match 'amd64' -or $link -match 'x86' -or $link -match 'arm64')) {
|
|
||||||
# WriteLog "No architecture found in $link, assume this is for all architectures"
|
|
||||||
# #FIX: 3/22/2024 - the SecurityHealthSetup fix was updated and now includes two files (one is x64 and the other is arm64)
|
|
||||||
# #Unfortunately there is no easy way to determine the architecture from the file name
|
|
||||||
# #There is a support doc that include links to download, but it's out of date (n-1)
|
|
||||||
# #https://support.microsoft.com/en-us/topic/windows-security-update-a6ac7d2e-b1bf-44c0-a028-41720a242da3
|
|
||||||
# #These files don't change that often, so will check the link above to see when it updates and may use that
|
|
||||||
# #For now this is hard-coded for these specific file names
|
|
||||||
# if ($link -match 'security'){
|
|
||||||
# #Make sure we're getting the correct architecture for the Security Health Setup update
|
|
||||||
# WriteLog "Link: $link matches security"
|
|
||||||
# if ($WindowsArch -eq 'x64'){
|
|
||||||
# if ($link -match 'securityhealthsetup_e1'){
|
|
||||||
# Writelog "Downloading $Link for $WindowsArch to $Path"
|
|
||||||
# Start-BitsTransferWithRetry -Source $link -Destination $Path
|
|
||||||
# $fileName = ($link -split '/')[-1]
|
|
||||||
# Writelog "Returning $fileName"
|
|
||||||
# break
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# elseif ($WindowsArch -eq 'arm64'){
|
|
||||||
# if ($link -match 'securityhealthsetup_25'){
|
|
||||||
# Writelog "Downloading $Link for $WindowsArch to $Path"
|
|
||||||
# Start-BitsTransferWithRetry -Source $link -Destination $Path
|
|
||||||
# $fileName = ($link -split '/')[-1]
|
|
||||||
# Writelog "Returning $fileName"
|
|
||||||
# break
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# continue
|
|
||||||
# }
|
|
||||||
# Start-BitsTransferWithRetry -Source $link -Destination $Path
|
|
||||||
# $fileName = ($link -split '/')[-1]
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# else {
|
|
||||||
# if ($link -match $WindowsArch) {
|
|
||||||
# Start-BitsTransferWithRetry -Source $link -Destination $Path
|
|
||||||
# $fileName = ($link -split '/')[-1]
|
|
||||||
# break
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
foreach ($kb in $name) {
|
foreach ($kb in $name) {
|
||||||
$links = Get-KBLink -Name $kb
|
$links = Get-KBLink -Name $kb
|
||||||
foreach ($link in $links) {
|
foreach ($link in $links) {
|
||||||
@@ -3228,9 +3364,14 @@ Function New-DeploymentUSB {
|
|||||||
if ($WindowsArch -eq 'x64') {
|
if ($WindowsArch -eq 'x64') {
|
||||||
Copy-Item -Path "$FFUDevelopmentPath\unattend\unattend_x64.xml" -Destination "$DeployUnattendPath\Unattend.xml" -Force | Out-Null
|
Copy-Item -Path "$FFUDevelopmentPath\unattend\unattend_x64.xml" -Destination "$DeployUnattendPath\Unattend.xml" -Force | Out-Null
|
||||||
}
|
}
|
||||||
else {
|
if ($WindowsArch -eq 'arm64') {
|
||||||
Copy-Item -Path "$FFUDevelopmentPath\unattend\unattend_arm64.xml" -Destination "$DeployUnattendPath\Unattend.xml" -Force | Out-Null
|
Copy-Item -Path "$FFUDevelopmentPath\unattend\unattend_arm64.xml" -Destination "$DeployUnattendPath\Unattend.xml" -Force | Out-Null
|
||||||
}
|
}
|
||||||
|
#Check for prefixes.txt file and copy it to the USB drive
|
||||||
|
if (Test-Path "$FFUDevelopmentPath\unattend\prefixes.txt") {
|
||||||
|
WriteLog "Copying prefixes.txt file to $DeployUnattendPath"
|
||||||
|
Copy-Item -Path "$FFUDevelopmentPath\unattend\prefixes.txt" -Destination "$DeployUnattendPath\prefixes.txt" -Force | Out-Null
|
||||||
|
}
|
||||||
WriteLog 'Copy completed'
|
WriteLog 'Copy completed'
|
||||||
}
|
}
|
||||||
#Copy PPKG folder in the FFU folder to the USB drive. Can use copy-item as it's a small folder
|
#Copy PPKG folder in the FFU folder to the USB drive. Can use copy-item as it's a small folder
|
||||||
@@ -3322,8 +3463,13 @@ function Get-FFUEnvironment {
|
|||||||
foreach ($image in $mountedImages) {
|
foreach ($image in $mountedImages) {
|
||||||
$mountPath = $image.Path
|
$mountPath = $image.Path
|
||||||
WriteLog "Dismounting image at $mountPath"
|
WriteLog "Dismounting image at $mountPath"
|
||||||
Dismount-WindowsImage -Path $mountPath -discard | Out-null
|
try {
|
||||||
WriteLog "Successfully dismounted image at $mountPath"
|
Dismount-WindowsImage -Path $mountPath -discard | Out-null
|
||||||
|
WriteLog "Successfully dismounted image at $mountPath"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
WriteLog "Failed to dismount image at $mountPath with error: $_"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3352,6 +3498,7 @@ function Get-FFUEnvironment {
|
|||||||
Remove-FFUUserShare
|
Remove-FFUUserShare
|
||||||
WriteLog 'Removal complete'
|
WriteLog 'Removal complete'
|
||||||
}
|
}
|
||||||
|
Clear-InstallAppsandSysprep
|
||||||
#Clean up $KBPath
|
#Clean up $KBPath
|
||||||
If (Test-Path -Path $KBPath) {
|
If (Test-Path -Path $KBPath) {
|
||||||
WriteLog "Removing $KBPath"
|
WriteLog "Removing $KBPath"
|
||||||
@@ -3384,7 +3531,6 @@ function Get-FFUEnvironment {
|
|||||||
WriteLog "Cleaning up MSStore folder"
|
WriteLog "Cleaning up MSStore folder"
|
||||||
Remove-Item -Path "$AppsPath\MSStore" -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item -Path "$AppsPath\MSStore" -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
Clear-InstallAppsandSysprep
|
|
||||||
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"
|
||||||
@@ -3408,29 +3554,34 @@ function Clear-InstallAppsandSysprep {
|
|||||||
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove Defender Platform Update"
|
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove Defender Platform Update"
|
||||||
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
||||||
$CmdContent -notmatch 'd:\\Defender*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
$CmdContent -notmatch 'd:\\Defender*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
||||||
# #Remove $DefenderPath
|
#Clean up $DefenderPath
|
||||||
# WriteLog "Removing $DefenderPath"
|
If (Test-Path -Path $DefenderPath) {
|
||||||
# Remove-Item -Path $DefenderPath -Recurse -Force
|
WriteLog "Removing $DefenderPath"
|
||||||
# WriteLog "Removal complete"
|
Remove-Item -Path $DefenderPath -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
WriteLog 'Removal complete'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ($UpdateOneDrive) {
|
if ($UpdateOneDrive) {
|
||||||
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove OneDrive install"
|
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove OneDrive install"
|
||||||
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
||||||
$CmdContent -notmatch 'd:\\OneDrive*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
$CmdContent -notmatch 'd:\\OneDrive*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
||||||
# #Remove $OneDrivePath
|
#Clean up $OneDrivePath
|
||||||
# WriteLog "Removing $OneDrivePath"
|
If (Test-Path -Path $OneDrivePath) {
|
||||||
# Remove-Item -Path $OneDrivePath -Recurse -Force
|
WriteLog "Removing $OneDrivePath"
|
||||||
# WriteLog "Removal complete"
|
Remove-Item -Path $OneDrivePath -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
WriteLog 'Removal complete'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ($UpdateEdge) {
|
if ($UpdateEdge) {
|
||||||
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove Edge install"
|
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove Edge install"
|
||||||
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
||||||
$CmdContent -notmatch 'd:\\Edge*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
$CmdContent -notmatch 'd:\\Edge*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
||||||
# #Remove $EdgePath
|
#Clean up $EdgePath
|
||||||
# WriteLog "Removing $EdgePath"
|
If (Test-Path -Path $EdgePath) {
|
||||||
# Remove-Item -Path $EdgePath -Recurse -Force
|
WriteLog "Removing $EdgePath"
|
||||||
# WriteLog "Removal complete"
|
Remove-Item -Path $EdgePath -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
WriteLog 'Removal complete'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3447,6 +3598,84 @@ Write-Host "To track progress, please open the log file $Logfile or use the -Ver
|
|||||||
|
|
||||||
WriteLog 'Begin Logging'
|
WriteLog 'Begin Logging'
|
||||||
|
|
||||||
|
###PARAMETER VALIDATION
|
||||||
|
|
||||||
|
#Validate drivers folder
|
||||||
|
if ($InstallDrivers -or $CopyDrivers) {
|
||||||
|
WriteLog 'Doing driver validation'
|
||||||
|
if ($Make -and $Model){
|
||||||
|
WriteLog "Make and Model are set to $Make and $Model, will attempt to download drivers"
|
||||||
|
} else {
|
||||||
|
if (!(Test-Path -Path $DriversFolder)) {
|
||||||
|
WriteLog "-InstallDrivers or -CopyDrivers is set to `$true, but the $DriversFolder folder is missing"
|
||||||
|
throw "-InstallDrivers or -CopyDrivers is set to `$true, but the $DriversFolder folder is missing"
|
||||||
|
}
|
||||||
|
if ((Get-ChildItem -Path $DriversFolder -Recurse | Measure-Object -Property Length -Sum).Sum -lt 1MB) {
|
||||||
|
WriteLog "-InstallDrivers or -CopyDrivers is set to `$true, but the $DriversFolder folder is empty"
|
||||||
|
throw "-InstallDrivers or -CopyDrivers is set to `$true, but the $DriversFolder folder is empty"
|
||||||
|
}
|
||||||
|
WriteLog 'Driver validation complete'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#Validate PEDrivers folder
|
||||||
|
if ($CopyPEDrivers) {
|
||||||
|
WriteLog 'Doing PEDriver validation'
|
||||||
|
if (!(Test-Path -Path $PEDriversFolder)) {
|
||||||
|
WriteLog "-CopyPEDrivers is set to `$true, but the $PEDriversFolder folder is missing"
|
||||||
|
throw "-CopyPEDrivers is set to `$true, but the $PEDriversFolder folder is missing"
|
||||||
|
}
|
||||||
|
if ((Get-ChildItem -Path $PEDriversFolder -Recurse | Measure-Object -Property Length -Sum).Sum -lt 1MB) {
|
||||||
|
WriteLog "-CopyPEDrivers is set to `$true, but the $PEDriversFolder folder is empty"
|
||||||
|
throw "-CopyPEDrivers is set to `$true, but the $PEDriversFolder folder is empty"
|
||||||
|
}
|
||||||
|
WriteLog 'PEDriver validation complete'
|
||||||
|
}
|
||||||
|
|
||||||
|
#Validate PPKG folder
|
||||||
|
if ($CopyPPKG) {
|
||||||
|
WriteLog 'Doing PPKG validation'
|
||||||
|
if (!(Test-Path -Path $PPKGFolder)) {
|
||||||
|
WriteLog "-CopyPPKG is set to `$true, but the $PPKGFolder folder is missing"
|
||||||
|
throw "-CopyPPKG is set to `$true, but the $PPKGFolder folder is missing"
|
||||||
|
}
|
||||||
|
#Check for at least one .PPKG file
|
||||||
|
if (!(Get-ChildItem -Path $PPKGFolder -Filter *.ppkg)) {
|
||||||
|
WriteLog "-CopyPPKG is set to `$true, but the $PPKGFolder folder is missing a .PPKG file"
|
||||||
|
throw "-CopyPPKG is set to `$true, but the $PPKGFolder folder is missing a .PPKG file"
|
||||||
|
}
|
||||||
|
WriteLog 'PPKG validation complete'
|
||||||
|
}
|
||||||
|
|
||||||
|
#Validate Autopilot folder
|
||||||
|
if ($CopyAutopilot) {
|
||||||
|
WriteLog 'Doing Autopilot validation'
|
||||||
|
if (!(Test-Path -Path $AutopilotFolder)) {
|
||||||
|
WriteLog "-CopyAutopilot is set to `$true, but the $AutopilotFolder folder is missing"
|
||||||
|
throw "-CopyAutopilot is set to `$true, but the $AutopilotFolder folder is missing"
|
||||||
|
}
|
||||||
|
#Check for .JSON file
|
||||||
|
if (!(Get-ChildItem -Path $AutopilotFolder -Filter *.json)) {
|
||||||
|
WriteLog "-CopyAutopilot is set to `$true, but the $AutopilotFolder folder is missing a .JSON file"
|
||||||
|
throw "-CopyAutopilot is set to `$true, but the $AutopilotFolder folder is missing a .JSON file"
|
||||||
|
}
|
||||||
|
WriteLog 'Autopilot validation complete'
|
||||||
|
}
|
||||||
|
|
||||||
|
#Validate Unattend folder
|
||||||
|
if ($CopyUnattend) {
|
||||||
|
WriteLog 'Doing Unattend validation'
|
||||||
|
if (!(Test-Path -Path $UnattendFolder)) {
|
||||||
|
WriteLog "-CopyUnattend is set to `$true, but the $UnattendFolder folder is missing"
|
||||||
|
throw "-CopyUnattend is set to `$true, but the $UnattendFolder folder is missing"
|
||||||
|
}
|
||||||
|
#Check for .XML file
|
||||||
|
if (!(Get-ChildItem -Path $UnattendFolder -Filter unattend_*.xml)) {
|
||||||
|
WriteLog "-CopyUnattend is set to `$true, but the $UnattendFolder folder is missing a .XML file"
|
||||||
|
throw "-CopyUnattend is set to `$true, but the $UnattendFolder folder is missing a .XML file"
|
||||||
|
}
|
||||||
|
WriteLog 'Unattend validation complete'
|
||||||
|
}
|
||||||
|
|
||||||
#Override $InstallApps value if using ESD to build FFU. This is due to a strange issue where building the FFU
|
#Override $InstallApps value if using ESD to build FFU. This is due to a strange issue where building the FFU
|
||||||
#from vhdx doesn't work (you get an older style OOBE screen and get stuck in an OOBE reboot loop when hitting next).
|
#from vhdx doesn't work (you get an older style OOBE screen and get stuck in an OOBE reboot loop when hitting next).
|
||||||
#This behavior doesn't happen with WIM files.
|
#This behavior doesn't happen with WIM files.
|
||||||
@@ -3466,6 +3695,25 @@ if (($InstallApps -and ($VMHostIPAddress -eq ''))) {
|
|||||||
throw "If variable InstallApps is set to `$true, VMHostIPAddress must also be set to capture the FFU. Please set -VMHostIPAddress and try again."
|
throw "If variable InstallApps is set to `$true, VMHostIPAddress must also be set to capture the FFU. Please set -VMHostIPAddress and try again."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (($VMHostIPAddress) -and ($VMSwitchName)){
|
||||||
|
WriteLog "Validating -VMSwitchName $VMSwitchName and -VMHostIPAddress $VMHostIPAddress"
|
||||||
|
#Check $VMSwitchName by using Get-VMSwitch
|
||||||
|
$VMSwitch = Get-VMSwitch -Name $VMSwitchName -ErrorAction SilentlyContinue
|
||||||
|
if (-not $VMSwitch) {
|
||||||
|
throw "-VMSwitchName $VMSwitchName not found. Please check the -VMSwitchName parameter and try again."
|
||||||
|
}
|
||||||
|
#Find the IP address of $VMSwitch and check if it matches $VMHostIPAddress
|
||||||
|
$interfaceAlias = "vEthernet ($VMSwitchName)"
|
||||||
|
$VMSwitchIPAddress = (Get-NetIPAddress -InterfaceAlias $interfaceAlias -AddressFamily 'IPv4' -ErrorAction SilentlyContinue).IPAddress
|
||||||
|
if (-not $VMSwitchIPAddress) {
|
||||||
|
throw "IP address for -VMSwitchName $VMSwitchName not found. Please check the -VMSwitchName parameter and try again."
|
||||||
|
}
|
||||||
|
if ($VMSwitchIPAddress -ne $VMHostIPAddress) {
|
||||||
|
throw "IP address for -VMSwitchName $VMSwitchName is $VMSwitchIPAddress, which does not match the -VMHostIPAddress $VMHostIPAddress. Please check the -VMHostIPAddress parameter and try again."
|
||||||
|
}
|
||||||
|
WriteLog '-VMSwitchName and -VMHostIPAddress validation complete'
|
||||||
|
}
|
||||||
|
|
||||||
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."
|
||||||
}
|
}
|
||||||
@@ -3492,10 +3740,8 @@ if (($WindowsArch -eq 'ARM64') -and ($UpdateOneDrive -eq $true)) {
|
|||||||
$UpdateOneDrive = $false
|
$UpdateOneDrive = $false
|
||||||
WriteLog 'OneDrive currently fails to install on ARM64 VMs (even with the OneDrive ARM setup files). Setting UpdateOneDrive to false'
|
WriteLog 'OneDrive currently fails to install on ARM64 VMs (even with the OneDrive ARM setup files). Setting UpdateOneDrive to false'
|
||||||
}
|
}
|
||||||
# if(($WindowsArch -eq 'ARM64') -and ($UpdateLatestDefender -eq $true)){
|
|
||||||
# $UpdateLatestDefender = $false
|
###END PARAMETER VALIDATION
|
||||||
# WriteLog 'Defender ARM and x64 updates currently fail to install on ARM64 VMs. Setting UpdateLatestDefender to false'
|
|
||||||
# }
|
|
||||||
|
|
||||||
#Get script variable values
|
#Get script variable values
|
||||||
LogVariableValues
|
LogVariableValues
|
||||||
@@ -3599,17 +3845,20 @@ if ($InstallApps) {
|
|||||||
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
|
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
|
||||||
WriteLog "Update complete"
|
WriteLog "Update complete"
|
||||||
|
|
||||||
#Get Windows Security platform update
|
###### 9/4/2024 - Windows Security Platform update is no longer available from Update Catalog. Will change to using
|
||||||
$Name = "Windows Security platform definition updates"
|
###### https://support.microsoft.com/en-us/topic/windows-security-update-a6ac7d2e-b1bf-44c0-a028-41720a242da3
|
||||||
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $DefenderPath"
|
|
||||||
$KBFilePath = Save-KB -Name $Name -Path $DefenderPath
|
# #Get Windows Security platform update
|
||||||
WriteLog "Latest Security Platform Update saved to $DefenderPath\$KBFilePath"
|
# $Name = "Windows Security platform definition updates"
|
||||||
#Modify InstallAppsandSysprep.cmd to add in $KBFilePath on the line after REM Install Windows Security Platform Update
|
# WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $DefenderPath"
|
||||||
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Windows Security Platform Update"
|
# $KBFilePath = Save-KB -Name $Name -Path $DefenderPath
|
||||||
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
# WriteLog "Latest Security Platform Update saved to $DefenderPath\$KBFilePath"
|
||||||
$UpdatedcmdContent = $CmdContent -replace '^(REM Install Windows Security Platform Update)', ("REM Install Windows Security Platform Update`r`nd:\Defender\$KBFilePath")
|
# #Modify InstallAppsandSysprep.cmd to add in $KBFilePath on the line after REM Install Windows Security Platform Update
|
||||||
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
|
# WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Windows Security Platform Update"
|
||||||
WriteLog "Update complete"
|
# $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
|
#Download latest Defender Definitions
|
||||||
WriteLog "Downloading latest Defender Definitions"
|
WriteLog "Downloading latest Defender Definitions"
|
||||||
@@ -3668,7 +3917,7 @@ if ($InstallApps) {
|
|||||||
#Modify InstallAppsandSysprep.cmd to add in $OneDrivePath on the line after REM Install Defender Definitions
|
#Modify InstallAppsandSysprep.cmd to add in $OneDrivePath on the line after REM Install Defender Definitions
|
||||||
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include OneDrive client"
|
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include OneDrive client"
|
||||||
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
|
$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")
|
$UpdatedcmdContent = $CmdContent -replace '^(REM Install OneDrive Per Machine)', ("REM Install OneDrive Per Machine`r`nd:\OneDrive\OneDriveSetup.exe /allusers /silent")
|
||||||
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
|
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
|
||||||
WriteLog "Update complete"
|
WriteLog "Update complete"
|
||||||
}
|
}
|
||||||
@@ -3749,10 +3998,10 @@ try {
|
|||||||
|
|
||||||
Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1]
|
Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1]
|
||||||
|
|
||||||
#Update latest Cumulative Update
|
#Update latest Cumulative Update if both $UpdateLatestCU is $true and $UpdatePreviewCU is $false
|
||||||
#Changed to use MU Catalog instead of using Get-LatestWindowsKB
|
#Changed to use MU Catalog instead of using Get-LatestWindowsKB
|
||||||
#The Windows release info page is updated later than the MU Catalog
|
#The Windows release info page is updated later than the MU Catalog
|
||||||
if ($UpdateLatestCU) {
|
if ($UpdateLatestCU -and -not $UpdatePreviewCU) {
|
||||||
Writelog "`$UpdateLatestCU is set to true, checking for latest CU"
|
Writelog "`$UpdateLatestCU is set to true, checking for latest CU"
|
||||||
$Name = """Cumulative update for Windows $WindowsRelease Version $WindowsVersion for $WindowsArch"""
|
$Name = """Cumulative update for Windows $WindowsRelease Version $WindowsVersion for $WindowsArch"""
|
||||||
#Check if $KBPath exists, if not, create it
|
#Check if $KBPath exists, if not, create it
|
||||||
@@ -3765,6 +4014,20 @@ try {
|
|||||||
WriteLog "Latest CU saved to $KBPath\$KBFilePath"
|
WriteLog "Latest CU saved to $KBPath\$KBFilePath"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#Update Latest Preview Cumlative Update
|
||||||
|
#will take Precendence over $UpdateLastestCU if both were set to $true
|
||||||
|
if ($UpdatePreviewCU) {
|
||||||
|
Writelog "`$UpdatePreviewCU is set to true, checking for latest Preview CU"
|
||||||
|
$Name = """Cumulative update Preview for Windows $WindowsRelease Version $WindowsVersion for $WindowsArch"""
|
||||||
|
#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 Preview CU saved to $KBPath\$KBFilePath"
|
||||||
|
}
|
||||||
|
|
||||||
#Update Latest .NET Framework
|
#Update Latest .NET Framework
|
||||||
if ($UpdateLatestNet) {
|
if ($UpdateLatestNet) {
|
||||||
@@ -3779,23 +4042,23 @@ try {
|
|||||||
$KBFilePath = Save-KB -Name $Name -Path $KBPath
|
$KBFilePath = Save-KB -Name $Name -Path $KBPath
|
||||||
WriteLog "Latest .NET saved to $KBPath\$KBFilePath"
|
WriteLog "Latest .NET saved to $KBPath\$KBFilePath"
|
||||||
}
|
}
|
||||||
#Update Latest Security Platform Update
|
# #Update Latest Security Platform Update
|
||||||
if ($UpdateSecurityPlatform) {
|
# if ($UpdateSecurityPlatform) {
|
||||||
WriteLog "`$UpdateSecurityPlatform is set to true, checking for latest Security Platform Update"
|
# WriteLog "`$UpdateSecurityPlatform is set to true, checking for latest Security Platform Update"
|
||||||
$Name = "Windows Security platform definition updates"
|
# $Name = "Windows Security platform definition updates"
|
||||||
#Check if $KBPath exists, if not, create it
|
# #Check if $KBPath exists, if not, create it
|
||||||
If (-not (Test-Path -Path $KBPath)) {
|
# If (-not (Test-Path -Path $KBPath)) {
|
||||||
WriteLog "Creating $KBPath"
|
# WriteLog "Creating $KBPath"
|
||||||
New-Item -Path $KBPath -ItemType Directory -Force | Out-Null
|
# New-Item -Path $KBPath -ItemType Directory -Force | Out-Null
|
||||||
}
|
# }
|
||||||
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $KBPath"
|
# WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $KBPath"
|
||||||
$KBFilePath = Save-KB -Name $Name -Path $KBPath
|
# $KBFilePath = Save-KB -Name $Name -Path $KBPath
|
||||||
WriteLog "Latest Security Platform Update saved to $KBPath\$KBFilePath"
|
# WriteLog "Latest Security Platform Update saved to $KBPath\$KBFilePath"
|
||||||
}
|
# }
|
||||||
|
|
||||||
|
|
||||||
#Add Windows packages
|
#Add Windows packages
|
||||||
if ($UpdateLatestCU -or $UpdateLatestNet) {
|
if ($UpdateLatestCU -or $UpdateLatestNet -or $UpdatePreviewCU ) {
|
||||||
try {
|
try {
|
||||||
WriteLog "Adding KBs to $WindowsPartition"
|
WriteLog "Adding KBs to $WindowsPartition"
|
||||||
WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient'
|
WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient'
|
||||||
@@ -3999,30 +4262,30 @@ catch {
|
|||||||
throw $_
|
throw $_
|
||||||
}
|
}
|
||||||
|
|
||||||
#Clean up InstallAppsandSysprep.cmd
|
# #Clean up InstallAppsandSysprep.cmd
|
||||||
try {
|
# try {
|
||||||
WriteLog "Cleaning up $AppsPath\InstallAppsandSysprep.cmd"
|
# WriteLog "Cleaning up $AppsPath\InstallAppsandSysprep.cmd"
|
||||||
Clear-InstallAppsandSysprep
|
# Clear-InstallAppsandSysprep
|
||||||
}
|
# }
|
||||||
catch {
|
# catch {
|
||||||
Write-Host 'Cleaning up InstallAppsandSysprep.cmd failed'
|
# Write-Host 'Cleaning up InstallAppsandSysprep.cmd failed'
|
||||||
Writelog "Cleaning up InstallAppsandSysprep.cmd failed with error $_"
|
# Writelog "Cleaning up InstallAppsandSysprep.cmd failed with error $_"
|
||||||
throw $_
|
# throw $_
|
||||||
}
|
# }
|
||||||
try {
|
# try {
|
||||||
if (Test-Path -Path "$AppsPath\Win32" -PathType Container) {
|
# if (Test-Path -Path "$AppsPath\Win32" -PathType Container) {
|
||||||
WriteLog "Cleaning up Win32 folder"
|
# WriteLog "Cleaning up Win32 folder"
|
||||||
Remove-Item -Path "$AppsPath\Win32" -Recurse -Force
|
# Remove-Item -Path "$AppsPath\Win32" -Recurse -Force
|
||||||
}
|
# }
|
||||||
if (Test-Path -Path "$AppsPath\MSStore" -PathType Container) {
|
# if (Test-Path -Path "$AppsPath\MSStore" -PathType Container) {
|
||||||
WriteLog "Cleaning up MSStore folder"
|
# WriteLog "Cleaning up MSStore folder"
|
||||||
Remove-Item -Path "$AppsPath\MSStore" -Recurse -Force
|
# Remove-Item -Path "$AppsPath\MSStore" -Recurse -Force
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
catch {
|
# catch {
|
||||||
WriteLog "$_"
|
# WriteLog "$_"
|
||||||
throw $_
|
# throw $_
|
||||||
}
|
# }
|
||||||
#Create Deployment Media
|
#Create Deployment Media
|
||||||
If ($CreateDeploymentMedia) {
|
If ($CreateDeploymentMedia) {
|
||||||
try {
|
try {
|
||||||
@@ -4127,10 +4390,16 @@ Write-Host "FFU build process completed at" $endTime
|
|||||||
# Calculate the total run time
|
# Calculate the total run time
|
||||||
$runTime = $endTime - $startTime
|
$runTime = $endTime - $startTime
|
||||||
|
|
||||||
# Format the runtime as minutes and seconds
|
# Format the runtime with hours, minutes, and seconds
|
||||||
$runTimeFormatted = 'Duration: {0:mm} min {0:ss} sec' -f $runTime
|
if ($runTime.TotalHours -ge 1) {
|
||||||
|
$runTimeFormatted = 'Duration: {0:hh} hr {0:mm} min {0:ss} sec' -f $runTime
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$runTimeFormatted = 'Duration: {0:mm} min {0:ss} sec' -f $runTime
|
||||||
|
}
|
||||||
|
|
||||||
if ($VerbosePreference -ne 'Continue'){
|
if ($VerbosePreference -ne 'Continue'){
|
||||||
Write-Host $runTimeFormatted
|
Write-Host $runTimeFormatted
|
||||||
}
|
}
|
||||||
WriteLog 'Script complete: ' + $runTimeFormatted
|
WriteLog 'Script complete'
|
||||||
|
WriteLog $runTimeFormatted
|
||||||
|
|||||||
Binary file not shown.
@@ -128,13 +128,18 @@ $LogFileName = 'ScriptLog.txt'
|
|||||||
$USBDrive = Get-USBDrive
|
$USBDrive = Get-USBDrive
|
||||||
New-item -Path $USBDrive -Name $LogFileName -ItemType "file" -Force | Out-Null
|
New-item -Path $USBDrive -Name $LogFileName -ItemType "file" -Force | Out-Null
|
||||||
$LogFile = $USBDrive + $LogFilename
|
$LogFile = $USBDrive + $LogFilename
|
||||||
$version = '2408.1'
|
$version = '2409.1'
|
||||||
WriteLog 'Begin Logging'
|
WriteLog 'Begin Logging'
|
||||||
WriteLog "Script version: $version"
|
WriteLog "Script version: $version"
|
||||||
|
|
||||||
#Find PhysicalDrive
|
#Find PhysicalDrive
|
||||||
# $PhysicalDeviceID = Get-HardDrive
|
# $PhysicalDeviceID = Get-HardDrive
|
||||||
$hardDrive = Get-HardDrive
|
$hardDrive = Get-HardDrive
|
||||||
|
if($hardDrive -eq $null){
|
||||||
|
WriteLog 'No hard drive found. Exiting'
|
||||||
|
WriteLog 'Try adding storage drivers to the PE boot image (you can re-create your FFU and USB drive and add the PE drivers to the PEDrivers folder and add -CopyPEDrivers $true to the command line, or manually add them via DISM)'
|
||||||
|
Exit
|
||||||
|
}
|
||||||
$PhysicalDeviceID = $hardDrive.DeviceID
|
$PhysicalDeviceID = $hardDrive.DeviceID
|
||||||
$BytesPerSector = $hardDrive.BytesPerSector
|
$BytesPerSector = $hardDrive.BytesPerSector
|
||||||
WriteLog "Physical BytesPerSector is $BytesPerSector"
|
WriteLog "Physical BytesPerSector is $BytesPerSector"
|
||||||
@@ -549,6 +554,12 @@ If (Test-Path -Path $Drivers)
|
|||||||
WriteLog 'Copying drivers succeeded'
|
WriteLog 'Copying drivers succeeded'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WriteLog "Setting Windows Boot Manager to be first in the display order."
|
||||||
|
Invoke-Process bcdedit.exe "/set {fwbootmgr} displayorder {bootmgr} /addfirst"
|
||||||
|
WriteLog "Windows Boot Manager has been set to be first in the display order."
|
||||||
|
WriteLog "Setting default Windows boot loader to be first in the display order."
|
||||||
|
Invoke-Process bcdedit.exe "/set {bootmgr} displayorder {default} /addfirst"
|
||||||
|
WriteLog "The default Windows boot loader has been set to be first in the display order."
|
||||||
#Copy DISM log to USBDrive
|
#Copy DISM log to USBDrive
|
||||||
WriteLog "Copying dism log to $USBDrive"
|
WriteLog "Copying dism log to $USBDrive"
|
||||||
invoke-process xcopy "X:\Windows\logs\dism\dism.log $USBDrive /Y"
|
invoke-process xcopy "X:\Windows\logs\dism\dism.log $USBDrive /Y"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ The Full-Flash update (FFU) process can automatically download the latest releas
|
|||||||
|
|
||||||
# Updates
|
# Updates
|
||||||
|
|
||||||
2408.1 has been released! Check out the changes in the [Change Log](ChangeLog.md)
|
2409.1 has been released! Check out the changes in the [Change Log](ChangeLog.md)
|
||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user