Last active
July 13, 2025 01:22
-
-
Save RandallFlagg/ce2b68b2c49da210c27eafb2ff48f180 to your computer and use it in GitHub Desktop.
Winget
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
A PowerShell script to export or import installed applications using the Windows Package Manager (winget). | |
.DESCRIPTION | |
This script allows you to either export a list of currently installed winget packages to a JSON file | |
or import a list from a JSON file to install them. It includes validation, comprehensive logging, | |
and detailed reporting on successful and failed installations. | |
.PARAMETER Action | |
Specifies the operation to perform. Must be either 'Export' or 'Import'. | |
.PARAMETER FilePath | |
Specifies the full path to the JSON file to be used for the export or import operation. | |
.PARAMETER LogPath | |
Optional. Specifies the directory where the transcript and result logs will be saved. | |
Defaults to a 'logs' folder in the script's directory. | |
.PARAMETER Usage | |
Displays the help information and usage examples for the script. | |
.EXAMPLE | |
# Show usage instructions | |
.\YourScriptName.ps1 -Usage | |
.EXAMPLE | |
# Exports installed packages to a file on the Desktop, with logs saved to the default location. | |
.\YourScriptName.ps1 -Action Export -FilePath "$env:USERPROFILE\Desktop\winget_packages.json" | |
.EXAMPLE | |
# Imports packages and saves logs to a custom path. | |
.\YourScriptName.ps1 -Action Import -FilePath "C:\temp\packages.json" -LogPath "C:\temp\winget_logs" | |
#> | |
param( | |
[Parameter(Mandatory = $false, HelpMessage = "Specify 'Export' to save the package list or 'Import' to install from a list.")] | |
[string]$Action, | |
[Parameter(Mandatory = $false, HelpMessage = "Enter the full path for the JSON file.")] | |
[string]$FilePath, | |
[Parameter(Mandatory = $false, HelpMessage = "Directory to store log files.")] | |
[string]$LogPath = (Join-Path $PSScriptRoot "logs"), | |
[Parameter(Mandatory = $false, HelpMessage = "Display the script's usage instructions.")] | |
[switch]$Usage | |
) | |
# Get the script's own filename dynamically at the global scope | |
$scriptName = $MyInvocation.MyCommand.Name | |
# Function to display usage information, replacing Get-Help for better portability | |
function Show-Usage { | |
Write-Host "`n.SYNOPSIS" -ForegroundColor Cyan | |
Write-Host " A PowerShell script to export or import installed applications using the Windows Package Manager (winget)." | |
Write-Host "`n.DESCRIPTION" -ForegroundColor Cyan | |
Write-Host " This script allows you to either export a list of currently installed winget packages to a JSON file" | |
Write-Host " or import a list from a JSON file to install them. It includes validation, comprehensive logging," | |
Write-Host " and detailed reporting on successful and failed installations." | |
Write-Host "`n.PARAMETER Action" -ForegroundColor Cyan | |
Write-Host " Specifies the operation to perform. Must be either 'Export' or 'Import'." | |
Write-Host "`n.PARAMETER FilePath" -ForegroundColor Cyan | |
Write-Host " Specifies the full path to the JSON file to be used for the export or import operation." | |
Write-Host "`n.PARAMETER LogPath" -ForegroundColor Cyan | |
Write-Host " Optional. Specifies the directory where the transcript and result logs will be saved." | |
Write-Host " Defaults to a 'logs' folder in the script's directory." | |
Write-Host "`n.PARAMETER Usage" -ForegroundColor Cyan | |
Write-Host " Displays the help information and usage examples for the script." | |
Write-Host "`n.EXAMPLE" -ForegroundColor Cyan | |
Write-Host " # Show usage instructions" | |
Write-Host " .$scriptName -Usage" | |
Write-Host "`n.EXAMPLE" -ForegroundColor Cyan | |
Write-Host " # Exports installed packages to a file on the Desktop, with logs saved to the default location." | |
Write-Host " .$scriptName -Action Export -FilePath `"$env:USERPROFILE\Desktop\winget_packages.json`"" | |
Write-Host "`n.EXAMPLE" -ForegroundColor Cyan | |
Write-Host " # Imports packages and saves logs to a custom path." | |
Write-Host " .$scriptName -Action Import -FilePath `"$env:USERPROFILE\Desktop\winget_packages.json`" -LogPath `"$env:USERPROFILE\Desktop\winget_logs`"" | |
Write-Host "" | |
} | |
# If -Usage switch is used, or mandatory parameters are missing, or Action is invalid, show help and exit. | |
if ($Usage -or (-not $Action) -or (-not $FilePath) -or ($Action -ne 'Export' -and $Action -ne 'Import')) { | |
Show-Usage # Call the custom usage function | |
return | |
} | |
# --- Main Function --- | |
function Invoke-WingetAction { | |
# Create the log directory if it doesn't exist | |
if (-not (Test-Path -Path $LogPath)) { | |
New-Item -Path $LogPath -ItemType Directory -Force | Out-Null | |
} | |
# Define log file paths | |
$transcriptLog = Join-Path $LogPath "Transcript-$(Get-Date -Format 'yyyy-MM-dd_HH-mm-ss').log" | |
$successLog = Join-Path $LogPath "Success.log" | |
$failureLog = Join-Path $LogPath "Failure.log" | |
# Start logging all console output | |
Start-Transcript -Path $transcriptLog | |
try { | |
Write-Host "Starting winget '$Action' operation..." -ForegroundColor Green | |
Write-Host "Full transcript will be saved to: $transcriptLog" | |
switch ($Action) { | |
'Export' { | |
$Directory = Split-Path -Path $FilePath -Parent | |
# Validate that the parent directory exists | |
if (-not (Test-Path -Path $Directory)) { | |
throw "Error: The directory '$Directory' does not exist. Please create it or provide a valid path." | |
} | |
# Validate that FilePath includes a filename (i.e., is not just a directory) | |
if ([string]::IsNullOrEmpty((Split-Path -Path $FilePath -Leaf))) { | |
throw "Error: When exporting, the FilePath must include a filename (e.g., 'C:\path\to\packages.json'), not just a directory." | |
} | |
# New check: If the FilePath already exists, ensure it's a file, not a directory. | |
if (Test-Path -Path $FilePath -PathType Container) { | |
throw "Error: The provided FilePath '$FilePath' exists and is a directory. Please provide a path to a file." | |
} | |
Write-Host "Exporting installed packages to: $FilePath" | |
# Execute the winget export command. We do NOT include versions to ensure import gets the latest. | |
winget export --source winget -o $FilePath | |
} | |
'Import' { | |
if (-not (Test-Path -Path $FilePath -PathType Leaf)) { | |
throw "Error: The file '$FilePath' was not found. Please provide a valid file path." | |
} | |
Write-Host "Importing packages from: $FilePath" | |
Write-Host "Results will be logged to:" | |
Write-Host " - Success: $successLog" | |
Write-Host " - Failure: $failureLog" | |
# Clear previous result logs | |
Clear-Content $successLog, $failureLog -ErrorAction SilentlyContinue | |
# Execute the winget import command and capture all output (standard and error) | |
# The --ignore-versions flag ensures winget fetches the latest version of each package. | |
$importOutput = winget import -i $FilePath --ignore-versions --accept-package-agreements --accept-source-agreements 2>&1 | |
# Parse the output to determine success and failures | |
$packages = (Get-Content $FilePath | ConvertFrom-Json).Packages.PackageIdentifier | |
foreach ($package in $packages) { | |
# Check for success message related to the package | |
if ($importOutput -match "Successfully installed.*$package" -or $importOutput -match "$package\s+Already installed") { | |
"$package" | Add-Content -Path $successLog | |
} | |
else { | |
# Find the specific error for the failed package | |
$errorLine = $importOutput | Select-String -Pattern "$package" -Context 0, 2 | Select-String -Pattern "Installer failed|No applicable installer found|error" | |
"$package - Reason: $($errorLine | Out-String)" | Add-Content -Path $failureLog | |
} | |
} | |
Write-Host "`n--- Import Summary ---" | |
Write-Host "Successful packages logged to $successLog" | |
Get-Content $successLog -ErrorAction SilentlyContinue | |
Write-Host "`nFailed packages logged to $failureLog" | |
Get-Content $failureLog -ErrorAction SilentlyContinue | |
Write-Host "----------------------`n" | |
} | |
} | |
Write-Host "Winget '$Action' operation completed." -ForegroundColor Green | |
} | |
catch { | |
# Catch any terminating errors from the script or winget process | |
Write-Error "A critical error occurred during the '$Action' operation: $_" | |
} | |
finally { | |
# Ensure the transcript is always stopped | |
Stop-Transcript | |
} | |
} | |
# Run the main function | |
Invoke-WingetAction |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment