Last active
June 7, 2026 14:30
-
-
Save pszemraj/af5823c756a4cb225d42f364d4622f89 to your computer and use it in GitHub Desktop.
use https://setuserfta.com/ to reassign any extensions that would be opened in Edge to a browser of your choice
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
| <# | |
| .SYNOPSIS | |
| Finds every file type and protocol currently assigned to Microsoft Edge | |
| and reassigns them all to your preferred browser using SetUserFTA. | |
| .DESCRIPTION | |
| Windows protects file associations with a hash -- you can't just edit the | |
| registry. SetUserFTA reverse-engineers that hash so it can set associations | |
| from the command line. | |
| This script: | |
| 1. Locates (or downloads) SetUserFTA | |
| 2. Detects installed browsers and lets you pick one | |
| 3. Finds ALL extensions/protocols currently mapped to any Edge ProgID | |
| 4. Reassigns every single one to your chosen browser | |
| .NOTES | |
| Run from a normal (non-admin) PowerShell terminal. | |
| SetUserFTA operates per-user -- no admin required. | |
| #> | |
| $ErrorActionPreference = "Stop" | |
| # --- 1. Ensure SetUserFTA is available ---------------------------------------- | |
| $setUserFtaDir = "$env:LOCALAPPDATA\SetUserFTA" | |
| $setUserFtaExe = Join-Path $setUserFtaDir "SetUserFTA.exe" | |
| if (-not (Test-Path $setUserFtaExe)) { | |
| Write-Host "`n[*] SetUserFTA not found. Attempting download..." -ForegroundColor Cyan | |
| New-Item -ItemType Directory -Path $setUserFtaDir -Force | Out-Null | |
| $zipUrl = "https://kolbi.cz/SetUserFTA.zip" | |
| $zipPath = Join-Path $setUserFtaDir "SetUserFTA.zip" | |
| try { | |
| Invoke-WebRequest -Uri $zipUrl -OutFile $zipPath -UseBasicParsing | |
| Expand-Archive -Path $zipPath -DestinationPath $setUserFtaDir -Force | |
| Remove-Item $zipPath -Force | |
| # The exe may be nested in a subfolder after extraction | |
| $found = Get-ChildItem -Path $setUserFtaDir -Recurse -Filter "SetUserFTA.exe" | | |
| Where-Object { $_.FullName -notmatch "x86" } | | |
| Select-Object -First 1 | |
| if ($found -and $found.FullName -ne $setUserFtaExe) { | |
| Copy-Item $found.FullName -Destination $setUserFtaExe -Force | |
| } | |
| } | |
| catch { | |
| Write-Host "`n[!] Auto-download failed." -ForegroundColor Red | |
| Write-Host " Download SetUserFTA from: https://setuserfta.com/download-setuserfta/" -ForegroundColor Yellow | |
| Write-Host " Place SetUserFTA.exe in: $setUserFtaDir" -ForegroundColor Yellow | |
| exit 1 | |
| } | |
| } | |
| if (-not (Test-Path $setUserFtaExe)) { | |
| Write-Host "[!] SetUserFTA.exe not found at $setUserFtaExe" -ForegroundColor Red | |
| Write-Host " Download it from https://setuserfta.com/download-setuserfta/ and place it there." -ForegroundColor Yellow | |
| exit 1 | |
| } | |
| Write-Host "[OK] SetUserFTA found: $setUserFtaExe" -ForegroundColor Green | |
| # --- 2. Detect installed browsers --------------------------------------------- | |
| # Map of display name -> ProgID used for file associations | |
| $knownBrowsers = [ordered]@{ | |
| "Google Chrome" = "ChromeHTML" | |
| "Mozilla Firefox" = $null # Firefox ProgIDs have a per-install suffix; detected below | |
| "Brave" = "BraveHTML" | |
| "Vivaldi" = "VivaldiHTM" | |
| "Opera" = "OperaStable" | |
| "Opera GX" = "OperaGXStable" | |
| } | |
| # Detect Firefox's actual ProgID (it includes a hash like FirefoxHTML-308046B0AF4A39CB) | |
| $firefoxProgId = Get-ChildItem "HKCU:\Software\Classes" -ErrorAction SilentlyContinue | | |
| Where-Object { $_.PSChildName -match "^FirefoxHTML-" } | | |
| Select-Object -First 1 -ExpandProperty PSChildName | |
| if (-not $firefoxProgId) { | |
| $firefoxProgId = Get-ChildItem "HKLM:\Software\Classes" -ErrorAction SilentlyContinue | | |
| Where-Object { $_.PSChildName -match "^FirefoxHTML-" } | | |
| Select-Object -First 1 -ExpandProperty PSChildName | |
| } | |
| if ($firefoxProgId) { | |
| $knownBrowsers["Mozilla Firefox"] = $firefoxProgId | |
| } | |
| # Filter to only browsers that are actually registered on this system | |
| $availableBrowsers = [ordered]@{} | |
| foreach ($name in $knownBrowsers.Keys) { | |
| $progId = $knownBrowsers[$name] | |
| if (-not $progId) { continue } | |
| $exists = (Test-Path "HKCU:\Software\Classes\$progId") -or | |
| (Test-Path "HKLM:\Software\Classes\$progId") | |
| if ($exists) { | |
| $availableBrowsers[$name] = $progId | |
| } | |
| } | |
| if ($availableBrowsers.Count -eq 0) { | |
| Write-Host "`n[!] No supported browsers detected." -ForegroundColor Red | |
| Write-Host " Install Chrome, Firefox, Brave, Vivaldi, or Opera first." -ForegroundColor Yellow | |
| exit 1 | |
| } | |
| # --- 3. Let user pick --------------------------------------------------------- | |
| Write-Host "`nDetected browsers:" -ForegroundColor Cyan | |
| $i = 1 | |
| $browserList = @($availableBrowsers.GetEnumerator()) | |
| foreach ($entry in $browserList) { | |
| Write-Host " [$i] $($entry.Key) (ProgID: $($entry.Value))" -ForegroundColor White | |
| $i++ | |
| } | |
| do { | |
| $choice = Read-Host "`nSelect browser [1-$($browserList.Count)]" | |
| } while ($choice -notmatch '^\d+$' -or [int]$choice -lt 1 -or [int]$choice -gt $browserList.Count) | |
| $targetName = $browserList[[int]$choice - 1].Key | |
| $targetProgId = $browserList[[int]$choice - 1].Value | |
| Write-Host "`n[*] Target: $targetName ($targetProgId)" -ForegroundColor Green | |
| # --- 4. Find ALL Edge associations -------------------------------------------- | |
| # Known Edge ProgIDs -- there are several | |
| $edgeProgIds = @( | |
| "MSEdgeHTM" | |
| "MSEdgePDF" | |
| "MSEdgeMHT" | |
| "AppXq0fevzme2pys62n3e0fbqa7peapykr8v" # Edge UWP protocol handler | |
| "AppXd4nrz8ff68srnhf9t5a8sbjyar1cr723" # Edge PDF (UWP variant) | |
| "AppXde74bfzw9j31bzhcvsrxsyjnhhbq66cs" # Edge HTML (UWP variant) | |
| "AppX4hxtad77fbk3jkkeerkrm0ze94wjf3s9" # Edge MHT (UWP variant) | |
| "AppXc6xm04by1gqrb4hhdg9g6tzk09eajvb2" # Edge SVG (UWP variant) | |
| "AppXe1yx5t83bv01c2c6g01m22bhx10ns8y2" # Edge XML (UWP variant) | |
| ) | |
| Write-Host "`n[*] Scanning all current file associations for Edge ProgIDs..." -ForegroundColor Cyan | |
| # Get ALL current associations | |
| $allAssociations = & $setUserFtaExe get 2>&1 | Where-Object { $_ -match "," } | |
| $edgeAssociations = @() | |
| foreach ($line in $allAssociations) { | |
| # Format: .ext, ProgID or protocol, ProgID | |
| if ($line -match "^(.+?),\s*(.+)$") { | |
| $ext = $Matches[1].Trim() | |
| $progId = $Matches[2].Trim() | |
| if ($progId -in $edgeProgIds -or $progId -match "(?i)edge") { | |
| $edgeAssociations += [PSCustomObject]@{ | |
| Extension = $ext | |
| CurrentProgId = $progId | |
| } | |
| } | |
| } | |
| } | |
| if ($edgeAssociations.Count -eq 0) { | |
| Write-Host "`n[*] No file associations currently pointing to Edge. Nothing to do." -ForegroundColor Green | |
| exit 0 | |
| } | |
| Write-Host "`n[!] Found $($edgeAssociations.Count) associations mapped to Edge:" -ForegroundColor Yellow | |
| foreach ($assoc in $edgeAssociations) { | |
| Write-Host (" {0} -> {1}" -f $assoc.Extension, $assoc.CurrentProgId) -ForegroundColor Gray | |
| } | |
| # --- 5. Reassign everything --------------------------------------------------- | |
| Write-Host "`n[*] Reassigning all to $targetName ($targetProgId)...`n" -ForegroundColor Cyan | |
| # Some extensions need a different ProgID (Firefox uses FirefoxURL-* for protocols) | |
| $targetUrlProgId = $targetProgId | |
| if ($targetName -eq "Mozilla Firefox") { | |
| $firefoxUrlProgId = $targetProgId -replace "^FirefoxHTML-", "FirefoxURL-" | |
| $urlExists = (Test-Path "HKCU:\Software\Classes\$firefoxUrlProgId") -or | |
| (Test-Path "HKLM:\Software\Classes\$firefoxUrlProgId") | |
| if ($urlExists) { | |
| $targetUrlProgId = $firefoxUrlProgId | |
| } | |
| } | |
| $protocols = @("http", "https", "ftp", "mailto", "microsoft-edge", "microsoft-edge-holographic", | |
| "read", "ie.http", "ie.https", "ie.ftp") | |
| $successCount = 0 | |
| $failCount = 0 | |
| foreach ($assoc in $edgeAssociations) { | |
| $ext = $assoc.Extension | |
| # Use URL-type ProgID for protocols, HTML-type for file extensions | |
| if ($ext -in $protocols -or $ext -notmatch "^\.") { | |
| $useProgId = $targetUrlProgId | |
| } else { | |
| $useProgId = $targetProgId | |
| } | |
| $result = & $setUserFtaExe $ext $useProgId 2>&1 | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host (" [OK] {0} -> {1}" -f $ext, $useProgId) -ForegroundColor Green | |
| $successCount++ | |
| } else { | |
| Write-Host (" [FAIL] {0} -> {1} : {2}" -f $ext, $useProgId, $result) -ForegroundColor Red | |
| $failCount++ | |
| } | |
| } | |
| # --- 6. Summary --------------------------------------------------------------- | |
| Write-Host "`n----------------------------------------" -ForegroundColor DarkGray | |
| Write-Host "Done. $successCount reassigned, $failCount failed." -ForegroundColor Cyan | |
| if ($failCount -gt 0) { | |
| Write-Host "Some failures are expected -- Windows enforces certain protocol handlers." -ForegroundColor Yellow | |
| Write-Host "For those, MSEdgeRedirect (github.com/rcmaehl/MSEdgeRedirect) handles the rest." -ForegroundColor Yellow | |
| } | |
| Write-Host "" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example run on my machine