mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
- Added Apps\Orchestration folder with new orchestration workflow to replace InstallAppsAndSysprep.cmd file.
- Updated BuildFFUUnattend files to point to the new Orchestrator.ps1 file. - Added new common and FFUUI.Core directories that house common/shared files between the UI and PS1 script. This breaks up each of the PS1 scripts to keep things smaller and more organized. Still a lot of work to do here to pull some stuff out of the PS1 scripts. - Modified the CaptureFFU.ps1 file to include more info during the capture process to help with troubleshooting - Too many functional changes to list here.
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
# FFU.Common.Core.psm1
|
||||
# Contains common core functions like logging and process invocation.
|
||||
|
||||
#Requires -Modules BitsTransfer
|
||||
|
||||
# Script-scoped variable for the log file path
|
||||
$script:CommonCoreLogFilePath = $null
|
||||
# Mutex for log file access
|
||||
$script:commonCoreLogMutexName = "Global\FFUCommonCoreLogMutex" # Unique name
|
||||
$script:commonCoreLogMutex = New-Object System.Threading.Mutex($false, $script:commonCoreLogMutexName)
|
||||
|
||||
# Function to set the log file path for this module
|
||||
function Set-CommonCoreLogPath {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Path
|
||||
)
|
||||
$script:CommonCoreLogFilePath = $Path
|
||||
if (-not [string]::IsNullOrWhiteSpace($script:CommonCoreLogFilePath)) {
|
||||
# This initial WriteLog confirms the path is set and the logger is working.
|
||||
WriteLog "CommonCoreLogPath set to: $script:CommonCoreLogFilePath"
|
||||
}
|
||||
else {
|
||||
# This Write-Warning will appear on console if path is bad, but won't go to log file yet.
|
||||
Write-Warning "Set-CommonCoreLogPath called with an empty or null path."
|
||||
}
|
||||
}
|
||||
|
||||
# Centralized WriteLog function
|
||||
function WriteLog {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$LogText
|
||||
)
|
||||
|
||||
# Check if the log file path has been set
|
||||
if ([string]::IsNullOrWhiteSpace($script:CommonCoreLogFilePath)) {
|
||||
Write-Warning "CommonCoreLogFilePath not set. Message: $LogText"
|
||||
return
|
||||
}
|
||||
|
||||
$logEntry = "$((Get-Date).ToString()) $LogText"
|
||||
$streamWriter = $null
|
||||
|
||||
try {
|
||||
$script:commonCoreLogMutex.WaitOne() | Out-Null
|
||||
# Ensure directory exists before writing
|
||||
$logDir = Split-Path -Path $script:CommonCoreLogFilePath -Parent
|
||||
if (-not (Test-Path -Path $logDir -PathType Container)) {
|
||||
New-Item -Path $logDir -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
|
||||
}
|
||||
$streamWriter = New-Object System.IO.StreamWriter($script:CommonCoreLogFilePath, $true, [System.Text.Encoding]::UTF8)
|
||||
$streamWriter.WriteLine($logEntry)
|
||||
|
||||
Write-Verbose $LogText
|
||||
}
|
||||
catch {
|
||||
# Use Write-Host for console visibility as Write-Warning might also try to log
|
||||
Write-Host "WARNING: Error writing to log file '$($script:CommonCoreLogFilePath)': $($_.Exception.Message)" -ForegroundColor Yellow
|
||||
}
|
||||
finally {
|
||||
if ($null -ne $streamWriter) {
|
||||
$streamWriter.Dispose()
|
||||
}
|
||||
$script:commonCoreLogMutex.ReleaseMutex()
|
||||
}
|
||||
}
|
||||
|
||||
# Function to invoke external process
|
||||
# function Invoke-Process {
|
||||
# [CmdletBinding(SupportsShouldProcess)]
|
||||
# param(
|
||||
# [Parameter(Mandatory)]
|
||||
# [ValidateNotNullOrEmpty()]
|
||||
# [string]$FilePath,
|
||||
# [Parameter()]
|
||||
# [ValidateNotNullOrEmpty()]
|
||||
# [string[]]$ArgumentList,
|
||||
# [Parameter()]
|
||||
# [ValidateNotNullOrEmpty()]
|
||||
# [bool]$Wait = $true
|
||||
# )
|
||||
|
||||
# $ErrorActionPreference = 'Stop' # Keep this local to the function
|
||||
|
||||
# try {
|
||||
# $stdOutTempFile = "$env:TEMP\$((New-Guid).Guid)"
|
||||
# $stdErrTempFile = "$env:TEMP\$((New-Guid).Guid)"
|
||||
|
||||
# $startProcessParams = @{
|
||||
# FilePath = $FilePath
|
||||
# ArgumentList = $ArgumentList
|
||||
# RedirectStandardError = $stdErrTempFile
|
||||
# RedirectStandardOutput = $stdOutTempFile
|
||||
# Wait = $Wait
|
||||
# PassThru = $true
|
||||
# NoNewWindow = $true
|
||||
# }
|
||||
|
||||
# # DEBUG
|
||||
# # WriteLog "Running Command: $($startProcessParams.FilePath) $($startProcessParams.ArgumentList -join ' ')"
|
||||
|
||||
# if ($PSCmdlet.ShouldProcess("Process [$($FilePath)]", "Run with args: [$($ArgumentList)]")) {
|
||||
# $cmd = Start-Process @startProcessParams
|
||||
# $cmdOutput = Get-Content -Path $stdOutTempFile -Raw -ErrorAction SilentlyContinue
|
||||
# $cmdError = Get-Content -Path $stdErrTempFile -Raw -ErrorAction SilentlyContinue
|
||||
|
||||
# if (-not [string]::IsNullOrWhiteSpace($cmdOutput)) {
|
||||
# WriteLog "STDOUT from '$FilePath': $cmdOutput"
|
||||
# }
|
||||
# if (-not [string]::IsNullOrWhiteSpace($cmdError)) {
|
||||
# WriteLog "STDERR from '$FilePath': $cmdError"
|
||||
# }
|
||||
|
||||
# if ($cmd.ExitCode -ne 0 -and $Wait) {
|
||||
# $errorMessage = "Process '$FilePath' exited with code $($cmd.ExitCode)."
|
||||
# if (-not [string]::IsNullOrWhiteSpace($cmdError)) {
|
||||
# $errorMessage += " Error: $cmdError"
|
||||
# }
|
||||
# elseif (-not [string]::IsNullOrWhiteSpace($cmdOutput)) {
|
||||
# $errorMessage += " Output: $cmdOutput"
|
||||
# }
|
||||
# throw $errorMessage.Trim()
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# catch {
|
||||
# WriteLog "Error in Invoke-Process for '$FilePath': $($_.Exception.Message)"
|
||||
# throw
|
||||
# }
|
||||
# finally {
|
||||
# if (Test-Path $stdOutTempFile) { Remove-Item -Path $stdOutTempFile -Force -ErrorAction Ignore }
|
||||
# if (Test-Path $stdErrTempFile) { Remove-Item -Path $stdErrTempFile -Force -ErrorAction Ignore }
|
||||
# }
|
||||
# return $cmd
|
||||
# }
|
||||
|
||||
function Invoke-Process {
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$FilePath,
|
||||
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string[]]$ArgumentList,
|
||||
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[bool]$Wait = $true
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
try {
|
||||
$stdOutTempFile = "$env:TEMP\$((New-Guid).Guid)"
|
||||
$stdErrTempFile = "$env:TEMP\$((New-Guid).Guid)"
|
||||
|
||||
$startProcessParams = @{
|
||||
FilePath = $FilePath
|
||||
ArgumentList = $ArgumentList
|
||||
RedirectStandardError = $stdErrTempFile
|
||||
RedirectStandardOutput = $stdOutTempFile
|
||||
Wait = $($Wait);
|
||||
PassThru = $true;
|
||||
NoNewWindow = $true;
|
||||
}
|
||||
if ($PSCmdlet.ShouldProcess("Process [$($FilePath)]", "Run with args: [$($ArgumentList)]")) {
|
||||
$cmd = Start-Process @startProcessParams
|
||||
$cmdOutput = Get-Content -Path $stdOutTempFile -Raw
|
||||
$cmdError = Get-Content -Path $stdErrTempFile -Raw
|
||||
if ($cmd.ExitCode -ne 0 -and $wait -eq $true) {
|
||||
if ($cmdError) {
|
||||
throw $cmdError.Trim()
|
||||
}
|
||||
if ($cmdOutput) {
|
||||
throw $cmdOutput.Trim()
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ([string]::IsNullOrEmpty($cmdOutput) -eq $false) {
|
||||
WriteLog $cmdOutput
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
#$PSCmdlet.ThrowTerminatingError($_)
|
||||
WriteLog $_
|
||||
# Write-Host "Script failed - $Logfile for more info"
|
||||
throw $_
|
||||
|
||||
}
|
||||
finally {
|
||||
Remove-Item -Path $stdOutTempFile, $stdErrTempFile -Force -ErrorAction Ignore
|
||||
}
|
||||
return $cmd
|
||||
}
|
||||
|
||||
# Function to download a file using BITS with retry and error handling
|
||||
function Start-BitsTransferWithRetry {
|
||||
param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Source,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Destination,
|
||||
[int]$Retries = 3
|
||||
)
|
||||
|
||||
$attempt = 0
|
||||
$lastError = $null
|
||||
|
||||
while ($attempt -lt $Retries) {
|
||||
$OriginalVerbosePreference = $VerbosePreference
|
||||
$OriginalProgressPreference = $ProgressPreference
|
||||
try {
|
||||
$VerbosePreference = 'SilentlyContinue'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
Start-BitsTransfer -Source $Source -Destination $Destination -ErrorAction Stop
|
||||
|
||||
$ProgressPreference = $OriginalProgressPreference
|
||||
$VerbosePreference = $OriginalVerbosePreference
|
||||
WriteLog "Successfully transferred $Source to $Destination."
|
||||
return
|
||||
}
|
||||
catch {
|
||||
$lastError = $_
|
||||
$attempt++
|
||||
WriteLog "Attempt $attempt of $Retries failed to download $Source. Error: $($lastError.Exception.Message)."
|
||||
Start-Sleep -Seconds (1 * $attempt)
|
||||
}
|
||||
finally {
|
||||
if (Get-Variable -Name 'OriginalProgressPreference' -ErrorAction SilentlyContinue) {
|
||||
$ProgressPreference = $OriginalProgressPreference
|
||||
}
|
||||
if (Get-Variable -Name 'OriginalVerbosePreference' -ErrorAction SilentlyContinue) {
|
||||
$VerbosePreference = $OriginalVerbosePreference
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WriteLog "Failed to download $Source after $Retries attempts. Last Error: $($lastError.Exception.Message)"
|
||||
throw $lastError
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function Set-CommonCoreLogPath, WriteLog, Invoke-Process, Start-BitsTransferWithRetry
|
||||
@@ -0,0 +1,92 @@
|
||||
# FFU Common Drivers Module
|
||||
# Contains shared functions related to driver handling.
|
||||
|
||||
#Requires -Modules Dism
|
||||
|
||||
# Import the common core module for logging and process invocation
|
||||
Import-Module "$PSScriptRoot\FFU.Common.Core.psm1"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# SECTION: Driver Compression Function
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
function Compress-DriverFolderToWim {
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateScript({ Test-Path -Path $_ -PathType Container })]
|
||||
[string]$SourceFolderPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$DestinationWimPath,
|
||||
|
||||
[Parameter()]
|
||||
[string]$WimName, # Optional, defaults to folder name
|
||||
|
||||
[Parameter()]
|
||||
[string]$WimDescription # Optional, defaults to folder name
|
||||
)
|
||||
|
||||
WriteLog "Starting compression of folder '$SourceFolderPath' to '$DestinationWimPath'."
|
||||
|
||||
# Default WIM Name and Description to the source folder name if not provided
|
||||
$sourceFolderName = Split-Path -Path $SourceFolderPath -Leaf
|
||||
if ([string]::IsNullOrWhiteSpace($WimName)) {
|
||||
$WimName = $sourceFolderName
|
||||
WriteLog "WIM Name not provided, defaulting to source folder name: '$WimName'."
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($WimDescription)) {
|
||||
$WimDescription = $sourceFolderName
|
||||
WriteLog "WIM Description not provided, defaulting to source folder name: '$WimDescription'."
|
||||
}
|
||||
|
||||
# Ensure destination directory exists
|
||||
$destinationDir = Split-Path -Path $DestinationWimPath -Parent
|
||||
if (-not (Test-Path -Path $destinationDir -PathType Container)) {
|
||||
WriteLog "Creating destination directory: $destinationDir"
|
||||
try {
|
||||
New-Item -Path $destinationDir -ItemType Directory -Force -ErrorAction Stop | Out-Null
|
||||
}
|
||||
catch {
|
||||
WriteLog "Failed to create destination directory '$destinationDir': $($_.Exception.Message)"
|
||||
return $false # Indicate failure
|
||||
}
|
||||
}
|
||||
|
||||
if ($PSCmdlet.ShouldProcess("Folder '$SourceFolderPath'", "Compress to WIM '$DestinationWimPath'")) {
|
||||
try {
|
||||
# Construct arguments for dism.exe
|
||||
$dismArgs = "/Capture-Image /ImageFile:`"$DestinationWimPath`" /CaptureDir:`"$SourceFolderPath`" /Name:`"$WimName`" /Description:`"$WimDescription`" /Compress:Max /CheckIntegrity /Quiet"
|
||||
|
||||
WriteLog "Executing dism.exe via Invoke-Process with arguments:"
|
||||
WriteLog "dism.exe $dismArgs"
|
||||
|
||||
# Call Invoke-Process (assumed to be available from FFUUI.Core.psm1 or another imported module)
|
||||
# Invoke-Process is expected to throw an exception for non-zero exit codes.
|
||||
Invoke-Process -FilePath "dism.exe" -ArgumentList $dismArgs -Wait $true
|
||||
|
||||
WriteLog "Successfully compressed '$SourceFolderPath' to '$DestinationWimPath' using dism.exe."
|
||||
return $true # Indicate success
|
||||
}
|
||||
catch {
|
||||
WriteLog "Failed to compress folder '$SourceFolderPath' to WIM '$DestinationWimPath' using dism.exe."
|
||||
WriteLog "Error details: $($_.Exception.Message)"
|
||||
# Check if the error message contains details about the DISM log (dism.exe output might be in the exception)
|
||||
if ($_.Exception.Message -match 'DISM log file can be found at (.*)') {
|
||||
$dismLogPath = $matches[1].Trim()
|
||||
WriteLog "Check the DISM log for more details: $dismLogPath"
|
||||
}
|
||||
return $false # Indicate failure
|
||||
}
|
||||
}
|
||||
else {
|
||||
WriteLog "Compression operation skipped due to -WhatIf."
|
||||
return $false # Indicate skipped operation
|
||||
}
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# SECTION: Module Export
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
Export-ModuleMember -Function Compress-DriverFolderToWim
|
||||
+68
-29
@@ -1,3 +1,6 @@
|
||||
# Import the common core module for logging
|
||||
Import-Module "$PSScriptRoot\FFU.Common.Core.psm1"
|
||||
|
||||
function Get-Application {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
@@ -14,10 +17,10 @@ function Get-Application {
|
||||
$wingetSearchResult = Find-WinGetPackage -id $AppId -MatchOption Equals -Source $Source
|
||||
if (-not $wingetSearchResult) {
|
||||
if ($VerbosePreference -ne 'Continue') {
|
||||
Write-Error "$AppName not found in $Source repository. Exiting."
|
||||
Write-Error "$AppName not found in $Source repository."
|
||||
Write-Error "Check the AppList.json file and make sure the AppID is correct."
|
||||
}
|
||||
WriteLog "$AppName not found in $Source repository. Exiting."
|
||||
WriteLog "$AppName not found in $Source repository."
|
||||
WriteLog "Check the AppList.json file and make sure the AppID is correct."
|
||||
Exit 1
|
||||
}
|
||||
@@ -26,7 +29,8 @@ function Get-Application {
|
||||
$appIsWin32 = ($Source -eq 'msstore' -and $AppId.StartsWith("XP"))
|
||||
if ($Source -eq 'winget' -or $appIsWin32) {
|
||||
$appFolderPath = Join-Path -Path "$AppsPath\Win32" -ChildPath $AppName
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$appFolderPath = Join-Path -Path "$AppsPath\MSStore" -ChildPath $AppName
|
||||
}
|
||||
|
||||
@@ -67,14 +71,12 @@ function Get-Application {
|
||||
Write-Error "ERROR: The Microsoft Store app $AppName does not support downloads by the publisher. Please remove it from the AppList.json. If there's a winget source version of the application, try using that instead. Exiting."
|
||||
Exit 1
|
||||
}
|
||||
|
||||
# Other download failures
|
||||
WriteLog "ERROR: Download failed for $AppName with status: $($wingetDownloadResult.status)"
|
||||
WriteLog "ERROR: Download failed for $AppName with error code: $($wingetDownloadResult.ExtendedErrorCode)"
|
||||
WriteLog "Exiting"
|
||||
}
|
||||
else {
|
||||
$errormsg = "ERROR: Download failed for $AppName with status: $($wingetDownloadResult.status) $($wingetDownloadResult.ExtendedErrorCode)"
|
||||
WriteLog $errormsg
|
||||
Remove-Item -Path $appFolderPath -Recurse -Force
|
||||
Write-Error "ERROR: Download failed for $AppName with status: $($wingetDownloadResult.status)"
|
||||
Write-Error "ERROR: Download failed for $AppName with error code: $($wingetDownloadResult.ExtendedErrorCode)"
|
||||
Write-Error $errormsg
|
||||
Exit 1
|
||||
}
|
||||
}
|
||||
@@ -88,7 +90,7 @@ function Get-Application {
|
||||
if ($uwpExtensions -contains $installerPath.Extension -and $appFolderPath -match 'Win32') {
|
||||
# Handle UWP apps
|
||||
$NewAppPath = "$AppsPath\MSStore\$AppName"
|
||||
Writelog "$AppName is a UWP app. Moving to $NewAppPath"
|
||||
WriteLog "$AppName is a UWP app. Moving to $NewAppPath"
|
||||
WriteLog "Creating $NewAppPath"
|
||||
New-Item -Path "$AppsPath\MSStore\$AppName" -ItemType Directory -Force | Out-Null
|
||||
WriteLog "Moving $AppName to $NewAppPath"
|
||||
@@ -97,12 +99,16 @@ function Get-Application {
|
||||
Remove-Item -Path $appFolderPath -Force -Recurse
|
||||
WriteLog "$AppName moved to $NewAppPath"
|
||||
# Set-InstallStoreAppsFlag
|
||||
$result = 0 # Success for UWP app
|
||||
}
|
||||
|
||||
# If app is in Win32 folder, add the silent install command to the WinGetWin32Apps.json file
|
||||
elseif($appFolderPath -match 'Win32'){
|
||||
elseif ($appFolderPath -match 'Win32') {
|
||||
WriteLog "$AppName is a Win32 app. Adding silent install command to $orchestrationpath\WinGetWin32Apps.json"
|
||||
Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $appFolderPath
|
||||
$result = Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $appFolderPath
|
||||
}
|
||||
else {
|
||||
# For any other case, set result to 0 (success)
|
||||
$result = 0
|
||||
}
|
||||
|
||||
# Handle MSStore specific post-processing
|
||||
@@ -145,8 +151,9 @@ function Get-Application {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result
|
||||
}
|
||||
|
||||
function Get-Apps {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
@@ -181,7 +188,7 @@ function Get-Apps {
|
||||
# Create necessary folders
|
||||
$win32Folder = Join-Path -Path $AppsPath -ChildPath "Win32"
|
||||
$storeAppsFolder = Join-Path -Path $AppsPath -ChildPath "MSStore"
|
||||
|
||||
|
||||
# Process WinGet apps
|
||||
if ($wingetApps) {
|
||||
if (-not (Test-Path -Path $win32Folder -PathType Container)) {
|
||||
@@ -218,7 +225,30 @@ function Get-Apps {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Install-WinGet {
|
||||
param (
|
||||
[string]$Architecture
|
||||
)
|
||||
$packages = @(
|
||||
@{Name = "VCLibs"; Url = "https://aka.ms/Microsoft.VCLibs.$Architecture.14.00.Desktop.appx"; File = "Microsoft.VCLibs.$Architecture.14.00.Desktop.appx" },
|
||||
@{Name = "UIXaml"; Url = "https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.$Architecture.appx"; File = "Microsoft.UI.Xaml.2.8.$Architecture.appx" },
|
||||
@{Name = "WinGet"; Url = "https://aka.ms/getwinget"; File = "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" }
|
||||
)
|
||||
foreach ($package in $packages) {
|
||||
$destination = Join-Path -Path $env:TEMP -ChildPath $package.File
|
||||
WriteLog "Downloading $($package.Name) from $($package.Url) to $destination"
|
||||
Start-BitsTransferWithRetry -Source $package.Url -Destination $destination
|
||||
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
|
||||
# Set progress preference back to default
|
||||
$ProgressPreference = 'Continue'
|
||||
WriteLog "Removing $($package.Name)..."
|
||||
Remove-Item -Path $destination -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
WriteLog "WinGet installation complete."
|
||||
}
|
||||
function Confirm-WinGetInstallation {
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
@@ -228,19 +258,20 @@ function Confirm-WinGetInstallation {
|
||||
|
||||
# Check WinGet PowerShell module
|
||||
$wingetModule = Get-InstalledModule -Name Microsoft.Winget.Client -ErrorAction SilentlyContinue
|
||||
if ($wingetModule.Version -lt $minVersion -or -not $wingetModule) {
|
||||
$wingetModuleVersion = [version]$wingetModule.Version
|
||||
if ($wingetModuleVersion -lt $minVersion -or -not $wingetModule) {
|
||||
WriteLog 'Microsoft.Winget.Client module is not installed or is an older version. Installing the latest version...'
|
||||
|
||||
# Handle PSGallery trust settings
|
||||
$PSGalleryTrust = (Get-PSRepository -Name 'PSGallery').InstallationPolicy
|
||||
if($PSGalleryTrust -eq 'Untrusted') {
|
||||
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') {
|
||||
if ($PSGalleryTrust -eq 'Untrusted') {
|
||||
WriteLog 'Setting PSGallery back to untrusted repository...'
|
||||
Set-PSRepository -Name 'PSGallery' -InstallationPolicy Untrusted
|
||||
WriteLog 'Done'
|
||||
@@ -264,7 +295,6 @@ function Confirm-WinGetInstallation {
|
||||
WriteLog "Installed WinGet version: $wingetVersion"
|
||||
}
|
||||
}
|
||||
|
||||
function Add-Win32SilentInstallCommand {
|
||||
param (
|
||||
[string]$AppFolder,
|
||||
@@ -275,7 +305,7 @@ function Add-Win32SilentInstallCommand {
|
||||
if (-not $installerPath) {
|
||||
WriteLog "No win32 app installers were found. Skipping the inclusion of $AppFolder"
|
||||
Remove-Item -Path $AppFolderPath -Recurse -Force
|
||||
return $false
|
||||
return 1
|
||||
}
|
||||
$yamlFile = Get-ChildItem -Path "$appFolderPath\*" -Include "*.yaml" -File -ErrorAction Stop
|
||||
$yamlContent = Get-Content -Path $yamlFile -Raw
|
||||
@@ -283,7 +313,7 @@ function Add-Win32SilentInstallCommand {
|
||||
if (-not $silentInstallSwitch) {
|
||||
WriteLog "Silent install switch for $appName could not be found. Skipping the inclusion of $appName."
|
||||
Remove-Item -Path $appFolderPath -Recurse -Force
|
||||
return $false
|
||||
return 2
|
||||
}
|
||||
$installer = Split-Path -Path $installerPath -Leaf
|
||||
if ($installerPath.Extension -eq ".exe") {
|
||||
@@ -305,17 +335,18 @@ function Add-Win32SilentInstallCommand {
|
||||
if ($appsData.Count -gt 0) {
|
||||
$highestPriority = $appsData.Count + 1
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$appsData = @()
|
||||
$highestPriority = 1
|
||||
}
|
||||
|
||||
# Create new app entry
|
||||
$newApp = [PSCustomObject]@{
|
||||
Priority = $highestPriority
|
||||
Name = $appName
|
||||
Priority = $highestPriority
|
||||
Name = $appName
|
||||
CommandLine = $silentInstallCommand
|
||||
Arguments = $silentInstallSwitch
|
||||
Arguments = $silentInstallSwitch
|
||||
}
|
||||
|
||||
$appsData += $newApp
|
||||
@@ -323,5 +354,13 @@ function Add-Win32SilentInstallCommand {
|
||||
|
||||
WriteLog "Added $appName to WinGetWin32Apps.json with priority $highestPriority"
|
||||
|
||||
# return $true
|
||||
}
|
||||
# Return 0 for success
|
||||
return 0
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# SECTION: Module Export
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# Export functions needed by both BuildFFUVM and the UI Core module
|
||||
Export-ModuleMember -Function Get-Application, Get-Apps, Confirm-WinGetInstallation, Add-Win32SilentInstallCommand, Install-Winget
|
||||
Reference in New Issue
Block a user