#Requires -Version 5.1 #Requires -RunAsAdministrator <# .SYNOPSIS Registers Windows Scheduled Tasks for CI system maintenance. .DESCRIPTION Creates or updates two tasks under the \CI\ task folder: CI-CleanupOrphans — Runs Cleanup-OrphanedBuildVMs.ps1 every 6 hours and at host startup. Destroys stale build VMs (those older than -MaxAgeHours, default 4) that were not cleaned up after a crash or timeout. CI-RetentionPolicy — Runs Invoke-RetentionPolicy.ps1 daily at 3:00 AM and at host startup (with a 15-min random delay). Purges old artifact and log directories per the configured retention window. Both tasks run as SYSTEM with highest privilege. Idempotent: safe to re-run after updating the scripts — existing tasks are overwritten (-Force). .PARAMETER ScriptRoot Directory containing the CI scripts. Default: N:\Code\Workspace\Local-CI-CD-System\scripts .PARAMETER MaxAgeHours Passed to Cleanup-OrphanedBuildVMs.ps1. VMs older than this are treated as orphaned. Must exceed the longest expected build duration. Default: 4 .EXAMPLE # Register (or update) tasks — run from an elevated PowerShell session .\Register-CIScheduledTasks.ps1 # Preview what would be registered .\Register-CIScheduledTasks.ps1 -WhatIf #> [CmdletBinding(SupportsShouldProcess)] param( [string] $ScriptRoot = 'N:\Code\Workspace\Local-CI-CD-System\scripts', [ValidateRange(1, 168)] [int] $MaxAgeHours = 4 ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $psExe = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" $taskPath = '\CI\' $principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -RunLevel Highest # Ensure task folder exists (Register-ScheduledTask creates it, but be explicit) $schedulerService = New-Object -ComObject 'Schedule.Service' $schedulerService.Connect() $rootFolder = $schedulerService.GetFolder('\') try { $rootFolder.GetFolder('CI') | Out-Null } catch { $rootFolder.CreateFolder('CI') | Out-Null } [System.Runtime.InteropServices.Marshal]::ReleaseComObject($schedulerService) | Out-Null # ── Task 1: CI-CleanupOrphans ───────────────────────────────────────────────── $cleanupScript = Join-Path $ScriptRoot 'Cleanup-OrphanedBuildVMs.ps1' if (-not (Test-Path $cleanupScript -PathType Leaf)) { Write-Warning "Script not found — skipping CI-CleanupOrphans: $cleanupScript" } else { $cleanupAction = New-ScheduledTaskAction ` -Execute $psExe ` -Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$cleanupScript`" -MaxAgeHours $MaxAgeHours" # Repeat every 6 hours indefinitely (Once trigger + RepetitionInterval) $repeat6h = New-ScheduledTaskTrigger -Once -At '00:00' ` -RepetitionInterval (New-TimeSpan -Hours 6) $atStartup = New-ScheduledTaskTrigger -AtStartup $cleanupSettings = New-ScheduledTaskSettingsSet ` -ExecutionTimeLimit (New-TimeSpan -Hours 1) ` -MultipleInstances IgnoreNew ` -StartWhenAvailable if ($PSCmdlet.ShouldProcess('CI-CleanupOrphans', 'Register/update scheduled task')) { Register-ScheduledTask ` -TaskName 'CI-CleanupOrphans' ` -TaskPath $taskPath ` -Action $cleanupAction ` -Trigger @($repeat6h, $atStartup) ` -Principal $principal ` -Settings $cleanupSettings ` -Description "Destroys orphaned CI build VMs older than ${MaxAgeHours}h (Local CI/CD System)" ` -Force | Out-Null Write-Host "[Register] CI-CleanupOrphans registered (every 6h + at startup, -MaxAgeHours $MaxAgeHours)." -ForegroundColor Green } } # ── Task 2: CI-RetentionPolicy ──────────────────────────────────────────────── $retentionScript = Join-Path $ScriptRoot 'Invoke-RetentionPolicy.ps1' if (-not (Test-Path $retentionScript -PathType Leaf)) { Write-Warning "Script not found — skipping CI-RetentionPolicy: $retentionScript" } else { $retentionAction = New-ScheduledTaskAction ` -Execute $psExe ` -Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$retentionScript`"" $daily3am = New-ScheduledTaskTrigger -Daily -At '03:00' ` -RandomDelay (New-TimeSpan -Minutes 30) $atStartup2 = New-ScheduledTaskTrigger -AtStartup ` -RandomDelay (New-TimeSpan -Minutes 15) $retentionSettings = New-ScheduledTaskSettingsSet ` -ExecutionTimeLimit (New-TimeSpan -Hours 1) ` -MultipleInstances IgnoreNew ` -StartWhenAvailable if ($PSCmdlet.ShouldProcess('CI-RetentionPolicy', 'Register/update scheduled task')) { Register-ScheduledTask ` -TaskName 'CI-RetentionPolicy' ` -TaskPath $taskPath ` -Action $retentionAction ` -Trigger @($daily3am, $atStartup2) ` -Principal $principal ` -Settings $retentionSettings ` -Description 'Purges old CI artifacts, logs, and stale IP leases (Local CI/CD System)' ` -Force | Out-Null Write-Host "[Register] CI-RetentionPolicy registered (daily 03:00 + at startup)." -ForegroundColor Green } } Write-Host "`n[Register] Done. Verify with: Get-ScheduledTask -TaskPath '\CI\' | Format-Table TaskName, State" -ForegroundColor Cyan