Install-Winget.ps1 - Add existing installer files parameter
Adds optional string parameter to use existing installer filespull/13/head^2
parent
dc084ba12b
commit
a716ce5574
|
|
@ -3,11 +3,24 @@
|
||||||
|
|
||||||
# Author: ThioJoe
|
# Author: ThioJoe
|
||||||
# Repo Url: https://github.com/ThioJoe/Windows-Sandbox-Tools
|
# Repo Url: https://github.com/ThioJoe/Windows-Sandbox-Tools
|
||||||
# Last Updated: August 4, 2025
|
# Last Updated: February 12, 2026
|
||||||
|
|
||||||
param(
|
param(
|
||||||
[switch]$removeMsStoreAsSource = $false # If switch is included, it will remove the 'msstore' source after installing winget, which doesn't work with Sandbox, unless the Microsoft Store is also installed
|
# If switch is included, it will remove the 'msstore' source after installing winget, which doesn't work with Sandbox, unless the Microsoft Store is also installed
|
||||||
)
|
[switch]$removeMsStoreAsSource = $false,
|
||||||
|
|
||||||
|
# Optional path to a local directory containing the installation files. If provided, the download steps will be skipped.
|
||||||
|
# - Just copy the entire "Winget Install" folder with the files the script normally downloads, and put it in your mounted folder.
|
||||||
|
# - Make sure to use the mounted path from the perspective of within the sandbox.
|
||||||
|
[string]$ExistingInstallerFilesPath
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Parameter Usage Examples ---
|
||||||
|
# Standard run (Download & Install):
|
||||||
|
# .\Install-Winget.ps1
|
||||||
|
#
|
||||||
|
# Install from existing files instead of downloading:
|
||||||
|
# .\Install-Winget.ps1 -ExistingInstallerFilesPath "C:\Users\WDAGUtilityAccount\Desktop\HostShared\Winget Install"
|
||||||
|
|
||||||
function Get-LatestRelease {
|
function Get-LatestRelease {
|
||||||
param(
|
param(
|
||||||
|
|
@ -77,25 +90,33 @@ function Install-WingetDependencies {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# --- Define Working Directory ---
|
||||||
|
$userDownloadsFolder = (New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path
|
||||||
|
$subfolderName = "Winget Install"
|
||||||
|
$msixName = "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
|
||||||
|
|
||||||
|
if ($ExistingInstallerFilesPath) {
|
||||||
|
if (Test-Path -Path $ExistingInstallerFilesPath) {
|
||||||
|
$workingDir = $ExistingInstallerFilesPath
|
||||||
|
Write-Host "Using local source path: $workingDir" -ForegroundColor Yellow
|
||||||
|
} else {
|
||||||
|
Write-Error "The specified local source path does not exist: $ExistingInstallerFilesPath"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Combine them to create the full working directory path
|
||||||
|
$workingDir = Join-Path -Path $userDownloadsFolder -ChildPath $subfolderName
|
||||||
|
|
||||||
|
# Create the directory if it doesn't exist
|
||||||
|
if (-not (Test-Path -Path $workingDir)) {
|
||||||
|
New-Item -Path $workingDir -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Prevents progress bar from showing (often speeds downloads)
|
# Prevents progress bar from showing (often speeds downloads)
|
||||||
$ProgressPreference = 'SilentlyContinue'
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
|
||||||
$downloadPath = Join-Path $env:USERPROFILE "Downloads"
|
# --- Determine Architecture ---
|
||||||
$latestRelease = Get-LatestRelease
|
|
||||||
if (-not $latestRelease) { Write-Error "Could not retrieve the latest release. Exiting."; return; }
|
|
||||||
|
|
||||||
$latestTag = $latestRelease.tag_name
|
|
||||||
Write-Host "Latest winget version tag is: $latestTag"
|
|
||||||
|
|
||||||
# Download the MSIX bundle
|
|
||||||
$msixName = "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
|
|
||||||
$msixUrl = Get-AssetUrl -release $latestRelease -assetName $msixName
|
|
||||||
if (-not $msixUrl) { Write-Error "Could not find $msixName in the latest release assets."; return; }
|
|
||||||
|
|
||||||
Write-Host "Downloading $msixName..."
|
|
||||||
$msixPath = Join-Path $downloadPath $msixName
|
|
||||||
Invoke-WebRequest -Uri $msixUrl -OutFile $msixPath
|
|
||||||
|
|
||||||
# Figure out the OS architecture using environment variable
|
# Figure out the OS architecture using environment variable
|
||||||
$procArch = $env:PROCESSOR_ARCHITECTURE
|
$procArch = $env:PROCESSOR_ARCHITECTURE
|
||||||
switch -Wildcard ($procArch) {
|
switch -Wildcard ($procArch) {
|
||||||
|
|
@ -109,49 +130,85 @@ switch -Wildcard ($procArch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Download the dependencies zip
|
# --- Download Steps (Skipped if using existing files) ---
|
||||||
$depsZipName = "DesktopAppInstaller_Dependencies.zip"
|
if (-not $ExistingInstallerFilesPath) {
|
||||||
$depsZipUrl = Get-AssetUrl -release $latestRelease -assetName $depsZipName
|
$latestRelease = Get-LatestRelease
|
||||||
|
if (-not $latestRelease) { Write-Error "Could not retrieve the latest release. Exiting."; return; }
|
||||||
|
|
||||||
# We'll expand to a base 'Dependencies' folder
|
$latestTag = $latestRelease.tag_name
|
||||||
$topDepsFolder = Join-Path $downloadPath "Dependencies"
|
Write-Host "Latest winget version tag is: $latestTag"
|
||||||
# Then pick the sub-folder for the architecture
|
|
||||||
$depsFolder = Join-Path $topDepsFolder $arch
|
|
||||||
|
|
||||||
if ($depsZipUrl) {
|
# Download the MSIX bundle
|
||||||
Write-Host "Downloading $depsZipName..."
|
$msixUrl = Get-AssetUrl -release $latestRelease -assetName $msixName
|
||||||
$depsZipPath = Join-Path $downloadPath $depsZipName
|
if (-not $msixUrl) { Write-Error "Could not find $msixName in the latest release assets."; return; }
|
||||||
Invoke-WebRequest -Uri $depsZipUrl -OutFile $depsZipPath
|
|
||||||
|
|
||||||
# Remove existing Dependencies folder and expand the zip
|
Write-Host "Downloading $msixName..."
|
||||||
if (Test-Path $topDepsFolder) { Remove-Item -Path $topDepsFolder -Recurse -Force }
|
$msixPath = Join-Path $workingDir $msixName
|
||||||
|
Invoke-WebRequest -Uri $msixUrl -OutFile $msixPath
|
||||||
# Use Expand-Archive cmdlet by default because it's safe for constrained language mode. Fall back to .NET assembly if it fails.
|
|
||||||
try {
|
# Download the dependencies zip
|
||||||
Expand-Archive -LiteralPath $depsZipPath -DestinationPath $topDepsFolder -Force -ErrorAction Stop
|
$depsZipName = "DesktopAppInstaller_Dependencies.zip"
|
||||||
}
|
$depsZipUrl = Get-AssetUrl -release $latestRelease -assetName $depsZipName
|
||||||
catch {
|
|
||||||
Write-Warning "Standard extraction failed, attempting .NET fallback. The error was: $($_.Exception.Message)"
|
# We'll expand to a base 'Dependencies' folder
|
||||||
# Fallback using .NET System.IO.Compression (Fixes issues in non-EN Windows Sandbox)
|
$topDepsFolder = Join-Path $workingDir "Dependencies"
|
||||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
||||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($depsZipPath, $topDepsFolder)
|
if ($depsZipUrl) {
|
||||||
}
|
Write-Host "Downloading $depsZipName..."
|
||||||
}
|
$depsZipPath = Join-Path $workingDir $depsZipName
|
||||||
else { Write-Warning "No $depsZipName found in $latestTag, skipping dependency download."; }
|
Invoke-WebRequest -Uri $depsZipUrl -OutFile $depsZipPath
|
||||||
|
|
||||||
|
# Remove existing Dependencies folder and expand the zip
|
||||||
|
if (Test-Path $topDepsFolder) { Remove-Item -Path $topDepsFolder -Recurse -Force }
|
||||||
|
|
||||||
|
# Use Expand-Archive cmdlet by default because it's safe for constrained language mode. Fall back to .NET assembly if it fails.
|
||||||
|
try {
|
||||||
|
Expand-Archive -LiteralPath $depsZipPath -DestinationPath $topDepsFolder -Force -ErrorAction Stop
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Warning "Standard extraction failed, attempting .NET fallback. The error was: $($_.Exception.Message)"
|
||||||
|
# Fallback using .NET System.IO.Compression (Fixes issues in non-EN Windows Sandbox)
|
||||||
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||||
|
[System.IO.Compression.ZipFile]::ExtractToDirectory($depsZipPath, $topDepsFolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cleanup the zip file
|
||||||
|
if (Test-Path $depsZipPath) {
|
||||||
|
Remove-Item -Path $depsZipPath -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { Write-Warning "No $depsZipName found in $latestTag, skipping dependency download."; }
|
||||||
|
}
|
||||||
|
|
||||||
# Restore progress preference
|
# Restore progress preference
|
||||||
$ProgressPreference = 'Continue'
|
$ProgressPreference = 'Continue'
|
||||||
|
|
||||||
# If dependencies exist for this architecture, install them
|
# --- Installation Steps ---
|
||||||
|
|
||||||
|
# Define paths based on working directory
|
||||||
|
$msixPath = Join-Path $workingDir $msixName
|
||||||
|
$topDepsFolder = Join-Path $workingDir "Dependencies"
|
||||||
|
$depsFolder = Join-Path $topDepsFolder $arch
|
||||||
|
|
||||||
|
# Install Dependencies
|
||||||
if (Test-Path $depsFolder) {
|
if (Test-Path $depsFolder) {
|
||||||
Install-WingetDependencies -depsFolder $depsFolder
|
Install-WingetDependencies -depsFolder $depsFolder
|
||||||
} else {
|
} else {
|
||||||
Write-Warning "No architecture-specific dependencies found at $depsFolder"
|
if ($ExistingInstallerFilesPath) {
|
||||||
|
Write-Error "Dependencies folder not found at: $depsFolder`nEnsure the 'Dependencies' folder is present in your source directory."
|
||||||
|
} else {
|
||||||
|
Write-Warning "No architecture-specific dependencies found at $depsFolder"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Finally, install the winget MSIX bundle
|
# Install Winget MSIX bundle
|
||||||
Write-Host "Installing $msixName..."
|
if (Test-Path $msixPath) {
|
||||||
Add-AppxPackage -Path $msixPath
|
Write-Host "Installing $msixName..."
|
||||||
|
Add-AppxPackage -Path $msixPath
|
||||||
|
} else {
|
||||||
|
Write-Error "Winget package not found at: $msixPath"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
# Remove msstore source if set to do so
|
# Remove msstore source if set to do so
|
||||||
if ($removeMsStoreAsSource.IsPresent) {
|
if ($removeMsStoreAsSource.IsPresent) {
|
||||||
|
|
@ -164,4 +221,4 @@ if ($removeMsStoreAsSource.IsPresent) {
|
||||||
} else {
|
} else {
|
||||||
# Automatically accept source agreements to avoid prompts. Mostly applies to msstore.
|
# Automatically accept source agreements to avoid prompts. Mostly applies to msstore.
|
||||||
winget list --accept-source-agreements | Out-Null
|
winget list --accept-source-agreements | Out-Null
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue