<# CS2 File Sync Script Support: irm https://static.neting.cc/test.ps1 | iex Default: Download mode #> #Requires -Version 5.1 param( [string]$RunMode = "download" # download / upload ) # -------------------------- 配置区(和PHP的secretToken保持一致) -------------------------- $secretToken = "MyStrongSecret123456" $urlList = @( "https://static.neting.cc/cs2/730/remotecache.vdf", "https://static.neting.cc/cs2/730/local/socache.dt", "https://static.neting.cc/cs2/730/local/cfg/cs2_machine_convars.vcfg", "https://static.neting.cc/cs2/730/local/cfg/cs2_user_convars_0_slot0.vcfg", "https://static.neting.cc/cs2/730/local/cfg/cs2_user_keys_0_slot0.vcfg", "https://static.neting.cc/cs2/730/local/cfg/cs2_user_keys_0_slot1.vcfg", "https://static.neting.cc/cs2/730/local/cfg/cs2_user_keys_0_slot2.vcfg", "https://static.neting.cc/cs2/730/local/cfg/cs2_user_keys_0_slot3.vcfg", "https://static.neting.cc/cs2/730/local/cfg/cs2_video.txt", "https://static.neting.cc/cs2/730/local/cfg/trustedlaunch.cfg" ) $defaultRoot = "Z:\我的游戏\对战平台\Steam\steam\userdata\" $uploadApiUrl = "https://vvxp.cc/upload.php" $logFile = Join-Path $PWD.Path "sync_log_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt" # ------------------------------------------------------------------------------------------- # 日志函数 function Write-Log{ param([string]$Message) $msg = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $Message" Write-Host $msg Add-Content -Path $logFile -Value $msg -Encoding UTF8 } Write-Log "===== CS2 File Sync Tool Started =====" Write-Log "RunMode = $RunMode" # 判断Z盘,获取本地根目录 $zDriveExist = Get-PSDrive -Name Z -ErrorAction SilentlyContinue if ($zDriveExist) { $targetRoot = $defaultRoot if (-not (Test-Path $targetRoot)) { $targetRoot = "Z:\Dolagame\Steam\userdata\" } $targetRoot += "365858841\730\" Write-Log "Detected drive Z, use default path: $targetRoot" } else { Write-Log "Drive Z not found, please input target folder (example: D:\Steam\userdata\365858841\730\)" $valid = $false do { $inputPath = Read-Host "Input target root path" if (Test-Path $inputPath -IsValid) { $targetRoot = $inputPath.TrimEnd('\') + "\" $valid = $true } else { Write-Log "Invalid path format, try again!" $valid = $false } } while (-not $valid) } if (-not (Test-Path $targetRoot)) { Write-Log "Target folder not found, creating: $targetRoot" New-Item -Path $targetRoot -ItemType Directory -Force | Out-Null } Write-Log "Local root: $targetRoot" # ========== 下载函数(带进度条) ========== function Invoke-DownloadWithProgress { param( [string]$Uri, [string]$OutFile ) try { $request = [System.Net.HttpWebRequest]::Create($Uri) $request.Method = "GET" $request.Timeout = 15000 $response = $request.GetResponse() $totalLength = $response.ContentLength $streamIn = $response.GetResponseStream() $streamOut = [System.IO.File]::Create($OutFile) $buffer = New-Object byte[] 4096 $totalRead = 0 do { $readCount = $streamIn.Read($buffer,0,$buffer.Length) if ($readCount -le 0) { break } $streamOut.Write($buffer,0,$readCount) $totalRead += $readCount if ($totalLength -gt 0) { $percent = [math]::Round(($totalRead / $totalLength)*100,2) Write-Progress -Activity "Downloading $Uri" -Status "$totalRead / $totalLength bytes ($percent%)" -PercentComplete $percent } else { Write-Progress -Activity "Downloading $Uri" -Status "Received $totalRead bytes (unknown total size)" } } while ($true) Write-Progress -Activity "Download completed" -Completed $streamOut.Close() $streamIn.Close() $response.Close() return $true } catch { Write-Progress -Activity "Download failed" -Completed Write-Log "Download Error: $($_.Exception.Message)" return $false } } # ========== 上传函数:POST文件+Token,上传后比对MD5 ========== function Invoke-UploadFile { param( [string]$LocalFilePath, [string]$RelPath, [string]$ApiUrl, [string]$Token ) try{ $localMd5 = (Get-FileHash -Path $LocalFilePath -Algorithm MD5).Hash.ToLower() $boundary = [System.Guid]::NewGuid().ToString() $LF = "`r`n" $bodyLines = @( "--$boundary", "Content-Disposition: form-data; name=`"token`"$LF", $Token, "--$boundary", "Content-Disposition: form-data; name=`"relpath`"$LF", $RelPath, "--$boundary", "Content-Disposition: form-data; name=`"upfile`"; filename=`"$(Split-Path $LocalFilePath -Leaf)`"", "Content-Type: application/octet-stream$LF", [System.IO.File]::ReadAllBytes($LocalFilePath), "--$boundary--$LF" ) $encoding = New-Object System.Text.UTF8Encoding $body = @() foreach($line in $bodyLines){ if($line -is [byte[]]){ $body += $line }else{ $body += $encoding.GetBytes($line) } } $combined = New-Object byte[] $($body | Measure-Object -Property Length -Sum).Sum $offset=0 foreach($b in $body){ [Array]::Copy($b,0,$combined,$offset,$b.Length) $offset += $b.Length } $webReq = [System.Net.HttpWebRequest]::Create($ApiUrl) $webReq.Method = "POST" $webReq.ContentType = "multipart/form-data; boundary=`"$boundary`"" $webReq.ContentLength = $combined.Length $reqStream = $webReq.GetRequestStream() $reqStream.Write($combined,0,$combined.Length) $reqStream.Close() $resp = $webReq.GetResponse() $reader = New-Object System.IO.StreamReader($resp.GetResponseStream()) $resultJson = $reader.ReadToEnd() $reader.Close() $resp.Close() $ret = $resultJson | ConvertFrom-Json if($ret.code -eq 200){ $serverMd5 = $ret.md5.ToLower() if($localMd5 -eq $serverMd5){ Write-Log "MD5 match OK, local:$localMd5 server:$serverMd5" return $true }else{ Write-Log "MD5 MISMATCH! local:$localMd5 server:$serverMd5" return $false } }else{ Write-Log "Server return error: $($ret.msg)" return $false } } catch{ Write-Log "Upload exception: $($_.Exception.Message)" return $false } } # ===================== 主逻辑分支 ===================== $syncResult = @() if($RunMode -eq "download"){ Write-Log "===== ENTER DOWNLOAD MODE =====" foreach ($url in $urlList) { Write-Log "Downloading: $url" $relativePath = $url -replace "^https://static.neting.cc/cs2/730/", "" $localFile = Join-Path $targetRoot $relativePath $localDir = Split-Path -Path $localFile -Parent if (-not (Test-Path $localDir)) { Write-Log "Create subfolder: $localDir" New-Item -Path $localDir -ItemType Directory -Force | Out-Null } $success = Invoke-DownloadWithProgress -Uri $url -OutFile $localFile if ($success) { Write-Log "SUCCESS: $localFile" $syncResult += [PSCustomObject]@{ Url = $url LocalPath = $localFile SyncOK = $true } } else { Write-Log "FAILED : $localFile" $syncResult += [PSCustomObject]@{ Url = $url LocalPath = $localFile SyncOK = $false } } } # 下载校验逻辑 Write-Log "`n===== Download Verification =====" $allPass = $true foreach ($item in $syncResult) { if ($item.SyncOK -eq $true) { Write-Log "OK : $($item.LocalPath)" } else { if(Test-Path $item.LocalPath){ Write-Log "WARNING : $($item.LocalPath) -> Local old file exists, download failed, not updated!" }else{ Write-Log "MISSING : $($item.LocalPath)" } $allPass = $false } } if ($allPass) { Write-Log "All files downloaded successfully!" } else { Write-Log "WARNING: Some files download failed, old local files may remain!" } }elseif($RunMode -eq "upload"){ Write-Log "===== ENTER UPLOAD MODE =====" foreach ($url in $urlList) { Write-Log "Preparing upload: $url" $relativePath = $url -replace "^https://static.neting.cc/cs2/730/", "" $localFile = Join-Path $targetRoot $relativePath if(-not (Test-Path $localFile)){ Write-Log "SKIP: Local file not found $localFile" $syncResult += [PSCustomObject]@{ Url = $url LocalPath = $localFile SyncOK = $false } continue } $success = Invoke-UploadFile -LocalFilePath $localFile -RelPath "cs2/730/$relativePath" -ApiUrl $uploadApiUrl -Token $secretToken if ($success) { Write-Log "UPLOAD SUCCESS + MD5 OK: $localFile" $syncResult += [PSCustomObject]@{ Url = $url LocalPath = $localFile SyncOK = $true } } else { Write-Log "UPLOAD FAILED / MD5 MISMATCH : $localFile" $syncResult += [PSCustomObject]@{ Url = $url LocalPath = $localFile SyncOK = $false } } } # 上传结果汇总 Write-Log "`n===== Upload Verification =====" $allPass = $true foreach ($item in $syncResult) { if ($item.SyncOK -eq $true) { Write-Log "UPLOAD OK : $($item.LocalPath)" } else { Write-Log "UPLOAD FAILED/SKIP : $($item.LocalPath)" $allPass = $false } } if ($allPass) { Write-Log "All files uploaded, server backed up old files, MD5 verified!" } else { Write-Log "WARNING: Some files upload failed or MD5 mismatch!" } }else{ Write-Log "Invalid RunMode, exit." } Write-Log "`n===== Script Finished =====" Write-Log "Log saved to: $logFile" Read-Host "`nPress Enter to exit..."