2

I would like to update all of my Steam games via the command line, so that everything is ready when I open Steam.

I was looking into it and I found the steamcmd which gives an example to update counterstrike app_update 740 validate. To use this I would however first have some way of obtaining all of the IDs of the installed Steam games.

2
  • There is no official way with steamcmd
    – NoOne
    Commented Oct 15, 2023 at 15:36
  • You can do something similar by using the Steam client, by enabling auto-updates and scheduling the updates to some stretch of hours of the day.
    – harrymc
    Commented Oct 15, 2023 at 18:47

3 Answers 3

1

Version with login, it will ask 2factor verification, idk if you can make it somehow to remember(didnt explore that, i assume it can or should) that login.

Add-Type -AssemblyName System.Windows.Forms
$host.ui.RawUI.WindowTitle = "SteamCMD autoupdater"

function Check-LogExistsAndClean {
    param(
        [string]$logFile
    )
    if (Test-Path $logFile) {
        $choice = [System.Windows.Forms.MessageBox]::Show("Log file already exists. Do you want to clean it?", "Log File Exists on path:$logFile`nDo you want to clean it?", "YesNo", "Warning")
        if ($choice -eq "Yes") {
            Clear-Content $logFile
            Write-Host "Log file cleaned."
        }
    } else {
        Write-Log -Message "Log file does not exist. Creating new log file." -LogFile $logFile
    }
}

function Get-PathForThis {
    param(
        [string]$description
    )  
    $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
    $folderBrowser.Description = $description
    $folderBrowser.RootFolder = "MyComputer"
    $folderBrowser.ShowNewFolderButton = $false
    [void]$folderBrowser.ShowDialog()
    return $folderBrowser.SelectedPath
}

function Write-Log {
    param(
        [string]$Message,
        [string]$LogFile
    )
    Add-content -Path $LogFile -Value $Message
}

function Get-SteamCredentials {
    $form = New-Object System.Windows.Forms.Form
    $form.Text = "Enter Steam Credentials"
    $form.Size = New-Object System.Drawing.Size(300,200)
    $form.StartPosition = "CenterScreen"
    $form.Topmost = $true

    $labelName = New-Object System.Windows.Forms.Label
    $labelName.Location = New-Object System.Drawing.Point(10,20)
    $labelName.Size = New-Object System.Drawing.Size(280,20)
    $labelName.Text = "Name (Default: anonymous):"
    $form.Controls.Add($labelName)

    $textBoxName = New-Object System.Windows.Forms.TextBox
    $textBoxName.Location = New-Object System.Drawing.Point(10,40)
    $textBoxName.Size = New-Object System.Drawing.Size(260,20)
    $textBoxName.Text = "anonymous"
    $form.Controls.Add($textBoxName)

    $labelPassword = New-Object System.Windows.Forms.Label
    $labelPassword.Location = New-Object System.Drawing.Point(10,70)
    $labelPassword.Size = New-Object System.Drawing.Size(280,20)
    $labelPassword.Text = "Password (Press No to continue or enter credentials):"
    $form.Controls.Add($labelPassword)

    $textBoxPassword = New-Object System.Windows.Forms.TextBox
    $textBoxPassword.Location = New-Object System.Drawing.Point(10,90)
    $textBoxPassword.Size = New-Object System.Drawing.Size(260,20)
    $textBoxPassword.Text = "Press No to continue or enter credentials"
    $textBoxPassword.Add_Click({
        if ($textBoxPassword.Text -eq "Press No to continue or enter credentials") {
            $textBoxPassword.Text = ""
            $buttonYes.Enabled = $true
        }
        
    })  # Clear text when clicked
    $form.Controls.Add($textBoxPassword)

    $buttonYes = New-Object System.Windows.Forms.Button
    $buttonYes.Location = New-Object System.Drawing.Point(10,120)
    $buttonYes.Size = New-Object System.Drawing.Size(75,23)
    $buttonYes.Text = "Yes"
    $buttonYes.Enabled = $false  # Disable button initially
    $form.Controls.Add($buttonYes)
    $buttonYes.Add_Click({
        $form.Close()
    })
    
    $buttonNo = New-Object System.Windows.Forms.Button
    $buttonNo.Location = New-Object System.Drawing.Point(90,120)
    $buttonNo.Size = New-Object System.Drawing.Size(75,23)
    $buttonNo.Text = "No"
    $buttonNo.Add_Click({
        $form.Close()
        $global:cancelled = $true
    })
    $form.Controls.Add($buttonNo)

    $buttonCancel = New-Object System.Windows.Forms.Button
    $buttonCancel.Location = New-Object System.Drawing.Point(170,120)
    $buttonCancel.Size = New-Object System.Drawing.Size(75,23)
    $buttonCancel.Text = "Cancel"
    $buttonCancel.Add_Click({
        $form.Close()
        [Environment]::Exit(0)
    })
    $form.Controls.Add($buttonCancel)

    $form.Add_Shown({$textBoxName.Focus()})
    $form.ShowDialog() | Out-Null
    if ($global:cancelled) {
        return $null
    }
    $steamUser = $textBoxName.Text
    $steamPass = $textBoxPassword.Text
    return $steamUser, $steamPass
}
$logFile = "$PSScriptRoot\SteamUpdateLog.txt"
Check-LogExistsAndClean -logFile $logFile
$steamcmdAppRoot = Get-PathForThis -description "Select SteamCMD folder"
if ($steamcmdAppRoot -eq "") {
    exit
}
$steamPath = Get-PathForThis -description "Select Steam folder"
if ($steamPath -eq "") {
    exit
}
$steamAppsPath = "$steamPath\steamapps"
$steamCommonPath = "$steamAppsPath\common"
$steamUser = "anonymous"
$steamPass = "Press No to continue or enter credentials"
$userInput = Get-SteamCredentials
if ($userInput -ne $null) {
    $steamUser = $userInput[0]
    $steamPass = $userInput[1]
}

