|
| 1 | +# NightDisplay 安装前清理:结束全部旧进程、静默卸载其他旧版本、 |
| 2 | +# 把旧安装目录和旧安装包移到回收站、清理残余注册表值。只碰 NightDisplay 自己的东西。 |
| 3 | +param([string]$NewDir = "", [string]$SetupExe = "", [string]$AppId = "") |
| 4 | +$ErrorActionPreference = "SilentlyContinue" |
| 5 | +Add-Type -AssemblyName Microsoft.VisualBasic |
| 6 | +function Log($m) { Write-Output "[cleanup] $m" } |
| 7 | +function Norm($p) { if (-not $p) { return "" }; return ([IO.Path]::GetFullPath($p.Trim('"'))).TrimEnd('\').ToLowerInvariant() } |
| 8 | +function Recycle($path) { |
| 9 | + if (-not (Test-Path -LiteralPath $path)) { return } |
| 10 | + try { |
| 11 | + if (Test-Path -LiteralPath $path -PathType Container) { |
| 12 | + [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteDirectory($path, 'OnlyErrorDialogs', 'SendToRecycleBin') |
| 13 | + } else { |
| 14 | + [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($path, 'OnlyErrorDialogs', 'SendToRecycleBin') |
| 15 | + } |
| 16 | + Log "recycled $path" |
| 17 | + } catch { Remove-Item -LiteralPath $path -Recurse -Force; Log "deleted $path" } |
| 18 | +} |
| 19 | +function Kill-All { |
| 20 | + for ($i = 0; $i -lt 10; $i++) { |
| 21 | + $ps = @(Get-Process -Name NightDisplay -ErrorAction SilentlyContinue) |
| 22 | + # 旧版卸载器 unins*.exe 若在旧目录里卡住也一起结束 |
| 23 | + $ps += @(Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -and $_.ExecutablePath -match '\\NightDisplay[^\\]*\\unins\d+\.exe$' } | ForEach-Object { Get-Process -Id $_.ProcessId }) |
| 24 | + $ps = @($ps | Where-Object { $_ }) |
| 25 | + if ($ps.Count -eq 0) { return $true } |
| 26 | + foreach ($p in $ps) { Log "kill $($p.Id) $($p.Path)"; & taskkill.exe /F /T /PID $p.Id | Out-Null } |
| 27 | + Start-Sleep -Milliseconds 500 |
| 28 | + } |
| 29 | + return (@(Get-Process -Name NightDisplay -ErrorAction SilentlyContinue).Count -eq 0) |
| 30 | +} |
| 31 | + |
| 32 | +$newDirN = Norm $NewDir |
| 33 | +$ourKey = "$AppId" + "_is1" |
| 34 | +[void](Kill-All) |
| 35 | + |
| 36 | +# 1) 找出所有 NightDisplay 卸载登记(HKCU/HKLM,含 32 位视图) |
| 37 | +$roots = @('HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall', |
| 38 | + 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall', |
| 39 | + 'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall') |
| 40 | +$oldDirs = @() |
| 41 | +foreach ($r in $roots) { |
| 42 | + foreach ($k in @(Get-ChildItem -LiteralPath $r)) { |
| 43 | + $v = Get-ItemProperty -LiteralPath $k.PSPath |
| 44 | + if ("$($v.DisplayName)" -notmatch '^NightDisplay') { continue } |
| 45 | + $loc = Norm $v.InstallLocation |
| 46 | + if ($k.PSChildName -eq $ourKey -and $loc -eq $newDirN) { continue } # 就地升级,交给 Inno |
| 47 | + Log "old install: $($k.PSChildName) $loc" |
| 48 | + if ($loc) { $oldDirs += $loc } |
| 49 | + $un = "$($v.UninstallString)" |
| 50 | + $exe = if ($un -match '^"([^"]+)"') { $Matches[1] } else { ($un -split ' ')[0] } |
| 51 | + if ($exe -and (Test-Path -LiteralPath $exe)) { |
| 52 | + $p = Start-Process -FilePath $exe -ArgumentList '/VERYSILENT','/SUPPRESSMSGBOXES','/NORESTART' -PassThru -WindowStyle Hidden |
| 53 | + if (-not $p.WaitForExit(60000)) { & taskkill.exe /F /T /PID $p.Id | Out-Null } |
| 54 | + # Inno 卸载器会把自己复制到临时目录再跑,等它真正结束 |
| 55 | + for ($i = 0; $i -lt 60 -and (Get-Process | Where-Object { $_.ProcessName -match '^_iu\d+' }); $i++) { Start-Sleep -Milliseconds 500 } |
| 56 | + } |
| 57 | + [void](Kill-All) |
| 58 | + if (Test-Path -LiteralPath $k.PSPath) { Remove-Item -LiteralPath $k.PSPath -Recurse -Force; Log "removed key $($k.PSChildName)" } |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +# 2) 旧安装目录(不是这次的目标目录)移到回收站 |
| 63 | +$cands = $oldDirs + @("$env:LOCALAPPDATA\Programs\NightDisplay", "$env:ProgramFiles\NightDisplay", "${env:ProgramFiles(x86)}\NightDisplay") |
| 64 | +foreach ($d in ($cands | ForEach-Object { Norm $_ } | Where-Object { $_ } | Sort-Object -Unique)) { |
| 65 | + if ($d -eq $newDirN) { continue } |
| 66 | + if ((Split-Path $d -Leaf) -notmatch '^NightDisplay') { continue } # 只删名字是 NightDisplay* 的目录 |
| 67 | + Recycle $d |
| 68 | +} |
| 69 | + |
| 70 | +# 3) Run 里指向不存在程序的 NightDisplay* 残余值 |
| 71 | +foreach ($rk in 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run','HKLM:\Software\Microsoft\Windows\CurrentVersion\Run') { |
| 72 | + $props = Get-ItemProperty -LiteralPath $rk |
| 73 | + foreach ($n in @($props.PSObject.Properties.Name | Where-Object { $_ -like 'NightDisplay*' })) { |
| 74 | + $val = "$($props.$n)" |
| 75 | + $exe = if ($val -match '^"([^"]+)"') { $Matches[1] } else { ($val -split ' ')[0] } |
| 76 | + if ($n -ne 'NightDisplay' -or -not (Test-Path -LiteralPath $exe)) { Remove-ItemProperty -LiteralPath $rk -Name $n; Log "removed Run $n" } |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +# 4) 失效快捷方式(桌面/开始菜单里指向已不存在 exe 的 NightDisplay*.lnk) |
| 81 | +$sh = New-Object -ComObject WScript.Shell |
| 82 | +$lnkDirs = @([Environment]::GetFolderPath('Desktop'), [Environment]::GetFolderPath('CommonDesktopDirectory'), |
| 83 | + [Environment]::GetFolderPath('Programs'), [Environment]::GetFolderPath('CommonPrograms')) |
| 84 | +foreach ($ld in $lnkDirs) { |
| 85 | + if (-not $ld) { continue } |
| 86 | + foreach ($l in @(Get-ChildItem -LiteralPath $ld -Filter '*.lnk' -Recurse -Depth 1 | Where-Object { $_.FullName -match 'NightDisplay' })) { |
| 87 | + $t = $sh.CreateShortcut($l.FullName).TargetPath |
| 88 | + if ($t -and -not (Test-Path -LiteralPath $t)) { Recycle $l.FullName } |
| 89 | + } |
| 90 | + $g = Join-Path $ld 'NightDisplay' |
| 91 | + if ((Test-Path -LiteralPath $g) -and -not (Get-ChildItem -LiteralPath $g)) { Remove-Item -LiteralPath $g -Force } |
| 92 | +} |
| 93 | + |
| 94 | +# 5) 下载目录里旧的 NightDisplay 安装包/压缩包(不含正在运行的这个)移到回收站 |
| 95 | +$setupN = Norm $SetupExe |
| 96 | +$dl = Join-Path $env:USERPROFILE 'Downloads' |
| 97 | +foreach ($f in @(Get-ChildItem -LiteralPath $dl -File | Where-Object { $_.Name -match '^NightDisplay.*(Setup.*\.exe|Windows.*\.zip)$' })) { |
| 98 | + if ((Norm $f.FullName) -eq $setupN) { continue } |
| 99 | + Recycle $f.FullName |
| 100 | +} |
| 101 | + |
| 102 | +if (Kill-All) { Log "no NightDisplay process left"; exit 0 } else { Log "process still alive"; exit 3 } |
0 commit comments