Skip to content

Instantly share code, notes, and snippets.

@legendof-selda
Created July 22, 2025 20:07
Show Gist options
  • Save legendof-selda/c452021c81167d55341561e47fb7bea1 to your computer and use it in GitHub Desktop.
Save legendof-selda/c452021c81167d55341561e47fb7bea1 to your computer and use it in GitHub Desktop.
Steam auto shutdown after downloads
<#
.SYNOPSIS
Tracks Steam download activity and schedules a computer shutdown when downloads finish.
.DESCRIPTION
This script polls the Steam client’s registry and app manifest files to determine download status.
It handles scenarios like network interruptions and manual cancellation by checking the presence
and content of the appmanifest_<ID>.acf files. After observing a configurable number of idle
cycles following a completed download, it triggers a system shutdown with a grace period to abort.
.PARAMETER checkInterval
Seconds to wait between each download-status check.
.PARAMETER shutdownGracePeriod
Time, in seconds, between issuing the shutdown command and actual power‑off.
.PARAMETER idleCyclesBeforeShutdown
Number of consecutive “no download” checks (with manifest intact) required before initiating shutdown.
#>
param (
[int] $checkInterval = 60, # default: 60s between checks
[int] $shutdownGracePeriod = 900, # default: 15m until shutdown
[int] $idleCyclesBeforeShutdown = 5 # default: 5 idle loops
)
# Possible registry locations for Steam’s installation directory
$ClientRegKeys = @(
'HKLM:\SOFTWARE\WOW6432Node\Valve\Steam',
'HKLM:\SOFTWARE\Valve\Steam'
)
# Registry path where per‑app download flags live
$AppsStatusRegPath = 'HKCU:\Software\Valve\Steam\Apps\*'
$ClientProcessName = 'steam'
$ManifestNameFormat = 'appmanifest_{0}.acf'
function Resolve-ClientInstallDir {
foreach ($key in $ClientRegKeys) {
if (Test-Path $key) {
$props = Get-ItemProperty -Path $key -Name InstallPath -ErrorAction SilentlyContinue
if ($props.InstallPath -and (Test-Path $props.InstallPath)) {
return $props.InstallPath
}
}
}
return $null
}
function Get-ActiveTransfers {
<#
.SYNOPSIS
Returns registry entries for apps currently downloading (Updating = 1).
#>
Get-ItemProperty -Path $AppsStatusRegPath -Name Updating -ErrorAction SilentlyContinue |
Where-Object { $_.Updating -eq 1 }
}
function Check-TransferComplete {
<#
.SYNOPSIS
Reads an appmanifest file and returns $true if BytesDownloaded == BytesToDownload.
.PARAMETER manifestPath
Full filepath to the appmanifest_<AppID>.acf file.
#>
param (
[Parameter(Mandatory)]
[string] $manifestPath
)
Write-Output ("[{0}] Checking manifest: {1}" -f (Get-Date -Format 'HH:mm:ss'), $manifestPath)
if (-not (Test-Path $manifestPath)) {
Write-Output " → Manifest missing; assuming canceled/uninstalled."
return $false
}
$content = Get-Content -Path $manifestPath
$totalMatch = $content | Select-String -Pattern '"BytesToDownload"\s+"(\d+)"'
$doneMatch = $content | Select-String -Pattern '"BytesDownloaded"\s+"(\d+)"'
if ($totalMatch -and $doneMatch) {
$total = [int64]$totalMatch.Matches[0].Groups[1].Value
$done = [int64]$doneMatch.Matches[0].Groups[1].Value
Write-Output (" → BytesToDownload = {0:N0}, BytesDownloaded = {1:N0}" -f $total, $done)
return ($total -eq $done)
}
Write-Output " → Could not find byte‑count entries."
return $false
}
# ——————————————
# Start of main logic
# ——————————————
$installDir = Resolve-ClientInstallDir
if (-not $installDir) {
Write-Error "Steam install directory not found. Aborting."
exit 1
}
$state = 'AwaitingClientStart'
$currentAppID = $null
$idleCounter = 0
while ($true) {
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
Write-Output "=============================="
Write-Output ("[{0}] STATE: {1} | AppID: {2} | IdleCount: {3}" -f $timestamp, $state, ($currentAppID | % { $_ }), $idleCounter)
# Check if Steam is still running
$proc = Get-Process $ClientProcessName -ErrorAction SilentlyContinue
if (-not $proc) {
Write-Output ("[{0}] Steam process not found. Exiting monitor." -f $timestamp)
break
}
switch ($state) {
'AwaitingClientStart' {
Write-Output ("[{0}] Waiting for Steam to launch..." -f $timestamp)
Start-Sleep -Seconds 3
if (Get-Process $ClientProcessName -ErrorAction SilentlyContinue) {
Write-Output ("[{0}] Steam detected." -f (Get-Date -Format 'HH:mm:ss'))
$state = 'LookingForDownloads'
}
}
'LookingForDownloads' {
$transfer = Get-ActiveTransfers
if ($transfer) {
$currentAppID = $transfer.PSChildName
Write-Output ("[{0}] Detected new download for AppID {1}." -f (Get-Date -Format 'HH:mm:ss'), $currentAppID)
$idleCounter = 0
$state = 'Monitoring'
}
else {
Write-Output ("[{0}] No active downloads." -f (Get-Date -Format 'HH:mm:ss'))
Start-Sleep -Seconds 3
}
}
'Monitoring' {
$transfer = Get-ActiveTransfers
if ($transfer) {
Write-Output ("[{0}] Downloading AppID {1}…" -f (Get-Date -Format 'HH:mm:ss'), $transfer.PSChildName)
$currentAppID = $transfer.PSChildName
$idleCounter = 0
}
else {
$manifest = ($ManifestNameFormat -f $currentAppID)
$manifestPath = Join-Path $installDir "steamapps\$manifest"
if (Check-TransferComplete -manifestPath $manifestPath) {
Write-Warning ("[{0}] Download complete. Idle check {1}/{2}." `
-f (Get-Date -Format 'HH:mm:ss'), ($idleCounter + 1), $idleCyclesBeforeShutdown)
if ($idleCounter -ge $idleCyclesBeforeShutdown) {
Write-Output ("[{0}] Scheduling shutdown in {1} seconds…" -f (Get-Date -Format 'HH:mm:ss'), $shutdownGracePeriod)
Start-Process -FilePath shutdown `
-ArgumentList "/s","/f","/t",$shutdownGracePeriod -NoNewWindow
Write-Output ("[{0}] To abort: press any key and run `shutdown /a`." -f (Get-Date -Format 'HH:mm:ss'))
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
exit 0
}
$idleCounter++
}
else {
Write-Output ("[{0}] Transfer interrupted or manifest removed. Resetting state." -f (Get-Date -Format 'HH:mm:ss'))
$state = 'LookingForDownloads'
continue
}
}
$nextCheck = (Get-Date).AddSeconds($checkInterval).ToString('yyyy-MM-dd HH:mm:ss')
Write-Output ("[{0}] Next check at {1}" -f (Get-Date -Format 'HH:mm:ss'), $nextCheck)
Start-Sleep -Seconds $checkInterval
}
}
}
@legendof-selda
Copy link
Author

FYI, this is an AI generated Script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment