# GSP Windows Agent Installer - PowerShell Script # This script handles the complete installation of GSP Windows Agent #Requires -RunAsAdministrator param( [string]$InstallPath = "C:\GSP", [string]$GitRepoUrl = "https://github.com/OpenGamePanel/OGP-Agent-Windows.git", [string]$GitBranch = "master", [string]$PortableGitPath, [switch]$SkipGitExtraction = $false ) # Get the directory where this script is located $Script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path if ([string]::IsNullOrEmpty($PortableGitPath)) { $PortableGitPath = Join-Path $Script:ScriptDir "PortableGit-2.54.0-64-bit.7z.exe" } $Script:AgentDir = Join-Path $InstallPath "Agent" $Script:GitDir = Join-Path $InstallPath "tools\PortableGit" $Script:HomeDir = Join-Path $InstallPath "home" $Script:BackupDir = Join-Path $InstallPath "backups\agent" $Script:LogsDir = Join-Path $InstallPath "logs" $Script:InstallLogFile = Join-Path $Script:LogsDir "install.log" # Initialize log if (-not (Test-Path $Script:LogsDir)) { New-Item -ItemType Directory -Path $Script:LogsDir -Force | Out-Null } function Log-Message { param([string]$Message, [switch]$IsError = $false) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logLine = "[$timestamp] $Message" if ($IsError) { Write-Host $logLine -ForegroundColor Red } else { Write-Host $logLine } Add-Content -Path $Script:InstallLogFile -Value $logLine -Force } function Test-Administrator { $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object Security.Principal.WindowsPrincipal($currentUser) return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Create-DirectoryStructure { Log-Message "Creating directory structure at $InstallPath..." try { $dirs = @( $InstallPath, (Join-Path $InstallPath "tools"), (Join-Path $InstallPath "backups"), $Script:BackupDir, $Script:HomeDir, $Script:LogsDir ) foreach ($dir in $dirs) { if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null Log-Message " Created: $dir" } else { Log-Message " Already exists: $dir" } } return $true } catch { Log-Message "ERROR creating directories: $_" -IsError $true return $false } } function Extract-PortableGit { Log-Message "Extracting Portable Git..." if (-not (Test-Path $PortableGitPath)) { Log-Message "ERROR: Portable Git installer not found at: $PortableGitPath" -IsError $true return $false } if ($SkipGitExtraction) { Log-Message "Skipping Portable Git extraction (--SkipGitExtraction flag set)" return $true } try { # Remove existing extraction if present if (Test-Path $Script:GitDir) { Log-Message "Removing existing PortableGit directory..." Remove-Item -Path $Script:GitDir -Recurse -Force } # Create parent directory for extraction New-Item -ItemType Directory -Path (Split-Path $Script:GitDir) -Force | Out-Null # Extract the 7z archive Log-Message "Running 7z extraction: $PortableGitPath" Log-Message "Extracting to: $Script:GitDir" $extractProcess = Start-Process -FilePath $PortableGitPath ` -ArgumentList "-o`"$Script:GitDir`" -y" ` -Wait -PassThru -NoNewWindow if ($extractProcess.ExitCode -ne 0) { Log-Message "ERROR: 7z extraction failed with exit code: $($extractProcess.ExitCode)" -IsError $true return $false } # Verify git.exe exists $gitExe = Join-Path $Script:GitDir "cmd\git.exe" if (-not (Test-Path $gitExe)) { Log-Message "ERROR: git.exe not found after extraction at: $gitExe" -IsError $true return $false } Log-Message "Portable Git extracted successfully" return $true } catch { Log-Message "ERROR extracting Portable Git: $_" -IsError $true return $false } } function Backup-ExistingAgent { Log-Message "Checking for existing agent installation..." if (-not (Test-Path $Script:AgentDir)) { Log-Message "No existing agent found" return $true } # Check if it's a git-managed installation $gitDir = Join-Path $Script:AgentDir ".git" if (Test-Path $gitDir) { Log-Message "Found existing Git-managed installation" Log-Message "Offering update/reconfigure instead of reinstall" $response = Read-Host "Updates available. Do you want to update? (Y/N)" if ($response -eq "Y" -or $response -eq "y") { Log-Message "Proceding with update instead of fresh install" # For now, we'll continue with update logic return $true } else { Log-Message "User cancelled update" return $false } } else { # Backup old manual installation $backupName = "manual-install-backup-$(Get-Date -Format 'yyyyMMdd-HHmmss')" $backupPath = Join-Path $Script:BackupDir $backupName Log-Message "Backing up existing manual installation..." Log-Message "Backup destination: $backupPath" try { Copy-Item -Path $Script:AgentDir -Destination $backupPath -Recurse -Force Log-Message "Backup completed successfully" # Preserve specific folders from old installation $preserveFolders = @("Cfg", "steamcmd", "screenlogs", "startups", "tmp", "shared") Log-Message "Marked folders for preservation after clone: $($preserveFolders -join ', ')" return $true } catch { Log-Message "ERROR creating backup: $_" -IsError $true return $false } } } function Clone-Repository { Log-Message "Cloning Windows Agent repository..." $gitExe = Join-Path $Script:GitDir "cmd\git.exe" if (-not (Test-Path $gitExe)) { Log-Message "ERROR: git.exe not found at: $gitExe" -IsError $true return $false } # Preserve existing folders if agent directory exists $preservedFolders = @{} $preserveFolders = @("Cfg", "steamcmd", "screenlogs", "startups", "tmp", "shared") if (Test-Path $Script:AgentDir) { foreach ($folder in $preserveFolders) { $folderPath = Join-Path $Script:AgentDir $folder if (Test-Path $folderPath) { $tempPath = Join-Path $env:TEMP "gsp_preserve_$folder" Log-Message "Preserving existing folder: $folder" Copy-Item -Path $folderPath -Destination $tempPath -Recurse -Force $preservedFolders[$folder] = $tempPath } } # Remove old directory to clone fresh Log-Message "Removing old agent directory for fresh clone..." Remove-Item -Path $Script:AgentDir -Recurse -Force -ErrorAction SilentlyContinue } try { Log-Message "Cloning from: $GitRepoUrl (branch: $GitBranch)" $cloneProcess = Start-Process -FilePath $gitExe ` -ArgumentList "clone", "--branch", $GitBranch, $GitRepoUrl, $Script:AgentDir ` -Wait -PassThru -NoNewWindow -WorkingDirectory $InstallPath if ($cloneProcess.ExitCode -ne 0) { Log-Message "ERROR: Git clone failed with exit code: $($cloneProcess.ExitCode)" -IsError $true return $false } Log-Message "Repository cloned successfully" # Restore preserved folders foreach ($folder in $preservedFolders.Keys) { $tempPath = $preservedFolders[$folder] $targetPath = Join-Path $Script:AgentDir $folder Log-Message "Restoring preserved folder: $folder" if (Test-Path $targetPath) { Remove-Item -Path $targetPath -Recurse -Force } Copy-Item -Path $tempPath -Destination $targetPath -Recurse -Force Remove-Item -Path $tempPath -Recurse -Force } return $true } catch { Log-Message "ERROR cloning repository: $_" -IsError $true return $false } } function Create-RequiredRuntimeFolders { Log-Message "Creating runtime folders in agent directory..." $runtimeFolders = @( "runtime_status", "screenlogs", "startups", "tmp", "shared" ) try { foreach ($folder in $runtimeFolders) { $folderPath = Join-Path $Script:AgentDir $folder if (-not (Test-Path $folderPath)) { New-Item -ItemType Directory -Path $folderPath -Force | Out-Null Log-Message " Created: $folder" } } return $true } catch { Log-Message "ERROR creating runtime folders: $_" -IsError $true return $false } } function Configure-Agent { Log-Message "Configuring agent..." try { # Call the configuration script if it exists $configScript = Join-Path $Script:ScriptDir "Configure-GSP-WindowsAgent.ps1" if (Test-Path $configScript) { Log-Message "Running configuration script..." & $configScript -AgentPath $Script:AgentDir -InstallPath $InstallPath } else { Log-Message "WARNING: Configuration script not found, skipping configuration" Log-Message "You can run configuration manually later with: Configure-GSP-WindowsAgent.ps1" } return $true } catch { Log-Message "ERROR during configuration: $_" -IsError $true return $false } } function Create-ScheduledTask { Log-Message "Creating Windows Task Scheduler entry..." try { # Path to the agent start script in the cloned repo $agentStartScript = Join-Path $Script:AgentDir "OGP64\agent_start.bat" if (-not (Test-Path $agentStartScript)) { Log-Message "WARNING: agent_start.bat not found at expected location" Log-Message "Task creation skipped - you may need to create the task manually" return $true } # Remove existing task if present try { Unregister-ScheduledTask -TaskName "GSP Windows Agent" -Confirm:$false -ErrorAction SilentlyContinue Log-Message "Removed existing task" } catch { # Task doesn't exist or couldn't be removed, continue } # Create task action $action = New-ScheduledTaskAction ` -Execute $agentStartScript ` -WorkingDirectory (Split-Path $agentStartScript) # Create task trigger at system startup $trigger = New-ScheduledTaskTrigger -AtStartup # Create task settings $settings = New-ScheduledTaskSettingsSet ` -AllowStartIfOnBatteries ` -DontStopIfGoingOnBatteries ` -Compatibility Win7 # Create and register the task $principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest $task = New-ScheduledTask ` -Action $action ` -Trigger $trigger ` -Principal $principal ` -Settings $settings ` -Description "GSP Windows Game Server Agent - Auto-start at system boot" Register-ScheduledTask -TaskName "GSP Windows Agent" -InputObject $task | Out-Null Log-Message "Scheduled task created successfully" Log-Message "Task name: GSP Windows Agent" Log-Message "Trigger: At system startup" Log-Message "Privileges: System (highest)" return $true } catch { Log-Message "ERROR creating scheduled task: $_" -IsError $true Log-Message "You may need to create the task manually or run with elevated privileges" return $false } } function Start-Agent { Log-Message "Starting agent..." try { $agentStartScript = Join-Path $Script:AgentDir "OGP64\agent_start.bat" if (-not (Test-Path $agentStartScript)) { Log-Message "WARNING: agent_start.bat not found" return $false } Log-Message "Agent start script located at: $agentStartScript" Log-Message "To start the agent manually, run: $agentStartScript" # Note: We don't auto-start the agent here because it needs to run at system startup # via the scheduled task, which handles Cygwin environment setup properly return $true } catch { Log-Message "ERROR starting agent: $_" -IsError $true return $false } } function Test-AdminPrivileges { if (-not (Test-Administrator)) { Log-Message "ERROR: This script must be run as Administrator" -IsError $true Log-Message "Please run this script with Administrator privileges" return $false } Log-Message "Administrator privileges verified" return $true } # Main installation flow function Main { Log-Message "=========================================" Log-Message "GSP Windows Agent Installation" Log-Message "=========================================" Log-Message "Install Path: $InstallPath" Log-Message "Git Repository: $GitRepoUrl" Log-Message "Git Branch: $GitBranch" Log-Message "" # Check admin if (-not (Test-AdminPrivileges)) { exit 1 } # Create directory structure if (-not (Create-DirectoryStructure)) { Log-Message "FATAL: Failed to create directory structure" -IsError $true exit 1 } # Extract Portable Git if (-not (Extract-PortableGit)) { Log-Message "FATAL: Failed to extract Portable Git" -IsError $true exit 1 } # Backup existing installation if present if (-not (Backup-ExistingAgent)) { Log-Message "Installation cancelled or backup failed" -IsError $true exit 1 } # Clone repository if (-not (Clone-Repository)) { Log-Message "FATAL: Failed to clone repository" -IsError $true exit 1 } # Create runtime folders if (-not (Create-RequiredRuntimeFolders)) { Log-Message "WARNING: Failed to create some runtime folders" -IsError $true # Don't exit - these may already exist } # Configure agent if (-not (Configure-Agent)) { Log-Message "WARNING: Configuration had errors" -IsError $true # Don't exit - user can configure manually } # Create scheduled task if (-not (Create-ScheduledTask)) { Log-Message "WARNING: Failed to create scheduled task" -IsError $true # Don't exit - user can create manually } # Start the scheduled task try { Start-ScheduledTask -TaskName "GSP Windows Agent" -ErrorAction SilentlyContinue Log-Message "Scheduled task started" } catch { Log-Message "WARNING: Could not start scheduled task immediately - it will start at next boot" } Log-Message "" Log-Message "=========================================" Log-Message "Installation Complete!" Log-Message "=========================================" Log-Message "Install location: $InstallPath" Log-Message "Agent will start at next system boot" Log-Message "Log file: $Script:InstallLogFile" Log-Message "" Log-Message "To update the agent later, run: update.bat" Log-Message "To rollback to a previous version, run: rollback.bat" Log-Message "" Read-Host "Press Enter to close this window" } # Run main installation Main