simplified bootstrapper script and introduced --install parameter for agent

This commit is contained in:
Oliver Kieselbach
2026-02-13 17:29:48 +01:00
parent 731894bc04
commit 65a20febcb
3 changed files with 194 additions and 51 deletions
+9 -50
View File
@@ -37,16 +37,11 @@ param(
# Configuration - Everything in ProgramData for easy cleanup
$AgentBasePath = "$env:ProgramData\AutopilotMonitor"
$AgentBinPath = "$AgentBasePath\Agent"
$AgentSpoolPath = "$AgentBasePath\Spool"
$AgentLogsPath = "$AgentBasePath\Logs"
$TaskName = "AutopilotMonitor-Agent"
$LogFile = "$AgentLogsPath\Bootstrap.log"
$LogFile = "$AgentBasePath\Bootstrap.log"
# Ensure directories exist
New-Item -Path $AgentBasePath -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -Path $AgentBinPath -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -Path $AgentSpoolPath -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -Path $AgentLogsPath -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
function Write-Log {
param([string]$Message)
@@ -213,54 +208,18 @@ try {
}
}
# Register as Scheduled Task (survives reboots, easy to remove)
Write-Log "Registering Scheduled Task..."
# Check if task already exists
$existingTask = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
if ($null -ne $existingTask) {
Write-Log "Scheduled Task already exists - removing old task"
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
# Let the agent install/deploy itself and manage its own Scheduled Task
Write-Log "Calling agent install mode (--install)..."
& $agentExePath --install
$installExitCode = $LASTEXITCODE
if ($installExitCode -ne 0) {
throw "Agent install failed with exit code $installExitCode"
}
# Create action - run agent executable
$action = New-ScheduledTaskAction -Execute $agentExePath -WorkingDirectory $AgentBinPath
# Create trigger - run at computer startup
$trigger = New-ScheduledTaskTrigger -AtStartup
# Create settings - run whether user is logged on or not
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries `
-StartWhenAvailable `
-RunOnlyIfNetworkAvailable `
-ExecutionTimeLimit (New-TimeSpan -Hours 0) # No time limit
# Create principal - run as SYSTEM
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
# Register the task
Register-ScheduledTask `
-TaskName $TaskName `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Principal $principal `
-Description "Autopilot Monitor Agent - Temporary enrollment monitoring" `
-Force
Write-Log "Scheduled Task registered successfully"
# Start the task immediately (don't wait for next reboot)
Write-Log "Starting agent task..."
Start-ScheduledTask -TaskName $TaskName
Write-Log "Agent task started"
Write-Log "Agent install mode completed successfully"
Write-Log "===== Bootstrap Completed Successfully ====="
Write-Log "Agent Path: $AgentBasePath"
Write-Log "Scheduled Task: $TaskName"
Write-Log "Scheduled Task: managed by agent (--install)"
Write-Log "Agent will monitor enrollment and auto-remove when complete"
Write-Log "Bootstrap log: $LogFile"
Write-Log ""
+184
View File
@@ -15,6 +15,13 @@ namespace AutopilotMonitor.Agent
{
static void Main(string[] args)
{
// Install mode: ensure folders, deploy payload, create/update Scheduled Task, and start it.
if (args.Contains("--install"))
{
RunInstallMode(args);
return;
}
// Check for mass rollout simulator mode
if (args.Contains("--simulator-mass-rollout"))
{
@@ -28,6 +35,86 @@ namespace AutopilotMonitor.Agent
RunAgent(args);
}
static void RunInstallMode(string[] args)
{
var logDir = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor\Logs");
var logger = new AgentLogger(logDir, enableDebug: true);
var consoleMode = args.Contains("--console") || Environment.UserInteractive;
try
{
logger.Info("======================= Agent install mode (--install) =======================");
EnsureAgentDirectories(logger);
var sourceExePath = Assembly.GetExecutingAssembly().Location;
var sourceDir = Path.GetDirectoryName(sourceExePath) ?? string.Empty;
var targetAgentDir = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor\Agent");
var targetExePath = Path.Combine(targetAgentDir, "AutopilotMonitor.Agent.exe");
if (!string.Equals(
Path.GetFullPath(sourceDir).TrimEnd('\\'),
Path.GetFullPath(targetAgentDir).TrimEnd('\\'),
StringComparison.OrdinalIgnoreCase))
{
logger.Info($"Install mode called from '{sourceDir}'. Deploying payload to '{targetAgentDir}'.");
CopyDirectory(sourceDir, targetAgentDir, logger);
}
else
{
logger.Info("Agent already running from target install directory; payload copy not required.");
}
var taskName = "AutopilotMonitor-Agent";
var taskCommand = $"\"{targetExePath}\"";
logger.Info($"Registering Scheduled Task '{taskName}' for executable: {targetExePath}");
var createExitCode = RunProcess(
"schtasks.exe",
$"/Create /TN \"{taskName}\" /TR \"{taskCommand}\" /SC ONSTART /RU SYSTEM /RL HIGHEST /F",
logger);
if (createExitCode != 0)
{
throw new InvalidOperationException($"Failed to create/update Scheduled Task '{taskName}' (exit code {createExitCode})");
}
logger.Info($"Scheduled Task '{taskName}' created/updated successfully");
var startExitCode = RunProcess(
"schtasks.exe",
$"/Run /TN \"{taskName}\"",
logger);
if (startExitCode != 0)
{
throw new InvalidOperationException($"Failed to start Scheduled Task '{taskName}' (exit code {startExitCode})");
}
logger.Info($"Scheduled Task '{taskName}' started successfully");
if (consoleMode)
{
Console.WriteLine("Installation completed successfully.");
Console.WriteLine($"Task: {taskName}");
Console.WriteLine($"Executable: {targetExePath}");
Console.WriteLine($"Log: {logDir}");
}
Environment.Exit(0);
}
catch (Exception ex)
{
logger.Error("Registration mode failed", ex);
if (consoleMode)
{
Console.WriteLine($"ERROR: {ex.Message}");
}
Environment.Exit(1);
}
}
static void RunAgent(string[] args)
{
var consoleMode = args.Contains("--console") || Environment.UserInteractive;
@@ -416,6 +503,103 @@ namespace AutopilotMonitor.Agent
return null;
}
private static void EnsureAgentDirectories(AgentLogger logger)
{
var basePath = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor");
var paths = new[]
{
basePath,
Path.Combine(basePath, "Agent"),
Path.Combine(basePath, "Spool"),
Path.Combine(basePath, "Logs")
};
foreach (var path in paths)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
logger.Info($"Created directory: {path}");
}
else
{
logger.Debug($"Directory already exists: {path}");
}
}
}
private static int RunProcess(string fileName, string arguments, AgentLogger logger)
{
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
logger.Info($"Executing: {fileName} {arguments}");
using (var process = Process.Start(psi))
{
if (process == null)
throw new InvalidOperationException($"Failed to start process: {fileName}");
var stdout = process.StandardOutput.ReadToEnd();
var stderr = process.StandardError.ReadToEnd();
process.WaitForExit();
if (!string.IsNullOrWhiteSpace(stdout))
logger.Info($"Process output: {stdout.Trim()}");
if (!string.IsNullOrWhiteSpace(stderr))
logger.Warning($"Process error output: {stderr.Trim()}");
logger.Info($"Process exit code: {process.ExitCode}");
return process.ExitCode;
}
}
private static void CopyDirectory(string sourceDir, string targetDir, AgentLogger logger)
{
if (!Directory.Exists(sourceDir))
throw new DirectoryNotFoundException($"Source directory not found: {sourceDir}");
Directory.CreateDirectory(targetDir);
foreach (var dir in Directory.GetDirectories(sourceDir, "*", SearchOption.AllDirectories))
{
var rel = dir.Substring(sourceDir.Length).TrimStart('\\');
Directory.CreateDirectory(Path.Combine(targetDir, rel));
}
foreach (var file in Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories))
{
var rel = file.Substring(sourceDir.Length).TrimStart('\\');
var dest = Path.Combine(targetDir, rel);
Directory.CreateDirectory(Path.GetDirectoryName(dest) ?? targetDir);
try
{
File.Copy(file, dest, true);
}
catch (Exception ex)
{
// If destination exists, keep going and let scheduled task use the latest available payload.
if (File.Exists(dest))
{
logger.Warning($"Could not overwrite '{dest}': {ex.Message}. Keeping existing file.");
continue;
}
throw;
}
}
logger.Info($"Payload deployment completed: '{sourceDir}' -> '{targetDir}'");
}
/// <summary>
/// Checks if another AutopilotMonitor.Agent.exe process is already running.
/// </summary>
@@ -1 +1 @@
9
12