function Get-InstallDirectoryFromACF {
    param(
        [string]$acfFilePath
    )
    Write-Host "Reading content of ACF file: $acfFilePath"
    $content = Get-Content -Path $acfFilePath -Raw
    $matches = $content | Select-String '"name"\s+"(.*?)"'
    if ($matches) {
        $installDir = $matches.Matches.Groups[1].Value
        Write-Host "Install Directory found: $installDir"
        return $installDir
    } else {
        Write-Host "No install directory found."
        return $null
    }
}

function Get-AppIdsFromACFFiles {
    param(
        [string]$directory,
        [string]$logFile
    )
    $acfFiles = Get-ChildItem -Path $directory -Filter "appmanifest_*.acf" -File
    $appIds = @()
    foreach ($file in $acfFiles) {
        $content = Get-Content -Path $file.FullName -Raw
        $appIdMatch = [regex]::Match($content, '"appid"\s+"(\d+)"')
        $nameMatch = [regex]::Match($content, '"name"\s+"(.*?)"')
        if ($appIdMatch.Success -and $nameMatch.Success) {
            $appId = $appIdMatch.Groups[1].Value
            $name = $nameMatch.Groups[1].Value
            Write-Log -Message "Found app with ID:$appId and name:$name" -LogFile $logFile
            $appInfo = [PSCustomObject]@{
                AppId = $appId
                Name = $name
            }
            $appIds += $appInfo
        }
    }
    return $appIds
}

$appIds = Get-AppIdsFromACFFiles -directory $steamAppsPath -logFile $logFile
if ($appIds.Count -eq 0) {
    Write-Log -Message "No app IDs found in ACF files." -LogFile $logFile
    exit
}

