Skip to content

Instantly share code, notes, and snippets.

@ergosteur
Last active October 30, 2024 02:24
Show Gist options
  • Save ergosteur/c61087cf78cdda37176f0a63a0a9145c to your computer and use it in GitHub Desktop.
Save ergosteur/c61087cf78cdda37176f0a63a0a9145c to your computer and use it in GitHub Desktop.
Helper script that creates a sort of Ninite-like experience for Winget
# Load Windows Forms assembly for confirmation dialog
Add-Type -AssemblyName System.Windows.Forms
### Variables
# Array of .NET Desktop Runtime packages
$dotnetDesktopPackages = 5..8 | ForEach-Object { "Microsoft.DotNet.DesktopRuntime.${_}" }
$dotnetRuntimePackages = 5..8 | ForEach-Object { "Microsoft.DotNet.Runtime.${_}" }
# Grouped arrays for applications (with corrected package IDs)
$browsers = @("Mozilla.Firefox", "Google.Chrome", "Vivaldi.Vivaldi", "Waterfox.Waterfox")
$developmentTools = @("Microsoft.VisualStudioCode", "Git.Git", "Python.Python.3.12")
$mediaTools = @("CodecGuide.K-LiteCodecPack.Full", "Gyan.FFmpeg", "yt-dlp.yt-dlp", "Audacity.Audacity", "Nikse.SubtitleEdit", "Streamlink.Streamlink", "VideoLAN.VLC", "Jellyfin.JellyfinMediaPlayer")
$communicationTools = @("SlackTechnologies.Slack", "Discord.Discord", "Beeper.Beeper", "TeamViewer.TeamViewer", "Microsoft.Teams")
$gaming = @("Valve.Steam", "Valve.SteamCMD", "GOG.Galaxy", "HeroicGamesLauncher.HeroicGamesLauncher")
$utilities = @("Rufus.Rufus", "Bitwarden.Bitwarden", "AntibodySoftware.WizTree", "Microsoft.Sysinternals", "Microsoft.PowerToys", "7zip.7zip", "M2Team.NanaZip", "Notepad++.Notepad++", "Dell.CommandUpdate", "WinSCP.WinSCP", "ElaborateBytes.VirtualCloneDrive")
$productivity = @("Microsoft.Office", "TheDocumentFoundation.LibreOffice", "Microsoft.OneDrive", "Google.GoogleDrive", "Splashtop.SplashtopBusiness")
$networkingTools = @("PuTTY.PuTTY", "TeraTermProject.teraterm5", "tailscale.tailscale", "WiresharkFoundation.Wireshark", "Insecure.Npcap")
$vcredistPackages = @("Microsoft.VCLibs.Desktop.14", "Microsoft.VCRedist.2010.x64", "Microsoft.VCRedist.2010.x86", "Microsoft.VCRedist.2012.x64", "Microsoft.VCRedist.2012.x86", "Microsoft.VCRedist.2013.x64", "Microsoft.VCRedist.2013.x86", "Microsoft.VCRedist.2015+.x64", "Microsoft.VCRedist.2015+.x86", "Microsoft.VCRedist.2005.x64", "Microsoft.VCRedist.2005.x86", "Microsoft.VCRedist.2008.x64", "Microsoft.VCRedist.2008.x86")
# Combine all packages by group with labels
$packageGroups = @{
"Browsers" = $browsers
"Development Tools" = $developmentTools
"Media Tools" = $mediaTools
"Communication Tools" = $communicationTools
"Gaming" = $gaming
"Utilities" = $utilities
"Productivity" = $productivity
"Networking Tools" = $networkingTools
"Visual C++ Redistributables" = $vcredistPackages
".NET Desktop Runtime" = $dotnetDesktopPackages
".NET Runtime" = $dotnetRuntimePackages
}
### Functions
# Function to check if the script is running as Administrator
function Check-Admin {
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Output "This script is not running as Administrator."
$adminPrompt = Read-Host "Would you like to relaunch as Administrator? (y/n)"
if ($adminPrompt -eq 'y') {
# Relaunch the script with elevated permissions
Write-Output "Relaunching script as Administrator..."
Start-Process -FilePath "powershell" -ArgumentList "-File `"$PSCommandPath`"" -Verb RunAs
exit
} else {
Write-Output "Some installations may require Administrator privileges. Continuing without elevation..."
}
} else {
Write-Output "Running with Administrator privileges."
}
}
# Function to check if PowerShell 7 or newer is installed and relaunch the script using it
function Check-And-Relaunch-PowerShellCore {
if ($PSVersionTable.PSVersion.Major -lt 7) {
Write-Output "You're running Windows PowerShell (version $($PSVersionTable.PSVersion.Major))."
# Check if PowerShell 7 or newer is already installed
$newPSPath = "$env:ProgramFiles\PowerShell\7\pwsh.exe"
if (Test-Path $newPSPath) {
Write-Output "PowerShell 7 or newer is already installed. Relaunching the script using PowerShell Core..."
Start-Process -FilePath $newPSPath -ArgumentList "-File `"$PSCommandPath`"" -NoNewWindow
exit
} else {
# Prompt to install PowerShell Core if not found
$installPrompt = Read-Host "Would you like to install the latest version of PowerShell Core using winget? (y/n)"
if ($installPrompt -eq 'y') {
# Install PowerShell using winget
Write-Output "Installing PowerShell via winget..."
winget install --id Microsoft.Powershell --source winget
# Confirm installation and relaunch script
if (Test-Path $newPSPath) {
Write-Output "PowerShell installed successfully. Relaunching script in PowerShell Core..."
Start-Process -FilePath $newPSPath -ArgumentList "-File `"$PSCommandPath`"" -NoNewWindow
exit
} else {
Write-Output "Failed to install PowerShell via winget. Please try installing manually."
exit
}
}
}
}
else {
Write-Output "You're running PowerShell Core version $($PSVersionTable.PSVersion.Major), continuing..."
}
}
# Function to check and install Desktop App Installer / winget if necessary
function Check-And-Install-Winget {
if (!(Get-Command winget -ErrorAction SilentlyContinue)) {
Write-Output "winget is not installed on this system."
$installPrompt = Read-Host "Would you like to install the Desktop App Installer (winget)? (y/n)"
if ($installPrompt -eq 'y') {
# Download the Desktop App Installer package
$installerUrl = "https://aka.ms/MicrosoftDesktopAppInstaller"
$installerPath = "$env:TEMP\DesktopAppInstaller.appxbundle"
Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath
# Install the Desktop App Installer package
Write-Output "Installing Desktop App Installer (winget)..."
Add-AppxPackage -Path $installerPath
# Verify installation
if (Get-Command winget -ErrorAction SilentlyContinue) {
Write-Output "winget installed successfully."
} else {
Write-Output "Failed to install winget. Please try installing manually."
exit
}
} else {
Write-Output "winget is required to run this script. Exiting..."
exit
}
}
else {
Write-Output "winget is available on this system."
}
}
# Function to install packages with error handling and success confirmation
function Install-Package {
param (
[string]$packageId
)
Write-Output "Preparing to install package: ${packageId}" # Debugging output
try {
Write-Output "Executing command: winget install --id ${packageId} -e"
$installProcess = Start-Process -FilePath "winget" -ArgumentList "install --id ${packageId} -e" -NoNewWindow -PassThru -Wait
# Check if installation was successful based on exit code
if ($installProcess.ExitCode -eq 0) {
Write-Output "${packageId} installed successfully."
} else {
Write-Output "Error installing ${packageId}: Exit code $($installProcess.ExitCode)"
}
}
catch {
Write-Output "Error installing ${packageId}: ${_}"
}
}
### Main Script execution
# Run the admin check
Check-Admin
# Run the PowerShell version check and relaunch if necessary
Check-And-Relaunch-PowerShellCore
# Run the winget check
Check-And-Install-Winget
# Run `winget list` once and store the output as an array of lines
$installedPackagesOutput = winget list
# Function to check if a package is installed by looking for a matching line in the output
function Is-PackageInstalled {
param ($packageId, $installedPackagesOutput)
return $installedPackagesOutput | Select-String -SimpleMatch $packageId
}
# Create a list with both group and individual package options, marking installed packages
$menuOptions = @()
foreach ($groupName in $packageGroups.Keys) {
# Add group item
$menuOptions += [PSCustomObject]@{ Name = "${groupName} (All)"; Type = "Group"; Installed = ""; Packages = $packageGroups[$groupName] }
# Add individual items, checking each package installation status
foreach ($package in $packageGroups[$groupName]) {
$isInstalled = if (Is-PackageInstalled -packageId $package -installedPackagesOutput $installedPackagesOutput) { "Y" } else { "" }
$menuOptions += [PSCustomObject]@{ Name = $package; Type = "Individual"; Installed = $isInstalled; Packages = @($package) }
}
}
# Show interactive menu to select groups or individual packages with installation status
$selectedItems = $menuOptions | Out-GridView -Title "Select Groups or Individual Packages to Install (Ctrl for multiple)" -PassThru
# Check if user made selections
if ($selectedItems) {
# Prepare list of selected package names for confirmation
$selectedpackageIds = $selectedItems | ForEach-Object { $_.Packages } | ForEach-Object { $_ } | Sort-Object | Get-Unique
$selectedText = $selectedpackageIds -join "`r`n"
# Confirmation popup with list of selected packages
$confirmationForm = New-Object Windows.Forms.Form
$confirmationForm.Text = "Confirm Selection"
$confirmationForm.Size = New-Object System.Drawing.Size(400,300)
$confirmationForm.StartPosition = "CenterScreen"
$textBox = New-Object Windows.Forms.TextBox
$textBox.Multiline = $true
$textBox.ReadOnly = $true
$textBox.Dock = "Fill"
$textBox.Text = "You selected the following packages:`r`n`r`n$selectedText"
$confirmationForm.Controls.Add($textBox)
$okButton = New-Object Windows.Forms.Button
$okButton.Text = "OK"
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$okButton.Dock = "Bottom"
$confirmationForm.Controls.Add($okButton)
$cancelButton = New-Object Windows.Forms.Button
$cancelButton.Text = "Cancel"
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$cancelButton.Dock = "Bottom"
$confirmationForm.Controls.Add($cancelButton)
$confirmationForm.AcceptButton = $okButton
$confirmationForm.CancelButton = $cancelButton
$dialogResult = $confirmationForm.ShowDialog()
# Process user's confirmation choice
if ($dialogResult -eq [System.Windows.Forms.DialogResult]::OK) {
Write-Output "You confirmed the following packages for installation:"
$selectedpackageIds | ForEach-Object { Write-Output "- $_" }
# Install each confirmed package
foreach ($package in $selectedpackageIds) {
Write-Output "Attempting to install package: ${package}" # Debugging output
Install-Package -packageId $package
}
} else {
Write-Output "Installation canceled by user."
}
} else {
Write-Output "No selection made. Exiting..."
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment