Add deployment automation system with build/publish workflow and fix path resolution
This commit introduces a complete deployment automation system for Windows Server deployment: New Features: - Publish-And-Deploy.ps1: Interactive console for building locally and transferring to server * Supports auto-detection of transfer method (Windows Share or SSH) * Configurable via deploy-config.json * Integrated with Build-ROA2WEB.ps1 for consistent builds - Check-And-Deploy.ps1: Server-side auto-deployment script * Monitors transfer directory for new packages * Automatically deploys when new version detected * Integrates with ROA2WEB-Console.ps1 for deployment - Setup-AutoDeploy.ps1: Configures scheduled task for auto-deployment - DEPLOYMENT_AUTOMATION.md: Complete documentation for automation workflow Bug Fixes: - Fix path resolution in Publish-And-Deploy.ps1: Added Resolve-FullPath function to correctly resolve ../deploy-package path - Fix ROA2WEB-Console.ps1 exit codes: Properly return boolean values and exit codes in non-interactive mode - Fix Build-ROA2WEB.ps1 script copying: Added debug output and force deletion to avoid caching issues Enhancements: - ROA2WEB-Console.ps1: Support for ROA2WEB_SOURCE environment variable for flexible source paths - Build-ROA2WEB.ps1: Enhanced debug output for troubleshooting script copying issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
472
deployment/windows/scripts/Setup-AutoDeploy.ps1
Normal file
472
deployment/windows/scripts/Setup-AutoDeploy.ps1
Normal file
@@ -0,0 +1,472 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
ROA2WEB - Auto-Deploy Setup Wizard (Server-Side)
|
||||
|
||||
.DESCRIPTION
|
||||
Interactive wizard to configure automatic deployment monitoring on Windows Server.
|
||||
Creates scheduled task that runs Check-And-Deploy.ps1 at specified intervals.
|
||||
|
||||
.PARAMETER MonitorPath
|
||||
Path to monitor for deployment packages (default: C:\Temp)
|
||||
|
||||
.PARAMETER ScriptsPath
|
||||
Path where Check-And-Deploy.ps1 is located (default: C:\Temp\ROA2WEB-Scripts)
|
||||
|
||||
.PARAMETER CheckIntervalMinutes
|
||||
How often to check for new packages in minutes (default: 5)
|
||||
|
||||
.PARAMETER AutoDeploy
|
||||
Automatically deploy new packages when found (default: true)
|
||||
|
||||
.PARAMETER CreateScheduledTask
|
||||
Create Windows Scheduled Task for automation (default: true)
|
||||
|
||||
.PARAMETER NonInteractive
|
||||
Run in non-interactive mode with provided parameters
|
||||
|
||||
.EXAMPLE
|
||||
.\Setup-AutoDeploy.ps1
|
||||
Launch interactive setup wizard
|
||||
|
||||
.EXAMPLE
|
||||
.\Setup-AutoDeploy.ps1 -NonInteractive -MonitorPath "C:\Temp" -CheckIntervalMinutes 5
|
||||
Non-interactive setup with defaults
|
||||
|
||||
.NOTES
|
||||
Author: ROA2WEB Team
|
||||
Version: 1.0 (Auto-Deploy Setup)
|
||||
Requires: Administrator privileges, PowerShell 5.1+
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$MonitorPath = "C:\Temp",
|
||||
[string]$ScriptsPath = "C:\Temp\ROA2WEB-Scripts",
|
||||
[int]$CheckIntervalMinutes = 5,
|
||||
[bool]$AutoDeploy = $true,
|
||||
[bool]$CreateScheduledTask = $true,
|
||||
[switch]$NonInteractive
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# =============================================================================
|
||||
# HELPER FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Write-Step {
|
||||
param([string]$Message)
|
||||
Write-Host "`n[*] $Message" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Write-Success {
|
||||
param([string]$Message)
|
||||
Write-Host " [OK] $Message" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Write-Error {
|
||||
param([string]$Message)
|
||||
Write-Host " [ERROR] $Message" -ForegroundColor Red
|
||||
}
|
||||
|
||||
function Write-Warning {
|
||||
param([string]$Message)
|
||||
Write-Host " [WARN] $Message" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
function Write-Info {
|
||||
param([string]$Message)
|
||||
Write-Host " [*] $Message" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# WIZARD FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Show-WizardWelcome {
|
||||
Clear-Host
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " ROA2WEB - Auto-Deploy Setup Wizard" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " This wizard will configure automatic deployment monitoring." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " What it does:" -ForegroundColor White
|
||||
Write-Host " • Creates directory structure for auto-deployment" -ForegroundColor Gray
|
||||
Write-Host " • Copies Check-And-Deploy.ps1 to scripts folder" -ForegroundColor Gray
|
||||
Write-Host " • Creates Windows Scheduled Task for monitoring" -ForegroundColor Gray
|
||||
Write-Host " • Configures auto-deploy settings" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to continue or Ctrl+C to cancel..." -ForegroundColor Yellow
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
}
|
||||
|
||||
function Get-WizardInput {
|
||||
param(
|
||||
[string]$Prompt,
|
||||
[string]$Default,
|
||||
[switch]$IsNumber,
|
||||
[switch]$IsYesNo
|
||||
)
|
||||
|
||||
do {
|
||||
Write-Host "`n$Prompt" -ForegroundColor Yellow
|
||||
if ($Default) {
|
||||
Write-Host " Default: $Default" -ForegroundColor Gray
|
||||
}
|
||||
Write-Host " > " -NoNewline -ForegroundColor Cyan
|
||||
$input = Read-Host
|
||||
|
||||
# Use default if empty
|
||||
if ([string]::IsNullOrWhiteSpace($input) -and $Default) {
|
||||
return $Default
|
||||
}
|
||||
|
||||
# Validate number
|
||||
if ($IsNumber) {
|
||||
$num = 0
|
||||
if ([int]::TryParse($input, [ref]$num) -and $num -gt 0) {
|
||||
return $num
|
||||
} else {
|
||||
Write-Host " Invalid number. Please enter a positive integer." -ForegroundColor Red
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
# Validate Yes/No
|
||||
if ($IsYesNo) {
|
||||
$normalized = $input.ToUpper()
|
||||
if ($normalized -eq "Y" -or $normalized -eq "YES") {
|
||||
return $true
|
||||
} elseif ($normalized -eq "N" -or $normalized -eq "NO") {
|
||||
return $false
|
||||
} else {
|
||||
Write-Host " Invalid input. Please enter Y or N." -ForegroundColor Red
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return $input
|
||||
} while ($true)
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# SETUP FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Test-Prerequisites {
|
||||
Write-Step "Checking prerequisites..."
|
||||
|
||||
# Check Administrator
|
||||
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
|
||||
$isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
|
||||
if (-not $isAdmin) {
|
||||
throw "This script requires Administrator privileges"
|
||||
}
|
||||
Write-Success "Running as Administrator"
|
||||
|
||||
# Check PowerShell version
|
||||
if ($PSVersionTable.PSVersion.Major -lt 5) {
|
||||
throw "PowerShell 5.1 or higher is required"
|
||||
}
|
||||
Write-Success "PowerShell version: $($PSVersionTable.PSVersion)"
|
||||
|
||||
# Check if Check-And-Deploy.ps1 exists
|
||||
$checkDeployScript = Join-Path $PSScriptRoot "Check-And-Deploy.ps1"
|
||||
if (-not (Test-Path $checkDeployScript)) {
|
||||
throw "Check-And-Deploy.ps1 not found in: $PSScriptRoot"
|
||||
}
|
||||
Write-Success "Check-And-Deploy.ps1 found"
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
function New-DirectoryStructure {
|
||||
param(
|
||||
[string]$MonitorPath,
|
||||
[string]$ScriptsPath
|
||||
)
|
||||
|
||||
Write-Step "Creating directory structure..."
|
||||
|
||||
# Create monitor path
|
||||
if (-not (Test-Path $MonitorPath)) {
|
||||
New-Item -ItemType Directory -Path $MonitorPath -Force | Out-Null
|
||||
Write-Success "Created: $MonitorPath"
|
||||
} else {
|
||||
Write-Success "Already exists: $MonitorPath"
|
||||
}
|
||||
|
||||
# Create scripts path
|
||||
if (-not (Test-Path $ScriptsPath)) {
|
||||
New-Item -ItemType Directory -Path $ScriptsPath -Force | Out-Null
|
||||
Write-Success "Created: $ScriptsPath"
|
||||
} else {
|
||||
Write-Success "Already exists: $ScriptsPath"
|
||||
}
|
||||
|
||||
# Create logs directory
|
||||
$logsPath = Join-Path $ScriptsPath "Logs"
|
||||
if (-not (Test-Path $logsPath)) {
|
||||
New-Item -ItemType Directory -Path $logsPath -Force | Out-Null
|
||||
Write-Success "Created: $logsPath"
|
||||
} else {
|
||||
Write-Success "Already exists: $logsPath"
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
function Copy-MonitorScript {
|
||||
param(
|
||||
[string]$SourcePath,
|
||||
[string]$DestPath
|
||||
)
|
||||
|
||||
Write-Step "Copying Check-And-Deploy.ps1 to scripts folder..."
|
||||
|
||||
$sourceScript = Join-Path $SourcePath "Check-And-Deploy.ps1"
|
||||
$destScript = Join-Path $DestPath "Check-And-Deploy.ps1"
|
||||
|
||||
# Check if source and destination are the same file
|
||||
$sourceFull = (Resolve-Path $sourceScript -ErrorAction SilentlyContinue).Path
|
||||
$destFull = (Resolve-Path $destScript -ErrorAction SilentlyContinue).Path
|
||||
|
||||
if ($sourceFull -and $destFull -and ($sourceFull -eq $destFull)) {
|
||||
Write-Success "Script already in target location: $destScript"
|
||||
return $destScript
|
||||
}
|
||||
|
||||
try {
|
||||
Copy-Item -Path $sourceScript -Destination $destScript -Force
|
||||
Write-Success "Script copied to: $destScript"
|
||||
return $destScript
|
||||
} catch {
|
||||
Write-Error "Failed to copy script: $_"
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function New-ScheduledTaskForAutoDeployNew {
|
||||
param(
|
||||
[string]$ScriptPath,
|
||||
[int]$IntervalMinutes,
|
||||
[string]$MonitorPath
|
||||
)
|
||||
|
||||
Write-Step "Creating Windows Scheduled Task..."
|
||||
|
||||
$taskName = "ROA2WEB-AutoDeploy"
|
||||
|
||||
# Remove existing task if present
|
||||
$existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
|
||||
if ($existingTask) {
|
||||
Write-Info "Removing existing task..."
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
|
||||
}
|
||||
|
||||
try {
|
||||
# Create action
|
||||
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" `
|
||||
-Argument "-NoProfile -ExecutionPolicy Bypass -File `"$ScriptPath`" -WatchPath `"$MonitorPath`""
|
||||
|
||||
# Create trigger (repeat indefinitely every X minutes)
|
||||
# Note: When RepetitionDuration is not specified, the task repeats indefinitely
|
||||
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) `
|
||||
-RepetitionInterval (New-TimeSpan -Minutes $IntervalMinutes)
|
||||
|
||||
# Create settings
|
||||
$settings = New-ScheduledTaskSettingsSet `
|
||||
-AllowStartIfOnBatteries `
|
||||
-DontStopIfGoingOnBatteries `
|
||||
-StartWhenAvailable `
|
||||
-RunOnlyIfNetworkAvailable:$false `
|
||||
-DontStopOnIdleEnd `
|
||||
-MultipleInstances IgnoreNew
|
||||
|
||||
# Register task (run as SYSTEM)
|
||||
Register-ScheduledTask -TaskName $taskName `
|
||||
-Action $action `
|
||||
-Trigger $trigger `
|
||||
-Settings $settings `
|
||||
-User "SYSTEM" `
|
||||
-RunLevel Highest `
|
||||
-Description "Monitors $MonitorPath for new deployment packages and auto-deploys them" | Out-Null
|
||||
|
||||
Write-Success "Scheduled task created: $taskName"
|
||||
Write-Success "Interval: Every $IntervalMinutes minutes"
|
||||
Write-Success "User: SYSTEM"
|
||||
Write-Success "Status: Enabled"
|
||||
|
||||
return $true
|
||||
} catch {
|
||||
Write-Error "Failed to create scheduled task: $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Show-SetupSummary {
|
||||
param(
|
||||
[hashtable]$Config
|
||||
)
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Setup Summary" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Monitor Path: $($Config.MonitorPath)" -ForegroundColor Gray
|
||||
Write-Host " Scripts Path: $($Config.ScriptsPath)" -ForegroundColor Gray
|
||||
Write-Host " Check Interval: $($Config.CheckIntervalMinutes) minutes" -ForegroundColor Gray
|
||||
Write-Host " Auto-Deploy: $($Config.AutoDeploy)" -ForegroundColor Gray
|
||||
Write-Host " Scheduled Task: $($Config.CreateScheduledTask)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Proceed with setup? [Y/N]: " -ForegroundColor Yellow -NoNewline
|
||||
$confirm = Read-Host
|
||||
|
||||
return ($confirm.ToUpper() -eq "Y" -or $confirm.ToUpper() -eq "YES")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MAIN SETUP FLOW
|
||||
# =============================================================================
|
||||
|
||||
function Invoke-Setup {
|
||||
param([hashtable]$Config)
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Starting Setup" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
try {
|
||||
# Test prerequisites
|
||||
Test-Prerequisites | Out-Null
|
||||
|
||||
# Create directory structure
|
||||
New-DirectoryStructure -MonitorPath $Config.MonitorPath -ScriptsPath $Config.ScriptsPath | Out-Null
|
||||
|
||||
# Copy monitor script
|
||||
$scriptPath = Copy-MonitorScript -SourcePath $PSScriptRoot -DestPath $Config.ScriptsPath
|
||||
|
||||
if (-not $scriptPath) {
|
||||
throw "Failed to copy monitor script"
|
||||
}
|
||||
|
||||
# Create scheduled task if requested
|
||||
if ($Config.CreateScheduledTask) {
|
||||
$taskSuccess = New-ScheduledTaskForAutoDeployNew `
|
||||
-ScriptPath $scriptPath `
|
||||
-IntervalMinutes $Config.CheckIntervalMinutes `
|
||||
-MonitorPath $Config.MonitorPath
|
||||
|
||||
if (-not $taskSuccess) {
|
||||
throw "Failed to create scheduled task"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Green
|
||||
Write-Host " SETUP COMPLETED SUCCESSFULLY" -ForegroundColor Green
|
||||
Write-Host ("=" * 70) -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host " Next Steps:" -ForegroundColor Yellow
|
||||
Write-Host " 1. Deploy packages will be placed in: $($Config.MonitorPath)" -ForegroundColor Gray
|
||||
Write-Host " 2. Server will check for updates every $($Config.CheckIntervalMinutes) minutes" -ForegroundColor Gray
|
||||
Write-Host " 3. New packages will be deployed automatically" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " Manual Testing:" -ForegroundColor Yellow
|
||||
Write-Host " - Test: cd $($Config.ScriptsPath) && .\\Check-And-Deploy.ps1 -Interactive" -ForegroundColor Gray
|
||||
Write-Host " - View Task: Get-ScheduledTask -TaskName 'ROA2WEB-AutoDeploy'" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Green
|
||||
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Red
|
||||
Write-Host " SETUP FAILED" -ForegroundColor Red
|
||||
Write-Host ("=" * 70) -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Error $_
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Red
|
||||
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MAIN EXECUTION FLOW
|
||||
# =============================================================================
|
||||
|
||||
function Main {
|
||||
# Non-interactive mode
|
||||
if ($NonInteractive) {
|
||||
$config = @{
|
||||
MonitorPath = $MonitorPath
|
||||
ScriptsPath = $ScriptsPath
|
||||
CheckIntervalMinutes = $CheckIntervalMinutes
|
||||
AutoDeploy = $AutoDeploy
|
||||
CreateScheduledTask = $CreateScheduledTask
|
||||
}
|
||||
|
||||
Invoke-Setup -Config $config | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
# Interactive mode - Wizard
|
||||
Show-WizardWelcome
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Configuration Wizard" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
# Step 1: Monitor Path
|
||||
$monitorPath = Get-WizardInput -Prompt "[1/5] Deploy Folder Path`n Path to monitor for new deployment packages:" -Default $MonitorPath
|
||||
|
||||
# Step 2: Scripts Path
|
||||
$scriptsPath = Get-WizardInput -Prompt "[2/5] Scripts Folder Path`n Path to store monitoring scripts:" -Default $ScriptsPath
|
||||
|
||||
# Step 3: Check Interval
|
||||
$checkInterval = Get-WizardInput -Prompt "[3/5] Check Interval`n How often to check for updates (minutes):" -Default $CheckIntervalMinutes -IsNumber
|
||||
|
||||
# Step 4: Auto-Deploy
|
||||
Write-Host "`n[4/5] Auto-Deploy Enabled" -ForegroundColor Yellow
|
||||
Write-Host " Deploy automatically when new package found?" -ForegroundColor Yellow
|
||||
Write-Host " [Y] Yes (recommended) [N] No (manual trigger only)" -ForegroundColor Gray
|
||||
$autoDeploy = Get-WizardInput -Prompt " Your choice:" -Default "Y" -IsYesNo
|
||||
|
||||
# Step 5: Scheduled Task
|
||||
Write-Host "`n[5/5] Create Scheduled Task" -ForegroundColor Yellow
|
||||
Write-Host " Create Windows Scheduled Task for automatic monitoring?" -ForegroundColor Yellow
|
||||
Write-Host " [Y] Yes [N] No" -ForegroundColor Gray
|
||||
$createTask = Get-WizardInput -Prompt " Your choice:" -Default "Y" -IsYesNo
|
||||
|
||||
# Configuration object
|
||||
$config = @{
|
||||
MonitorPath = $monitorPath
|
||||
ScriptsPath = $scriptsPath
|
||||
CheckIntervalMinutes = [int]$checkInterval
|
||||
AutoDeploy = $autoDeploy
|
||||
CreateScheduledTask = $createTask
|
||||
}
|
||||
|
||||
# Show summary and confirm
|
||||
$confirmed = Show-SetupSummary -Config $config
|
||||
|
||||
if ($confirmed) {
|
||||
Invoke-Setup -Config $config
|
||||
} else {
|
||||
Write-Host "`nSetup cancelled by user" -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "`nPress any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
}
|
||||
|
||||
# Run main
|
||||
Main
|
||||
Reference in New Issue
Block a user