Skip to content

Instantly share code, notes, and snippets.

@ergosteur
Created February 19, 2026 18:19
Show Gist options
  • Select an option

  • Save ergosteur/e46e53cfd9784506d7b60b69dc7d3dee to your computer and use it in GitHub Desktop.

Select an option

Save ergosteur/e46e53cfd9784506d7b60b69dc7d3dee to your computer and use it in GitHub Desktop.
Repairs and configures Winget for enterprise environments (Intune/SCCM/RMM) with unified Standalone/Detect/Remediate modes.
<#
.SYNOPSIS
Repairs and configures Winget for enterprise environments (Intune/SCCM/RMM) with unified Standalone/Detect/Remediate modes.
.DESCRIPTION
This script is designed to be used in three modes, controlled by the $ExecutionMode variable:
$ExecutionMode = "Standalone" # For manual/RMM/SCCM use (default)
$ExecutionMode = "Detect" # For Intune detection scripts
$ExecutionMode = "Remediate" # For Intune remediation scripts
- Standalone:
Runs full repair logic with SYSTEM-aware defaults, logging, and no special exit codes.
- Detect:
Runs health checks only (no changes), and exits:
0 = Winget is healthy
1 = Winget needs remediation
- Remediate:
Runs full repair logic and exits:
0 = Remediation succeeded
1 = Remediation failed
When running as SYSTEM (Intune/SCCM default), the script automatically applies
enterprise-safe defaults unless explicitly overridden via parameters:
-AllUsers:$true
-ProvisionForNewUsers:$true
-DisableMsStoreSource:$true
-ResetSources:$true
-Force:$true
-Silent:$true
All parameters can be explicitly overridden, even in SYSTEM context.
.PARAMETER WhatIf
Simulates actions without making changes (primarily for Standalone mode).
.PARAMETER Silent
Suppresses non-error output. Automatically enabled in SYSTEM context unless overridden.
.PARAMETER Force
Reapplies all fixes even if they appear correct. Automatically enabled in SYSTEM context.
.PARAMETER AllUsers
Applies PATH and Winget settings to all user profiles. Automatically enabled in SYSTEM context.
.PARAMETER ProvisionForNewUsers
Applies PATH and Winget settings to the default profile (C:\Users\Default).
Automatically enabled in SYSTEM context.
.PARAMETER ResetSources
Resets all Winget sources before applying configuration.
Automatically enabled in SYSTEM context.
.PARAMETER DisableMsStoreSource
Disables the msstore Winget source (default: $true).
Automatically enabled in SYSTEM context unless overridden.
.PARAMETER LogFile
Optional log file path. If not provided and running as SYSTEM,
defaults to: C:\ProgramData\WingetRepair\WingetRepair.log
.EXAMPLE
# Standalone / RMM / SCCM
$ExecutionMode = "Standalone"
.\Repair-Winget.ps1 -LogFile "C:\ProgramData\WingetRepair\WingetRepair.log"
.EXAMPLE
# Intune Detect script
$ExecutionMode = "Detect"
.\Repair-Winget.ps1
.EXAMPLE
# Intune Remediate script
$ExecutionMode = "Remediate"
.\Repair-Winget.ps1
#>
# -------------------------------
# Parameter definitions
# -------------------------------
param(
[switch]$Simulate,
[switch]$Silent,
[switch]$Force,
[switch]$AllUsers,
[switch]$ProvisionForNewUsers,
[switch]$ResetSources,
[bool]$DisableMsStoreSource = $true,
[string]$LogFile
)
# -------------------------------
# USER-ADJUSTABLE EXECUTION MODE
# -------------------------------
# Valid values: "Standalone", "Detect", "Remediate"
if (-not $ExecutionMode) {
$ExecutionMode = "Standalone"
}
# -------------------------------
# Detect SYSTEM context
# -------------------------------
$IsSystem = $env:USERNAME -eq "SYSTEM"
# -------------------------------
# Apply SYSTEM defaults (Option A)
# -------------------------------
if ($IsSystem) {
if (-not $PSBoundParameters.ContainsKey("Silent")) { $Silent = $true }
if (-not $PSBoundParameters.ContainsKey("Force")) { $Force = $true }
if (-not $PSBoundParameters.ContainsKey("AllUsers")) { $AllUsers = $true }
if (-not $PSBoundParameters.ContainsKey("ProvisionForNewUsers")) { $ProvisionForNewUsers = $true }
if (-not $PSBoundParameters.ContainsKey("ResetSources")) { $ResetSources = $true }
if (-not $PSBoundParameters.ContainsKey("DisableMsStoreSource")) { $DisableMsStoreSource = $true }
if (-not $PSBoundParameters.ContainsKey("LogFile")) {
$logDir = "C:\ProgramData\WingetRepair"
if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir | Out-Null }
$LogFile = "$logDir\WingetRepair.log"
}
}
# -------------------------------
# Logging helpers
# -------------------------------
function Write-Log($msg) {
if ($LogFile) {
Add-Content -Path $LogFile -Value ("[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $msg")
}
}
function Write-Info($msg) {
Write-Log $msg
if (-not $Silent) { Write-Host $msg -ForegroundColor Cyan }
}
function Write-Warn($msg) {
Write-Log "WARNING: $msg"
if (-not $Silent) { Write-Host $msg -ForegroundColor Yellow }
}
function Write-Good($msg) {
Write-Log $msg
if (-not $Silent) { Write-Host $msg -ForegroundColor Green }
}
Write-Info "=== Winget Repair Script Starting ==="
Write-Info ("ExecutionMode: " + $ExecutionMode)
Write-Info ("Running as: " + $env:USERNAME)
# -------------------------------
# Fix PATH for a user profile
# -------------------------------
function Fix-UserPath {
param(
[string]$UserProfile
)
$windowsApps = "$UserProfile\AppData\Local\Microsoft\WindowsApps"
$currentPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($Force -or $currentPath -notlike "*$windowsApps*") {
Write-Info "Adding WindowsApps to PATH for $UserProfile"
if (-not $Simulate) {
$newPath = $currentPath + ";" + $windowsApps
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
}
} else {
Write-Info "WindowsApps already present in PATH for $UserProfile"
}
}
# -------------------------------
# Test Winget health (for Detect mode)
# -------------------------------
function Test-WingetHealth {
Write-Info "Testing Winget health..."
# 1. Check App Installer
$appInstaller = Get-AppxPackage Microsoft.DesktopAppInstaller -ErrorAction SilentlyContinue
if (-not $appInstaller) {
Write-Warn "Health check failed: App Installer is missing."
return $false
}
# 2. Check winget command
try {
$v = winget --version
if (-not $v) {
Write-Warn "Health check failed: winget --version returned no output."
return $false
}
} catch {
Write-Warn "Health check failed: winget command not working."
return $false
}
# 3. Check msstore source state if we expect it disabled
if ($DisableMsStoreSource) {
try {
$sources = winget source list
if ($sources -match "msstore" -and $sources -notmatch "Disabled") {
Write-Warn "Health check failed: msstore source is not disabled."
return $false
}
} catch {
Write-Warn "Health check: unable to query sources, assuming unhealthy."
return $false
}
}
Write-Good "Winget health check passed."
return $true
}
# -------------------------------
# Full repair logic
# -------------------------------
function Repair-Winget {
Write-Info "Starting full Winget repair..."
# Apply PATH fixes
if ($AllUsers) {
Write-Info "Applying PATH fix to all user profiles..."
$profiles = Get-ChildItem "C:\Users" | Where-Object { $_.PSIsContainer }
foreach ($p in $profiles) {
Fix-UserPath -UserProfile $p.FullName
}
} else {
Fix-UserPath -UserProfile $env:USERPROFILE
}
# Provision default profile
if ($ProvisionForNewUsers) {
$defaultProfile = "C:\Users\Default"
Write-Info "Provisioning default profile at $defaultProfile"
Fix-UserPath -UserProfile $defaultProfile
}
# Ensure App Installer exists
$appInstaller = Get-AppxPackage Microsoft.DesktopAppInstaller -ErrorAction SilentlyContinue
if (-not $appInstaller) {
Write-Warn "App Installer is missing. Cannot repair in headless mode. Exiting."
return $false
}
Write-Info "App Installer found: $($appInstaller.Version)"
# Re-register App Installer
Write-Info "Re-registering App Installer..."
if (-not $Simulate) {
try {
Add-AppxPackage -Register "$($appInstaller.InstallLocation)\AppxManifest.xml" -DisableDevelopmentMode -ErrorAction Stop
}
catch {
Write-Warn "Re-register failed (App Installer likely in use). Continuing..."
}
}
# Reset Winget sources
if ($ResetSources) {
Write-Info "Resetting Winget sources..."
if (-not $Simulate) {
winget source reset --force
}
}
# Configure msstore source
if ($DisableMsStoreSource) {
Write-Info "Disabling msstore source..."
if (-not $Simulate) {
winget source disable msstore
}
} else {
Write-Info "Enabling msstore source..."
if (-not $Simulate) {
winget source enable msstore
}
}
# Winget settings
Write-Info "Enabling certificate pinning bypass..."
if (-not $Simulate) {
winget settings --enable BypassCertificatePinningForMicrosoftStore
}
Write-Info "Accepting agreements..."
if (-not $Simulate) {
winget source update
winget list --accept-source-agreements --accept-package-agreements | Out-Null
}
# Upgrade App Installer
Write-Info "Upgrading App Installer from winget source..."
if (-not $Simulate) {
winget upgrade Microsoft.AppInstaller --source winget --include-unknown --accept-source-agreements --accept-package-agreements
}
# Verify winget
Write-Info "Testing winget after repair..."
try {
if (-not $Simulate) {
$v = winget --version
Write-Good "Winget is working: $v"
}
} catch {
Write-Warn "Winget still not responding after repair."
return $false
}
Write-Info "Winget repair completed successfully."
return $true
}
# -------------------------------
# Mode dispatch
# -------------------------------
switch ($ExecutionMode.ToLower()) {
"detect" {
$healthy = Test-WingetHealth
if ($healthy) {
Write-Info "Detect mode: Winget is healthy. Exiting with code 0."
exit 0
} else {
Write-Warn "Detect mode: Winget is NOT healthy. Exiting with code 1."
exit 1
}
}
"remediate" {
$result = Repair-Winget
if ($result) {
Write-Info "Remediate mode: Repair succeeded. Exiting with code 0."
exit 0
} else {
Write-Warn "Remediate mode: Repair failed. Exiting with code 1."
exit 1
}
}
default {
# Standalone / RMM / SCCM mode
$result = Repair-Winget
if ($result) {
Write-Info "Standalone mode: Repair completed."
exit 0
} else {
Write-Warn "Standalone mode: Repair encountered issues."
exit 1
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment