# Experiment for retrobar.dev's RetroBar vs Windhawk comparison: can Windhawk and its # "Windows 11 Taskbar Styler" mod be installed and set to the WinXP theme without its UI, # so we can photograph the result next to RetroBar? Records versions, hashes, the CLI's # own help text and every command's output. Results go to verify//. $OutName = if ($env:VERIFY_OUT) { $env:VERIFY_OUT } else { 'results-windhawk' } . (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" 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") ([Math]::Max(0, ($rc.Right - $rc.Left) / 2 - 300)) $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 Run($exe, $argList, $sec = 180) { $o = Join-Path $env:TEMP ("wh-" + [guid]::NewGuid().ToString('n') + '.txt') $p = Start-Process $exe -ArgumentList $argList -RedirectStandardOutput $o -RedirectStandardError "$o.err" -PassThru -WindowStyle Hidden $null = $p.Handle $done = $p.WaitForExit($sec * 1000); if (-not $done) { Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue } $text = @((Get-Content $o -ErrorAction SilentlyContinue) + (Get-Content "$o.err" -ErrorAction SilentlyContinue) | ForEach-Object { "$_" }) Log "$([IO.Path]::GetFileName($exe)) $argList -> $(if ($done) { $p.ExitCode } else { 'timeout' })" [ordered]@{ args = $argList; exit = $(if ($done) { $p.ExitCode } else { 'timeout' }); output = $text } } Step 'machine' { Set-Screen $os = Get-CimInstance Win32_OperatingSystem $cv = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' $results.machine = [ordered]@{ os = $os.Caption; build = "$($cv.CurrentBuild).$($cv.UBR)"; displayVersion = $cv.DisplayVersion; arch = $env:PROCESSOR_ARCHITECTURE } Dismiss-Oobe; Hide-Consoles; Start-Sleep 2 TbShot 'wh-00-windows-taskbar' $results.explorerMbBefore = [math]::Round((Get-Process explorer | Measure-Object WorkingSet64 -Sum).Sum / 1MB) } Step 'install' { $h = @{ 'User-Agent' = 'retrobar.dev-verify' }; if ($env:GITHUB_TOKEN) { $h.Authorization = "Bearer $env:GITHUB_TOKEN" } $rels = Invoke-RestMethod 'https://api.github.com/repos/ramensoftware/windhawk/releases?per_page=10' -Headers $h $results.releases = @($rels | ForEach-Object { [ordered]@{ tag = $_.tag_name; prerelease = $_.prerelease; published = $_.published_at; assets = @($_.assets | ForEach-Object { $_.name }) } }) $want = if ($env:WH_PRERELEASE -eq '1') { $rels | Select-Object -First 1 } else { $rels | Where-Object { -not $_.prerelease } | Select-Object -First 1 } $results.latestNotes = $want.body $asset = $want.assets | Where-Object { $_.name -match '(?i)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.windhawk = [ordered]@{ tag = $want.tag_name; prerelease = $want.prerelease; setup = $asset.name; sha256 = (Get-FileHash $setup -Algorithm SHA256).Hash.ToLower(); signature = "$($sig.Status)"; signer = "$($sig.SignerCertificate.Subject)" } $r = Run $setup '/S' 300 $results.windhawk.install = $r Start-Sleep 8 $dirs = @("$env:ProgramFiles\Windhawk", "${env:ProgramFiles(x86)}\Windhawk") | Where-Object { Test-Path $_ } $results.windhawk.installDir = $dirs $results.windhawk.files = @(foreach ($d in $dirs) { Get-ChildItem $d -File -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Name) $($_.Length)" } }) $results.windhawk.textFiles = [ordered]@{} foreach ($d in $dirs) { foreach ($t in Get-ChildItem $d -File -Include *.txt, *.ini -Recurse -ErrorAction SilentlyContinue) { $results.windhawk.textFiles[$t.Name] = [IO.File]::ReadAllText($t.FullName) } } $results.windhawk.processes = @(Get-Process | Where-Object { $_.ProcessName -match '(?i)windhawk' } | ForEach-Object { "$($_.ProcessName) $($_.Path)" }) Dismiss-Oobe; Hide-Consoles Shot 'shots/wh-01-after-install' $results.topWindows = Get-TopWindows } Step 'cli' { $cli = Get-ChildItem @("$env:ProgramFiles\Windhawk", "${env:ProgramFiles(x86)}\Windhawk") -Recurse -Filter 'windhawk-cli.exe' -ErrorAction SilentlyContinue | Select-Object -First 1 $results.cli = [ordered]@{ path = $cli.FullName; runs = @() } if (-not $cli) { Log 'no windhawk-cli.exe'; return } $c = $cli.FullName foreach ($a in '--help', 'help', 'mod --help', 'mod install --help', 'mod settings --help', 'mod settings set --help', 'mod list') { $results.cli.runs += (Run $c $a 60) } $help = ($results.cli.runs | ForEach-Object { $_.output }) -join "`n" $flags = @([regex]::Matches($help, '--(?:yes|accept[-\w]*|force|non-interactive|no-prompt|y)\b') | ForEach-Object { $_.Value } | Select-Object -Unique) $results.cli.flagsFound = $flags $id = 'windows-11-taskbar-styler' $tries = @("mod install $id") + @($flags | ForEach-Object { "mod install $id $_" }) foreach ($t in $tries) { $r = Run $c $t 300; $results.cli.runs += $r $list = Run $c 'mod list' 60; $results.cli.runs += $list if (($list.output -join ' ') -match [regex]::Escape($id)) { $results.cli.installedWith = $t; break } } if (-not $results.cli.installedWith) { return } Start-Sleep 10 $results.taskbarRect = [ordered]@{ default = (TbShot 'wh-02-styler-default') } foreach ($th in 'WinXP', 'WinVista', 'Windows7') { $r = Run $c "mod settings set $id theme=$th" 60; $results.cli.runs += $r Start-Sleep 12 $slug = $th.ToLower() $results.taskbarRect[$th] = TbShot "wh-03-styler-$slug" Key @(0x5B); Start-Sleep 3; Shot "shots/wh-04-styler-$slug-start"; Key @(0x1B); Start-Sleep 2 } $results.cli.runs += (Run $c "mod settings get $id" 60) $results.cli.runs += (Run $c "mod show $id" 60) $results.mem = @(Get-Process | Where-Object { $_.ProcessName -match '(?i)windhawk' } | ForEach-Object { [ordered]@{ name = $_.ProcessName; mb = [math]::Round($_.WorkingSet64 / 1MB) } }) $results.explorerMbAfter = [math]::Round((Get-Process explorer | Measure-Object WorkingSet64 -Sum).Sum / 1MB) # Turning the mod off: does the Windows 11 taskbar come straight back? $results.cli.runs += (Run $c "mod disable $id" 60); Start-Sleep 10 $results.taskbarRect.disabled = TbShot 'wh-05-styler-disabled' } $results.finished = (Get-Date).ToString('o') Save 'results.json' $results