$errorCount = 0
foreach ($appIdInfo in $appIds) {
    $appId = $appIdInfo.AppId
    $name = $appIdInfo.Name
    $acfFilePath = "$steamAppsPath\appmanifest_$appId.acf"
    $installDir = Get-InstallDirectoryFromACF -acfFilePath $acfFilePath
    if ($installDir) {
        $gameInstallPath = "$steamCommonPath\$installDir"
        Write-Log -Message "Updating game on path: $gameInstallPath" -LogFile $gameInstallPath
        
        # Check if default credentials are used or if user entered custom credentials
        if ($steamUser -eq "anonymous" -and $steamPass -eq "Press No to continue or enter credentials") {
            $arguments = "+force_install_dir $gameInstallPath +login anonymous +app_update $appId validate +quit"
        } else {
            $arguments = "+force_install_dir $gameInstallPath +login $steamUser $steamPass +app_update $appId validate +quit"
        }        
        try {
            Start-Process -FilePath $steamcmdAppRoot\steamcmd.exe -ArgumentList $arguments -NoNewWindow -Wait
            Write-Log -Message "Game with ID:$appId and name:$name updated at path:$gameInstallPath" -LogFile $logFile
        } catch {
            $errorCount++
            Write-Log -Message "Failed to update game with ID:$appId and name:$name. Error: $_" -LogFile $logFile
        }
    } else {
        $errorCount++
        Write-Log -Message "Failed to find install directory for app ID:$appId and name:$name." -LogFile $logFile
    }
}

Write-Log -Message "Steam games updated." -LogFile $logFile

if ($errorCount -eq 0) {
    Write-Log -Message "There were no errors." -LogFile $logFile
} else {
    Write-Log -Message "There were a total of $errorCount errors." -LogFile $logFile
}
pause
0

I didn't add username and password, since it theory it shouldn't be needed, but if it turns out it is needed, i will expand script further.

Create new Named.ps1 script and paste whole code inside, save the file. Then on file right click and pick option "Run with PowerShell".

When you run the script, it will ask you for the location of SteamCMD and where your Steam is installed. It scans your steamapps folder for .vcf files that should be there if game is installed. After it extracts necessary info from .vcf file, it will try to update your app. I noticed one case where SteamCMD timedout, but ran normally on second and third test.

Add-Type -AssemblyName System.Windows.Forms

function Check-LogExistsAndClean {
    param(
        [string]$logFile
    )
    if (Test-Path $logFile) {
        $choice = [System.Windows.Forms.MessageBox]::Show("Log file already exists. Do you want to clean it?", "Log File Exists on path:$logFile`nDo you want to clean it?", "YesNo", "Warning")
        if ($choice -eq "Yes") {
            Clear-Content $logFile
            Write-Host "Log file cleaned."
        }
    } else {
        Write-Log -Message "Log file does not exist. Creating new log file." -LogFile $logFile
    }
}

function Get-PathForThis {
    param(
        [string]$description
    )  
    $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
    $folderBrowser.Description = $description
    $folderBrowser.RootFolder = "MyComputer"
    $folderBrowser.ShowNewFolderButton = $false
    [void]$folderBrowser.ShowDialog()
    return $folderBrowser.SelectedPath
}

function Write-Log {
    param(
        [string]$Message,
        [string]$LogFile
    )
    Add-content -Path $LogFile -Value $Message
}

$logFile = "$PSScriptRoot\SteamUpdateLog.txt"
Check-LogExistsAndClean -logFile $logFile
$steamcmdAppRoot = Get-PathForThis -description "Select SteamCMD folder"
$steamPath = Get-PathForThis -description "Select Steam folder"
$steamAppsPath = "$steamPath\steamapps"
$steamCommonPath = "$steamAppsPath\common"

function Get-InstallDirectoryFromACF {
    param(
        [string]$acfFilePath
    )
    Write-Host "Reading content of ACF file: $acfFilePath"
    $content = Get-Content -Path $acfFilePath -Raw
    $matches = $content | Select-String '"name"\s+"(.*?)"'
    if ($matches) {
        $installDir = $matches.Matches.Groups[1].Value
        Write-Host "Install Directory found: $installDir"
        return $installDir
    } else {
        Write-Host "No install directory found."
        return $null
    }
}

function Get-AppIdsFromACFFiles {
    param(
        [string]$directory,
        [string]$logFile
    )
    $acfFiles = Get-ChildItem -Path $directory -Filter "appmanifest_*.acf" -File
    $appIds = @()
    foreach ($file in $acfFiles) {
        $content = Get-Content -Path $file.FullName -Raw
        $appIdMatch = [regex]::Match($content, '"appid"\s+"(\d+)"')
        $nameMatch = [regex]::Match($content, '"name"\s+"(.*?)"')
        if ($appIdMatch.Success -and $nameMatch.Success) {
            $appId = $appIdMatch.Groups[1].Value
            $name = $nameMatch.Groups[1].Value
            Write-Log -Message "Found app with ID:$appId and name:$name" -LogFile $logFile
            $appInfo = [PSCustomObject]@{
                AppId = $appId
                Name = $name
            }
            $appIds += $appInfo
        }
    }
    return $appIds
}

$appIds = Get-AppIdsFromACFFiles -directory $steamAppsPath -logFile $logFile
if ($appIds.Count -eq 0) {
    Write-Log -Message "No app IDs found in ACF files." -LogFile $logFile
    exit
}

$errorCount = 0
foreach ($appIdInfo in $appIds) {
    $appId = $appIdInfo.AppId
    $name = $appIdInfo.Name
    $acfFilePath = "$steamAppsPath\appmanifest_$appId.acf"
    $installDir = Get-InstallDirectoryFromACF -acfFilePath $acfFilePath
    if ($installDir) {

        $gameInstallPath = "$steamCommonPath\$installDir"
        Write-Log -Message "Updating game on path: $gameInstallPath" -LogFile $gameInstallPath
        $arguments = "+force_install_dir $gameInstallPath +login anonymous +app_update $appId validate +quit"
        try {
            Start-Process -FilePath $steamcmdAppRoot\steamcmd.exe -ArgumentList $arguments -NoNewWindow -Wait
            Write-Log -Message "Game with ID:$appId and name:$name updated at path:$gameInstallPath" -LogFile $logFile
        } catch {
            $errorCount++
            Write-Log -Message "Failed to update game with ID:$appId and name:$name. Error: $_" -LogFile $logFile
        }
    } else {
        $errorCount++
        Write-Log -Message "Failed to find install directory for app ID:$appId and name:$name." -LogFile $logFile
    }
}

Write-Log -Message "Steam games updated." -LogFile $logFile

if ($errorCount -eq 0) {
    Write-Log -Message "There were no errors." -LogFile $logFile
} else {
    Write-Log -Message "There were a total of $errorCount errors." -LogFile $logFile
}
pause
-3

There is no direct command to update all Steam games at once. However this is every SteamCMD command in a list, and you can use a workaround to update all Steam games at once.

5
  • This is currently a comment. You can make it an answer by giving more information and perhaps some sample code that will string together a couple of the relevant commands in an indicative way. Commented Apr 3 at 21:22
  • It would be an answer if it were correct ^^
    – Danijel
    Commented Apr 4 at 7:30
  • @Danijel - A link by itself is never an answer to a question. Even if the link is correct and answers the question. We strive for more than just a sign post to a solution. A previous answer that linked to the same repository had already been deleted.
    – Ramhound
    Commented Apr 4 at 8:11
  • @Ramhound-to some point(didnt see not refer to what was deleted ^^) i agree with you, but i dont agree in cases where, i post link to stack exchange and somebody wants me to copy-paste other guy work and get points, with that i do not agree and it should be a link to solution(not a lie as i mentioned somewhere, where i copy and paste work from somebody else) even as an answer if it answers the OP question.
    – Danijel
    Commented Apr 4 at 10:55
  • 1
    @Danijel - The deleted answer was 2 sentences, with 2 URLs, with zero instructions on how to use SteamCMD. Sort of similar to this answer, where it's a URL, with zero instructions.
    – Ramhound
    Commented Apr 4 at 14:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .