使用 steamcmd 更新所有 steam 游戏

使用 steamcmd 更新所有 steam 游戏

我想通过命令行更新我的所有 Steam 游戏,以便打开 Steam 时一切准备就绪。

我正在调查此事,发现steam命令这给出了更新反恐精英的示例app_update 740 validate。要使用它,我首先需要某种方式获取已安装 Steam 游戏的所有 ID。

答案1

带有登录的版本,它将要求进行双因素验证,我不知道您是否可以以某种方式让它记住(没有探索过,我认为它可以或应该)该登录。

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

答案2

我没有添加用户名和密码,因为理论上不需要,但如果事实证明需要,我会进一步扩展脚本。

创建新的 Named.ps1 脚本并将整个代码粘贴到其中,保存文件。然后在文件上单击鼠标右键,选择“使用 PowerShell 运行”选项。

当您运行脚本时,它会询问您 SteamCMD 的位置以及 Steam 的安装位置。它会扫描您的 steamapps 文件夹以查找 .vcf 文件(如果安装了游戏,这些文件应该存在)。从 .vcf 文件中提取必要信息后,它会尝试更新您的应用程序。我注意到有一次 SteamCMD 超时,但在第二次和第三次测试中正常运行。

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

没有直接命令一次性更新所有 Steam 游戏。然而,这是列表中的每个 SteamCMD 命令,您可以使用变通方法一次性更新所有 Steam 游戏。

相关内容