Skip to content

Commit 7285bb5

Browse files
committed
Add winget-update powershell
1 parent 751a3f7 commit 7285bb5

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
Set-ExecutionPolicy Bypass -Scope Process -Force
2+
Clear-Host
3+
4+
<#
5+
.SYNOPSIS
6+
Quietly updates all Microsoft Store apps using winget (v1.11.x compatible).
7+
8+
.DESCRIPTION
9+
- Runs fully non-interactive (no prompts).
10+
- Properly orders command + flags for winget 1.11.x.
11+
- Accepts msstore/package agreements on upgrade/install only.
12+
- Uses include-unknown and a forced second pass to catch stubborn Store apps.
13+
- Detects if winget/App Installer updated itself mid-run and retries once.
14+
- Executes winget by absolute path (no App Execution Alias quirks).
15+
- Logs to C:\ProgramData\Winget-StoreUpgrade\upgrade-YYYYMMDD-HHMMSS.log
16+
17+
.NOTES
18+
Recommended to run in an elevated session to service machine-wide apps.
19+
#>
20+
21+
# ===== Global non-interactive settings =====
22+
$ErrorActionPreference = 'Stop'
23+
$ProgressPreference = 'SilentlyContinue'
24+
$env:WINGET_DISABLE_INTERACTIVITY = '1' # environment-based; no CLI side effects
25+
26+
# ===== Logging =====
27+
$LogRoot = Join-Path $env:ProgramData 'Winget-StoreUpgrade'
28+
if (-not (Test-Path $LogRoot)) { New-Item -Path $LogRoot -ItemType Directory -Force | Out-Null }
29+
$Timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
30+
$LogFile = Join-Path $LogRoot "upgrade-$Timestamp.log"
31+
32+
function Write-Info { param([string]$m) "[INFO ] $m" | Tee-Object -FilePath $LogFile -Append }
33+
function Write-Warn { param([string]$m) "[WARN ] $m" | Tee-Object -FilePath $LogFile -Append }
34+
function Write-Err { param([string]$m) "[ERROR] $m" | Tee-Object -FilePath $LogFile -Append }
35+
36+
Write-Info "Log file: $LogFile"
37+
Write-Info "Starting Microsoft Store updates..."
38+
39+
# ===== Robust winget resolution and invoker =====
40+
function Resolve-WinGetExe {
41+
# Prefer packaged App Installer location (more stable than user alias)
42+
$pkg = Get-AppxPackage -Name Microsoft.DesktopAppInstaller -ErrorAction SilentlyContinue
43+
if ($pkg) {
44+
$candidate = Join-Path $pkg.InstallLocation 'winget.exe'
45+
if (Test-Path $candidate) { return $candidate }
46+
}
47+
# Fallback to whatever PowerShell resolves
48+
return (Get-Command winget.exe -ErrorAction Stop).Source
49+
}
50+
51+
$script:WinGetExe = Resolve-WinGetExe
52+
53+
function Invoke-WinGet {
54+
param(
55+
[Parameter(Mandatory)][string[]]$Args, # e.g. @('upgrade','--all',...)
56+
[switch]$RetryOnSelfUpdate # retry once if winget self-updated
57+
)
58+
# Execute the EXE directly — do NOT call 'winget' then pass a path
59+
$output = & $script:WinGetExe @Args 2>&1
60+
$text = $output | Out-String
61+
$text | Tee-Object -FilePath $LogFile -Append | Out-Null
62+
63+
if ($RetryOnSelfUpdate -and $text -match 'Restart the application to complete the upgrade') {
64+
Write-Info "winget/App Installer updated itself; re-resolving path and retrying once..."
65+
Start-Sleep -Milliseconds 500
66+
$script:WinGetExe = Resolve-WinGetExe
67+
$output = & $script:WinGetExe @Args 2>&1
68+
$text = $output | Out-String
69+
$text | Tee-Object -FilePath $LogFile -Append | Out-Null
70+
}
71+
return $text
72+
}
73+
74+
# ===== Preflight: confirm winget exists =====
75+
try {
76+
Invoke-WinGet -Args @('--version') | Out-Null
77+
} catch {
78+
Write-Err "winget (App Installer) not found. Install/update 'App Installer' from Microsoft Store and re-run."
79+
exit 1
80+
}
81+
82+
# ===== Ensure Microsoft Store Install Service is running (helps Store updates) =====
83+
try {
84+
$svc = Get-Service -Name InstallService -ErrorAction SilentlyContinue
85+
if ($svc -and $svc.Status -ne 'Running') {
86+
Write-Info "Starting Microsoft Store Install Service (InstallService)..."
87+
Start-Service -Name InstallService -ErrorAction SilentlyContinue
88+
}
89+
} catch { Write-Warn "Could not verify/start InstallService. Continuing..." }
90+
91+
# ===== Ensure msstore source exists and refresh (NO accept flags here) =====
92+
try {
93+
$sources = Invoke-WinGet -Args @('source','list','--disable-interactivity')
94+
if ($sources -notmatch '(?im)^\s*msstore\b') {
95+
Write-Info "msstore source not found; resetting..."
96+
Invoke-WinGet -Args @('source','reset','--force','msstore','--disable-interactivity')
97+
}
98+
Invoke-WinGet -Args @('source','update','--disable-interactivity') | Out-Null
99+
} catch {
100+
Write-Warn "Winget source operations reported issues; continuing..."
101+
}
102+
103+
# ===== Optional: prevent winget self-upgrade during the session (pin App Installer) =====
104+
# (Uncomment if you want to avoid mid-run self-update entirely)
105+
# Invoke-WinGet -Args @('pin','add','--id','Microsoft.AppInstaller','--disable-interactivity') | Out-Null
106+
107+
# ===== PASS 1: Accept msstore terms & upgrade what winget can detect =====
108+
Write-Info "Pass 1: upgrading Microsoft Store apps (include-unknown)..."
109+
Invoke-WinGet -Args @(
110+
'upgrade','--all',
111+
'--source','msstore',
112+
'--include-unknown',
113+
'--silent',
114+
'--accept-source-agreements','--accept-package-agreements',
115+
'--disable-interactivity'
116+
) -RetryOnSelfUpdate | Out-Null
117+
118+
# ===== PASS 2: Force re-install latest for stragglers where version compare is unknown =====
119+
Write-Info "Pass 2: forced upgrade (msstore) for remaining/unknown version apps..."
120+
Invoke-WinGet -Args @(
121+
'upgrade','--all',
122+
'--source','msstore',
123+
'--include-unknown',
124+
'--force',
125+
'--silent',
126+
'--accept-source-agreements','--accept-package-agreements',
127+
'--disable-interactivity'
128+
) -RetryOnSelfUpdate | Out-Null
129+
130+
# ===== OPTIONAL Safety net pass: catch apps mapped under other sources =====
131+
Write-Info "Safety net: unfiltered pass to catch any remaining packages..."
132+
Invoke-WinGet -Args @(
133+
'upgrade','--all',
134+
'--include-unknown',
135+
'--silent',
136+
'--accept-source-agreements','--accept-package-agreements',
137+
'--disable-interactivity'
138+
) -RetryOnSelfUpdate | Out-Null
139+
140+
# ===== Summary: show any remaining Store upgrades (no accept flags here) =====
141+
Write-Info "Summary check for remaining Microsoft Store upgrades..."
142+
Invoke-WinGet -Args @('upgrade','--source','msstore','--disable-interactivity') | Out-Null
143+
144+
# ===== Optional: unpin App Installer after run =====
145+
# Invoke-WinGet -Args @('pin','remove','--id','Microsoft.AppInstaller','--disable-interactivity') | Out-Null
146+
147+
Write-Info "Completed. Full log: $LogFile"

0 commit comments

Comments
 (0)