Created
March 6, 2026 01:25
-
-
Save rlorenzo/5308b14a8ddc34e0f08078072fea3ebd to your computer and use it in GitHub Desktop.
Script to update all global packages for Volta on Windows via Powershell
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
| #requires -Version 7.0 | |
| Set-StrictMode -Version Latest | |
| $ErrorActionPreference = 'Stop' | |
| function Get-VoltaListAllPlainText { | |
| (& volta list all --format plain 2>&1 | Out-String) | |
| } | |
| function Get-VoltaPackagesFromPlain { | |
| $text = Get-VoltaListAllPlainText | |
| if (-not $text) { return @{} } | |
| $packages = [ordered]@{} | |
| foreach ($line in ($text -split "(`r`n|`n|`r)")) { | |
| $t = $line.Trim() | |
| if (-not $t) { continue } | |
| # plain format example: | |
| # package @scope/name@1.2.3 (default) | |
| # package name@1.2.3 (default) | |
| if ($t -match '^package\s+(.+?)@([0-9][0-9A-Za-z\.\-\+_]*)\b') { | |
| $name = $matches[1] | |
| $ver = $matches[2] | |
| $packages[$name] = $ver | |
| } | |
| } | |
| return $packages | |
| } | |
| function Get-NpmLatestVersion { | |
| param([Parameter(Mandatory)][string]$PackageName) | |
| try { | |
| $v = & npm view $PackageName version 2>$null | |
| if ($v) { return $v.ToString().Trim() } | |
| } catch { | |
| # ignore | |
| } | |
| return $null | |
| } | |
| function Try-ParseSemVer { | |
| param([Parameter(Mandatory)][string]$Version) | |
| try { | |
| return [System.Management.Automation.SemanticVersion]::Parse($Version) | |
| } catch { | |
| return $null | |
| } | |
| } | |
| function Invoke-VoltaInstallLatest { | |
| param([Parameter(Mandatory)][string]$PackageName) | |
| $psi = [System.Diagnostics.ProcessStartInfo]::new() | |
| $psi.FileName = 'volta' | |
| $psi.RedirectStandardOutput = $true | |
| $psi.RedirectStandardError = $true | |
| $psi.UseShellExecute = $false | |
| # PowerShell 7: ArgumentList exists and handles escaping | |
| $psi.ArgumentList.Add('install') | Out-Null | |
| $psi.ArgumentList.Add("$PackageName@latest") | Out-Null | |
| $p = [System.Diagnostics.Process]::new() | |
| $p.StartInfo = $psi | |
| [void]$p.Start() | |
| while (-not $p.HasExited) { | |
| while (-not $p.StandardOutput.EndOfStream) { Write-Output $p.StandardOutput.ReadLine() } | |
| while (-not $p.StandardError.EndOfStream) { Write-Error $p.StandardError.ReadLine() } | |
| Start-Sleep -Milliseconds 50 | |
| } | |
| while (-not $p.StandardOutput.EndOfStream) { Write-Output $p.StandardOutput.ReadLine() } | |
| while (-not $p.StandardError.EndOfStream) { Write-Error $p.StandardError.ReadLine() } | |
| return $p.ExitCode | |
| } | |
| Write-Output "Gathering Volta-managed global packages..." | |
| $initial = Get-VoltaPackagesFromPlain | |
| $names = @($initial.Keys) | |
| if ($names.Length -eq 0) { | |
| Write-Output "No Volta-managed global packages found." | |
| exit 0 | |
| } | |
| $total = $names.Length | |
| $current = 0 | |
| $skipped = New-Object System.Collections.Generic.List[string] | |
| $updated = New-Object System.Collections.Generic.List[string] | |
| $failed = New-Object System.Collections.Generic.List[string] | |
| foreach ($pkg in $names) { | |
| $current++ | |
| $percent = [int](($current / $total) * 100) | |
| $status = "Processing $pkg ($current of $total)" | |
| Write-Progress -Activity "Updating Volta global packages" -Status $status -PercentComplete $percent | |
| $installedStr = $initial[$pkg] | |
| $latestStr = Get-NpmLatestVersion -PackageName $pkg | |
| if (-not $latestStr) { | |
| Write-Warning ("Could not determine latest npm version for {0}, skipping." -f $pkg) | |
| $skipped.Add($pkg) | Out-Null | |
| continue | |
| } | |
| $installed = Try-ParseSemVer -Version $installedStr | |
| $latest = Try-ParseSemVer -Version $latestStr | |
| Write-Output "" | |
| Write-Output ("=== {0} ===" -f $status) | |
| Write-Output ("Installed: {0}" -f $installedStr) | |
| Write-Output ("Latest: {0}" -f $latestStr) | |
| if ($installed -and $latest) { | |
| if ($installed -ge $latest) { | |
| Write-Output ("Skipping {0}, already up to date." -f $pkg) | |
| $skipped.Add($pkg) | Out-Null | |
| continue | |
| } | |
| } else { | |
| # If SemVer parse fails, fall back to string equality only | |
| if ($installedStr -eq $latestStr) { | |
| Write-Output ("Skipping {0}, already up to date." -f $pkg) | |
| $skipped.Add($pkg) | Out-Null | |
| continue | |
| } | |
| } | |
| $exit = Invoke-VoltaInstallLatest -PackageName $pkg | |
| if ($exit -ne 0) { | |
| Write-Error ("volta install {0}@latest failed with exit code {1}" -f $pkg, $exit) | |
| $failed.Add($pkg) | Out-Null | |
| continue | |
| } | |
| $after = Get-VoltaPackagesFromPlain | |
| $newStr = $after[$pkg] | |
| if (-not $newStr) { $newStr = "unknown" } | |
| Write-Output ("Updated {0}: {1} -> {2}" -f $pkg, $installedStr, $newStr) | |
| $updated.Add($pkg) | Out-Null | |
| } | |
| Write-Progress -Activity "Updating Volta global packages" -Completed | |
| Write-Output "" | |
| Write-Output ("Processed: {0}" -f $total) | |
| Write-Output ("Updated: {0}" -f $updated.Count) | |
| Write-Output ("Skipped: {0}" -f $skipped.Count) | |
| Write-Output ("Failed: {0}" -f $failed.Count) | |
| if ($failed.Count -gt 0) { | |
| Write-Error "Failed packages:" | |
| $failed | ForEach-Object { Write-Error (" {0}" -f $_) } | |
| exit 1 | |
| } | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment