Last active
August 6, 2025 02:00
-
-
Save minanagehsalalma/01a76c768db6b3c7246e8b7bc26c3e2f to your computer and use it in GitHub Desktop.
Enable MANIFEST V2 by pinning chrome version 138
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
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true)] | |
[string]$PortableDir, # e.g. C:\Users\ASUS\Downloads\Compressed\GoogleChromePortable | |
[string]$ProfileDir = "C:\Chrome138Profile", | |
[switch]$DisableUpdater # Optional: stop & disable Google Update services/tasks | |
) | |
$ErrorActionPreference = 'Stop' | |
function Require-Admin { | |
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { | |
throw "Run this in an elevated PowerShell window (Run as Administrator)." | |
} | |
} | |
function Stop-Chrome { | |
Get-Process chrome -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue | |
Start-Sleep -Seconds 2 | |
} | |
function Try-UninstallBySetup($basePath) { | |
$setup = Join-Path $basePath 'Installer\setup.exe' | |
if (Test-Path $setup) { | |
try { & $setup --uninstall --multi-install --chrome --force-uninstall | Out-Null } catch {} | |
} | |
} | |
function Uninstall-SystemChrome { | |
Write-Host "Uninstalling Chrome Stable/Dev/Canary (machine + user) ..." | |
# Common install roots (machine) | |
@( | |
"$env:ProgramFiles\Google\Chrome\Application", | |
"$env:ProgramFiles(x86)\Google\Chrome\Application", | |
"$env:ProgramFiles\Google\Chrome Dev\Application", | |
"$env:ProgramFiles(x86)\Google\Chrome Dev\Application" | |
) | ForEach-Object { | |
if (Test-Path $_) { Try-UninstallBySetup (Split-Path -Parent $_) } | |
} | |
# User-level installs (Stable/Canary/SxS) | |
@( | |
"$env:LocalAppData\Google\Chrome\Application", | |
"$env:LocalAppData\Google\Chrome SxS\Application" | |
) | ForEach-Object { | |
if (Test-Path $_) { Try-UninstallBySetup (Split-Path -Parent $_) } | |
} | |
# Fallback: Use Uninstall registry to catch odd cases | |
$regPaths = @( | |
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', | |
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*', | |
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | |
) | |
foreach ($rp in $regPaths) { | |
Get-ItemProperty $rp -ErrorAction SilentlyContinue | | |
Where-Object { $_.DisplayName -match 'Google Chrome' -or $_.DisplayName -match 'Chrome Canary' -or $_.DisplayName -match 'Chrome Dev' } | | |
ForEach-Object { | |
$cmd = $_.UninstallString | |
if ($cmd) { | |
try { | |
if ($cmd -match 'msiexec') { | |
# Normalize MSI quiet flags | |
& cmd.exe /c "$cmd /qn /norestart" | Out-Null | |
} else { | |
& cmd.exe /c "$cmd --force-uninstall" | Out-Null | |
} | |
} catch {} | |
} | |
} | |
} | |
# Remove leftovers | |
@( | |
"$env:LocalAppData\Google\Chrome SxS", | |
"$env:LocalAppData\Google\Chrome\Application", | |
"$env:LocalAppData\Google\Update", | |
"$env:ProgramData\Google\Update" | |
) | ForEach-Object { | |
try { if (Test-Path $_) { Remove-Item $_ -Recurse -Force -ErrorAction SilentlyContinue } } catch {} | |
} | |
} | |
function Toggle-GoogleUpdater([bool]$disable) { | |
$svc = @('gupdate','gupdatem') | |
foreach ($s in $svc) { | |
try { | |
if ($disable) { | |
Stop-Service $s -ErrorAction SilentlyContinue | |
Set-Service $s -StartupType Disabled -ErrorAction SilentlyContinue | |
} else { | |
Set-Service $s -StartupType Manual -ErrorAction SilentlyContinue | |
Start-Service $s -ErrorAction SilentlyContinue | |
} | |
} catch {} | |
} | |
try { | |
$tasks = Get-ScheduledTask -TaskPath "\Google\" -ErrorAction SilentlyContinue | |
if ($tasks) { | |
if ($disable) { $tasks | Disable-ScheduledTask -ErrorAction SilentlyContinue | Out-Null } | |
else { $tasks | Enable-ScheduledTask -ErrorAction SilentlyContinue | Out-Null } | |
} | |
} catch {} | |
} | |
function Enable-MV2Policy { | |
$chromePol = 'HKLM:\SOFTWARE\Policies\Google\Chrome' | |
New-Item $chromePol -Force | Out-Null | |
New-ItemProperty $chromePol -Name 'ExtensionManifestV2Availability' -PropertyType DWord -Value 2 -Force | Out-Null | |
Write-Host "MV2 policy set (HKLM): ExtensionManifestV2Availability=2" | |
} | |
function Find-PortableChromeExe([string]$root) { | |
$exe = Get-ChildItem -Path $root -Filter chrome.exe -Recurse -ErrorAction SilentlyContinue | | |
Sort-Object FullName | Select-Object -First 1 | |
if (-not $exe) { throw "chrome.exe not found under $root" } | |
return $exe.FullName | |
} | |
function Ensure-ProfileDir([string]$dir) { | |
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } | |
} | |
function New-DesktopShortcut([string]$exe, [string]$profile) { | |
$ws = New-Object -ComObject WScript.Shell | |
$desktop = [Environment]::GetFolderPath('Desktop') | |
$lnk = Join-Path $desktop 'Chrome 138 (Portable MV2).lnk' | |
$sc = $ws.CreateShortcut($lnk) | |
$sc.TargetPath = $exe | |
$sc.Arguments = "--user-data-dir=`"$profile`" --no-first-run" | |
$sc.WorkingDirectory = (Split-Path $exe -Parent) | |
$sc.IconLocation = $exe | |
$sc.Description = "Portable Chrome 138 with MV2 enabled" | |
$sc.Save() | |
Write-Host "Shortcut created: $lnk" | |
} | |
function New-LauncherBat([string]$exe, [string]$profile) { | |
$bat = Join-Path $env:Public 'Desktop\chrome-138-portable-mv2.bat' | |
$content = "@echo off`r`n""$exe"" --user-data-dir=""$profile"" --no-first-run`r`n" | |
Set-Content -Path $bat -Value $content -Encoding ASCII | |
Write-Host "Launcher created: $bat" | |
} | |
# ---------------- MAIN ---------------- | |
Require-Admin | |
Write-Host "Stopping Chrome..." | |
Stop-Chrome | |
if ($DisableUpdater) { | |
Write-Host "Disabling Google Update services & tasks..." | |
Toggle-GoogleUpdater $true | |
} | |
Uninstall-SystemChrome | |
Write-Host "Enabling MV2 policy..." | |
Enable-MV2Policy | |
Write-Host "Configuring portable Chrome 138..." | |
$chromeExe = Find-PortableChromeExe -root $PortableDir | |
$ver = (Get-Item $chromeExe).VersionInfo.FileVersion | |
$major = ($ver -split '\.')[0] | |
Write-Host "Portable Chrome found: $chromeExe" | |
Write-Host "Version detected: $ver" | |
if ([int]$major -ne 138) { | |
Write-Warning "Portable Chrome is major $major, not 138. MV2 will NOT work on 139+. Replace the portable build with a 138 build." | |
} | |
Ensure-ProfileDir -dir $ProfileDir | |
New-DesktopShortcut -exe $chromeExe -profile $ProfileDir | |
New-LauncherBat -exe $chromeExe -profile $ProfileDir | |
if (-not $DisableUpdater) { | |
Write-Host "Re-enabling Google Update services & tasks (you chose not to disable)." | |
Toggle-GoogleUpdater $false | |
} | |
Write-Host "`nAll set." | |
Write-Host "Launch from the desktop shortcut **Chrome 138 (Portable MV2)** or the public desktop .bat." | |
Write-Host "Then in that window:" | |
Write-Host " - chrome://version → confirm major = 138" | |
Write-Host " - chrome://policy → Reload → ExtensionManifestV2Availability = 2 (Status: OK)" | |
Write-Host " - chrome://extensions → Developer mode → Load unpacked your MV2" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
after the install run command
powershell -ExecutionPolicy Bypass -File .\swap-to-portable-chrome138.ps1 -PortableDir "C:\PATHHHHHH\GoogleChromePortable" -ProfileDir "C:\Chrome138Profile" -DisableUpdater
you can get the installer from here
https://portableapps.com/apps/internet/google_chrome_portable