# Experiment for retrobar.dev's RetroBar vs ExplorerPatcher comparison: install the release # marked "Latest" on GitHub, photograph the taskbar it gives, try its taskbar styles, then # uninstall it and check that Windows 11's taskbar comes back. Results: verify//. $OutName = if ($env:VERIFY_OUT) { $env:VERIFY_OUT } else { 'results-ep' } . (Join-Path (Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)) 'verify\lib.ps1') New-Item -ItemType Directory -Force -Path (Join-Path $out 'shots') | Out-Null $results = [ordered]@{ started = (Get-Date).ToString('o') } function Step($name, [scriptblock]$body) { Log "== $name"; try { & $body } catch { Log "STEP FAILED ($name): $_"; $results["error_$name"] = "$_" }; Save 'results.json' $results } function TbShot($name) { Dismiss-Oobe; Hide-Consoles; Start-Sleep 1 Shot "shots/$name" $tb = [N]::FindWindow('Shell_TrayWnd', $null); $rc = New-Object N+RECT; [N]::GetWindowRect($tb, [ref]$rc) | Out-Null $png = Join-Path $out "shots/$name.png" if ($rc.Right -gt $rc.Left) { Crop-Png $png (Join-Path $out "shots/$name-strip.png") $rc.Left $rc.Top ($rc.Right - $rc.Left) ($rc.Bottom - $rc.Top) 1 Crop-Png $png (Join-Path $out "shots/$name-start-2x.png") $rc.Left $rc.Top 600 ($rc.Bottom - $rc.Top) 2 Crop-Png $png (Join-Path $out "shots/$name-tray-2x.png") ($rc.Right - 420) $rc.Top 420 ($rc.Bottom - $rc.Top) 2 } [ordered]@{ left = $rc.Left; top = $rc.Top; right = $rc.Right; bottom = $rc.Bottom } } function Reg-Dump { $k = 'HKCU:\Software\ExplorerPatcher'; if (Test-Path $k) { $p = Get-ItemProperty $k; $o = [ordered]@{}; foreach ($n in $p.PSObject.Properties.Name | Where-Object { $_ -notmatch '^PS' }) { $o[$n] = "$($p.$n)" }; $o } } function Restart-Explorer { Stop-Process -Name explorer -Force; Start-Sleep 8; if (-not (Get-Process explorer -ErrorAction SilentlyContinue)) { Start-Process explorer.exe; Start-Sleep 8 } } Step 'machine' { Set-Screen $cv = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' $results.machine = [ordered]@{ os = (Get-CimInstance Win32_OperatingSystem).Caption; build = "$($cv.CurrentBuild).$($cv.UBR)"; displayVersion = $cv.DisplayVersion; arch = $env:PROCESSOR_ARCHITECTURE } $results.explorerMbBefore = [math]::Round((Get-Process explorer | Measure-Object WorkingSet64 -Sum).Sum / 1MB) $results.taskbar = [ordered]@{ before = (TbShot 'ep-00-windows-taskbar') } } Step 'install' { $h = @{ 'User-Agent' = 'retrobar.dev-verify' }; if ($env:GITHUB_TOKEN) { $h.Authorization = "Bearer $env:GITHUB_TOKEN" } $rel = Invoke-RestMethod 'https://api.github.com/repos/valinet/ExplorerPatcher/releases/latest' -Headers $h $results.release = [ordered]@{ tag = $rel.tag_name; published = $rel.published_at; prerelease = $rel.prerelease; assets = @($rel.assets | ForEach-Object { $_.name }); notes = $rel.body } $want = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'ep_setup_arm64.exe' } else { 'ep_setup.exe' } $asset = $rel.assets | Where-Object { $_.name -eq $want } | Select-Object -First 1 if (-not $asset) { $asset = $rel.assets | Where-Object { $_.name -eq 'ep_setup.exe' } | Select-Object -First 1 } $setup = Join-Path $env:TEMP $asset.name Invoke-WebRequest $asset.browser_download_url -OutFile $setup -UseBasicParsing $sig = Get-AuthenticodeSignature $setup $results.setup = [ordered]@{ name = $asset.name; sha256 = (Get-FileHash $setup -Algorithm SHA256).Hash.ToLower(); signature = "$($sig.Status)"; signer = "$($sig.SignerCertificate.Subject)" } $t0 = Get-Date $p = Start-Process $setup -PassThru; $null = $p.Handle $done = $p.WaitForExit(240000); if (-not $done) { Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue } $results.setup.exit = if ($done) { $p.ExitCode } else { 'timeout' } $results.setup.seconds = [int]((Get-Date) - $t0).TotalSeconds Start-Sleep 15 $results.setup.topWindows = Get-TopWindows $results.installDir = @("$env:ProgramFiles\ExplorerPatcher", "${env:ProgramFiles(x86)}\ExplorerPatcher") | Where-Object { Test-Path $_ } $results.installFiles = @(foreach ($d in $results.installDir) { Get-ChildItem $d -File -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Name) $($_.Length)" } }) $results.regAfterInstall = Reg-Dump $results.taskbar.afterInstall = TbShot 'ep-01-after-install' Key @(0x5B); Start-Sleep 3; Shot 'shots/ep-02-after-install-start'; Key @(0x1B); Start-Sleep 2 $results.explorerMbAfter = [math]::Round((Get-Process explorer | Measure-Object WorkingSet64 -Sum).Sum / 1MB) } Step 'styles' { # Try the OldTaskbar values 1 and 2 (taskbar styles); the screenshots show what each one gives $k = 'HKCU:\Software\ExplorerPatcher' if (-not (Test-Path $k)) { Log 'no ExplorerPatcher key'; return } foreach ($v in 1, 2) { Set-ItemProperty $k OldTaskbar $v -Type DWord Restart-Explorer $results.taskbar["oldTaskbar$v"] = TbShot "ep-03-oldtaskbar-$v" } $results.regAfterStyles = Reg-Dump # Windows 10 Start menu: try the classic-mode value; the screenshot shows whether it took effect $adv = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' $results.startShowClassicModeBefore = (Get-ItemProperty $adv -ErrorAction SilentlyContinue).Start_ShowClassicMode Set-ItemProperty $adv Start_ShowClassicMode 1 -Type DWord Restart-Explorer; Get-Process StartMenuExperienceHost -ErrorAction SilentlyContinue | Stop-Process -Force; Start-Sleep 6 Dismiss-Oobe; Hide-Consoles Key @(0x5B); Start-Sleep 4; Shot 'shots/ep-05-start10-try'; $results.start10TopWindows = Get-TopWindows; Key @(0x1B); Start-Sleep 2 } Step 'uninstall' { $u = Get-ChildItem 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall' | Get-ItemProperty | Where-Object { $_.DisplayName -match 'ExplorerPatcher' } | Select-Object -First 1 $results.uninstallEntry = $u | Select-Object DisplayName, DisplayVersion, Publisher, UninstallString, InstallLocation if ($u.UninstallString) { $cmd = $u.UninstallString $exe = if ($cmd -match '^"([^"]+)"\s*(.*)$') { $matches[1] } else { $cmd.Split(' ')[0] } $argStr = if ($cmd -match '^"[^"]+"\s*(.*)$') { $matches[1] } else { ($cmd.Split(' ', 2) + '')[1] } $p = Start-Process $exe -ArgumentList $argStr -PassThru; $null = $p.Handle # The uninstaller asks for confirmation (and may show more messages): photograph each, answer Yes/OK $results.uninstallDialogs = @() for ($i = 1; $i -le 6 -and -not $p.HasExited; $i++) { Start-Sleep 6 $win = $null foreach ($w in $UIA::RootElement.FindAll([System.Windows.Automation.TreeScope]::Children, [System.Windows.Automation.Condition]::TrueCondition)) { if ($w.Current.Name -match 'ExplorerPatcher') { $win = $w; break } } if (-not $win) { continue } $texts = @($win.FindAll([System.Windows.Automation.TreeScope]::Descendants, [System.Windows.Automation.Condition]::TrueCondition) | ForEach-Object { $_.Current.Name } | Where-Object { $_ }) Shot ("shots/ep-04-uninstall-dialog-{0}" -f $i) $clicked = $null foreach ($b in 'Yes', 'OK') { $el = FindName $b 1 $win; if ($el) { Invoke-El $el | Out-Null; $clicked = $b; break } } $results.uninstallDialogs += [ordered]@{ title = $win.Current.Name; texts = $texts; clicked = $clicked } Log "uninstall dialog $i : $($texts -join ' | ') -> $clicked" } $done = $p.WaitForExit(120000) $results.uninstallExit = if ($done) { $p.ExitCode } else { 'timeout' } Start-Sleep 15 $results.uninstallTopWindows = Get-TopWindows } if (-not (Get-Process explorer -ErrorAction SilentlyContinue)) { Start-Process explorer.exe; Start-Sleep 8 } $results.leftAfterUninstall = [ordered]@{ folder = @("$env:ProgramFiles\ExplorerPatcher") | Where-Object { Test-Path $_ }; files = @(Get-ChildItem "$env:ProgramFiles\ExplorerPatcher" -File -ErrorAction SilentlyContinue | ForEach-Object { $_.Name }); regKey = Test-Path 'HKCU:\Software\ExplorerPatcher'; uninstallEntry = [bool](Get-ChildItem 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall' | Get-ItemProperty | Where-Object { $_.DisplayName -match 'ExplorerPatcher' }) } $results.taskbar.afterUninstall = TbShot 'ep-04-after-uninstall' } $results.finished = (Get-Date).ToString('o') Save 'results.json' $results