466 lines
16 KiB
PowerShell
466 lines
16 KiB
PowerShell
# 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
|