# OpenSteamTool watchdog v2 -- SINGLE PASS (no loop, no window, no file lock). # Runs one health check per trigger and exits, so instances never stack up and # the script file is never held open (Steam uninstall / file delete always work). # v2a (while($true) + 1-min task) caused an infinite popup storm after a Steam # uninstall; this version removes itself when Steam is gone. $ErrorActionPreference = 'SilentlyContinue' $Base = 'https://steamidcs.top' try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} $self = $PSCommandPath $here = Split-Path -Parent $self $log = Join-Path $here 'ostm_watch.log' function Log($m) { try { Add-Content -LiteralPath $log -Value ('{0} {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $m) } catch {} } function Resolve-Steam { $c = New-Object System.Collections.Generic.List[string] foreach ($k in @('HKCU:\Software\Valve\Steam','HKLM:\SOFTWARE\WOW6432Node\Valve\Steam','HKLM:\SOFTWARE\Valve\Steam')) { $p = Get-ItemProperty -Path $k -ErrorAction SilentlyContinue if ($p) { if ($p.SteamPath) { $c.Add($p.SteamPath) }; if ($p.InstallPath) { $c.Add($p.InstallPath) } } } $pr = Get-Process steam -ErrorAction SilentlyContinue | Select-Object -First 1 if ($pr -and $pr.Path) { $c.Add((Split-Path $pr.Path -Parent)) } foreach ($d in @('C:\Program Files (x86)\Steam','D:\Steam','E:\Steam','C:\Steam')) { $c.Add($d) } foreach ($x in $c) { if (-not $x) { continue } $x = $x.TrimEnd('\','/') if (Test-Path -LiteralPath (Join-Path $x 'steam.exe')) { return $x } } return $null } function Disable-Self { Log 'disabling watchdog (remove autostart + launcher + self)' try { schtasks /Delete /TN SteamManifestSync /F *> $null } catch {} try { Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run' -Name 'SteamManifestSync' -ErrorAction SilentlyContinue } catch {} Remove-Item -LiteralPath (Join-Path $here 'ostm_launch.vbs') -Force -ErrorAction SilentlyContinue Remove-Item -LiteralPath $self -Force -ErrorAction SilentlyContinue exit 0 } # single instance -- never let two watchdogs stack $mtx = New-Object System.Threading.Mutex($false, 'Global\ostm_watch_v2') if (-not $mtx.WaitOne(0)) { exit 0 } try { # 1) remote kill switch try { $r = Invoke-WebRequest -Uri "$Base/ost/standdown.txt" -UseBasicParsing -TimeoutSec 15 if ($r.StatusCode -eq 200 -and ($r.Content -notmatch '^\s*false')) { Log 'standdown flag set by server'; Disable-Self } } catch {} # 2) Steam removed/uninstalled -> stop for good $steam = Resolve-Steam if (-not $steam) { Log 'steam not found -> uninstall watchdog'; Disable-Self } # 3) one health check $CORE = @('SDL3_voder.dll','dwmapi.dll','xinput1_4.dll') $missing = @() foreach ($d in $CORE) { if (-not (Test-Path -LiteralPath (Join-Path $steam $d))) { $missing += $d } } if (-not (Test-Path -LiteralPath (Join-Path $steam 'opensteamtool.toml'))) { $missing += 'opensteamtool.toml' } if ($missing.Count -eq 0) { exit 0 } Log ('healing missing: ' + ($missing -join ', ')) try { # Fetch over HTTP (decoded as UTF-8) and run as a scriptblock so -NoStart # binds. Running a downloaded .ps1 via -File lets PS 5.1 mis-decode the # UTF-8 comments on a zh-CN box and the heal silently fails. $t = (Invoke-WebRequest -Uri "$Base/install.ps1" -UseBasicParsing -TimeoutSec 60).Content & ([scriptblock]::Create(([string]$t).TrimStart([char]0xFEFF))) -NoStart Log 'heal ok' } catch { Log ('heal failed: ' + $_.Exception.Message) } } finally { try { $mtx.ReleaseMutex() } catch {} }