mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 04:32:32 +00:00
feat: added DevPrepValidator (device association) and restructured agent to distinguish Classic vs v2 autopilot flow, in addition option for dev build added
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
DEV variant of the bootstrap script to deploy and start the Autopilot Monitor agent.
|
||||
|
||||
.DESCRIPTION
|
||||
Funktionally identical to Install-AutopilotMonitor.ps1 with two differences:
|
||||
1. Default $AgentDownloadUrl points to AutopilotMonitor-Agent-dev.zip
|
||||
2. Integrity check is read from version-dev.json (NOT version.json)
|
||||
This enables parallel lab testing of unreleased agent builds via a dedicated
|
||||
Intune Platform Script assignment, without touching any production artefacts.
|
||||
|
||||
See Install-AutopilotMonitor.ps1 for the full behaviour (guards, SHA-256
|
||||
integrity verification, scheduled task registration via --install, etc.).
|
||||
|
||||
.PARAMETER AgentDownloadUrl
|
||||
URL to download the DEV agent binaries from (ZIP file). Defaults to
|
||||
AutopilotMonitor-Agent-dev.zip in the same blob container as production.
|
||||
|
||||
.NOTES
|
||||
- ASCII-only. PowerShell 5.1 / IME AgentExecutor reads scripts without BOM
|
||||
as ANSI and corrupts multi-byte chars.
|
||||
- Guards are intentionally identical to Prod bootstrapper so lab behaviour
|
||||
matches production behaviour on fresh images.
|
||||
|
||||
.CHANGELOG
|
||||
2026-04-14 v1.1-dev Initial DEV variant forked from Install-AutopilotMonitor.ps1 v1.1.
|
||||
Default URL -> AutopilotMonitor-Agent-dev.zip, integrity file -> version-dev.json.
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$AgentDownloadUrl = "https://autopilotmonitor.blob.core.windows.net/agent/AutopilotMonitor-Agent-dev.zip",
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[int]$MaxBootstrapWindowHours = 12
|
||||
)
|
||||
|
||||
# Script version (bump on meaningful changes; see .CHANGELOG above)
|
||||
$ScriptVersion = "1.1-dev"
|
||||
|
||||
# Configuration - Everything in ProgramData for easy cleanup
|
||||
$AgentBasePath = "$env:ProgramData\AutopilotMonitor"
|
||||
$AgentBinPath = "$AgentBasePath\Agent"
|
||||
$AgentLogPath = "$AgentBasePath\Logs"
|
||||
$LogFile = "$AgentLogPath\bootstrap_agent.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 $AgentLogPath -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
|
||||
|
||||
function Write-Log {
|
||||
param([string]$Message)
|
||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
$logMessage = "[$timestamp] $Message"
|
||||
Write-Output $logMessage
|
||||
Add-Content -Path $LogFile -Value $logMessage -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
function Get-FileMd5Base64 {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
$md5 = [System.Security.Cryptography.MD5]::Create()
|
||||
try {
|
||||
$stream = [System.IO.File]::OpenRead($Path)
|
||||
try {
|
||||
$hashBytes = $md5.ComputeHash($stream)
|
||||
}
|
||||
finally {
|
||||
$stream.Dispose()
|
||||
}
|
||||
|
||||
return [Convert]::ToBase64String($hashBytes)
|
||||
}
|
||||
finally {
|
||||
$md5.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Log "===== Autopilot Monitor Bootstrap Started (DEV) ====="
|
||||
Write-Log "Bootstrap script version: v$ScriptVersion"
|
||||
Write-Log "Agent download URL: $AgentDownloadUrl"
|
||||
|
||||
# -- Pre-flight: Multi-signal guard (identical to production bootstrapper) --
|
||||
# Guard 1: Ghost re-installs (registry marker from previous deployment)
|
||||
# Guard 2: Productive devices (real user profile exists -- WMI + filesystem)
|
||||
# Guard 3: Productive devices (a real user has logged on before)
|
||||
# Guard 4: Bootstrap window expired (device uptime > 12h without agent)
|
||||
# Guard 5: Agent binary already present from a previous run
|
||||
|
||||
# Guard 1
|
||||
$deployed = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\AutopilotMonitor' -Name 'Deployed' -ErrorAction SilentlyContinue).Deployed
|
||||
if ($deployed) {
|
||||
Write-Log "SKIP: Agent was previously deployed at $deployed."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Guard 2
|
||||
$excludePattern = '^(defaultuser\d*|Public|Default( User)?|All Users)$'
|
||||
|
||||
$profileNames = @(
|
||||
try {
|
||||
Get-CimInstance Win32_UserProfile -ErrorAction Stop |
|
||||
Where-Object { -not $_.Special -and $_.LocalPath -like 'C:\Users\*' } |
|
||||
ForEach-Object { Split-Path $_.LocalPath -Leaf }
|
||||
} catch { Write-Log "INFO: WMI profile query failed, continuing with filesystem check." }
|
||||
|
||||
(Get-ChildItem 'C:\Users' -Directory -ErrorAction SilentlyContinue).Name
|
||||
) | Where-Object { $_ -and $_ -notmatch $excludePattern } |
|
||||
Select-Object -Unique
|
||||
|
||||
if ($profileNames) {
|
||||
$names = ($profileNames | Select-Object -First 3) -join ', '
|
||||
Write-Log "SKIP: Real user profile(s) found ($names). Device appears productive."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Guard 3
|
||||
$lastLoggedOnUser = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI' -Name 'LastLoggedOnUser' -EA SilentlyContinue).LastLoggedOnUser
|
||||
if ($lastLoggedOnUser -and $lastLoggedOnUser -notmatch 'defaultuser\d*') {
|
||||
Write-Log "SKIP: LastLoggedOnUser found ($lastLoggedOnUser). Device appears productive."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Guard 4
|
||||
$lastBoot = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
|
||||
$uptimeHours = ((Get-Date) - $lastBoot).TotalHours
|
||||
Write-Log "Device uptime: $([int]$uptimeHours)h (last boot: $lastBoot)"
|
||||
if ($uptimeHours -gt $MaxBootstrapWindowHours) {
|
||||
Write-Log "SKIP: Device uptime is $([int]$uptimeHours)h. OOBE state is older than accepted bootstrap window of ${MaxBootstrapWindowHours}h."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Guard 5
|
||||
if (Test-Path $AgentBinPath) {
|
||||
$existingAgent = Get-ChildItem -Path $AgentBinPath -Filter "AutopilotMonitor.Agent.exe" -ErrorAction SilentlyContinue
|
||||
if ($existingAgent) {
|
||||
Write-Log "SKIP: Agent already installed at $($existingAgent.FullName)."
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
Write-Log "Pre-flight checks passed -- no prior deployment, no real user profiles, no logged-on user, within bootstrap window"
|
||||
|
||||
# Download and extract agent binaries
|
||||
$agentExePath = Join-Path $AgentBinPath "AutopilotMonitor.Agent.exe"
|
||||
|
||||
if (Test-Path $agentExePath) {
|
||||
Write-Log "Agent already installed at $agentExePath"
|
||||
}
|
||||
else {
|
||||
Write-Log "Downloading DEV agent from $AgentDownloadUrl..."
|
||||
|
||||
try {
|
||||
# DEV: Integrity-File ist version-dev.json (im selben Container wie das -dev ZIP)
|
||||
$versionJsonUrl = $AgentDownloadUrl -replace '[^/]+$', 'version-dev.json'
|
||||
$expectedSha256 = $null
|
||||
|
||||
try {
|
||||
Write-Log "Fetching version-dev.json from $versionJsonUrl for integrity verification..."
|
||||
$versionJsonResponse = Invoke-RestMethod -Uri $versionJsonUrl -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop
|
||||
if ($versionJsonResponse.sha256) {
|
||||
$expectedSha256 = $versionJsonResponse.sha256.ToLowerInvariant()
|
||||
Write-Log "SHA-256 hash from version-dev.json: $expectedSha256 (version: $($versionJsonResponse.version))"
|
||||
} else {
|
||||
Write-Log "version-dev.json has no sha256 field - falling back to legacy MD5 check"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Log "WARNING: Could not fetch version-dev.json - falling back to legacy MD5 check: $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
$zipPath = Join-Path $env:TEMP "AutopilotMonitor-Agent-dev.zip"
|
||||
$maxDownloadAttempts = 3
|
||||
$downloadAttempt = 0
|
||||
$downloadResponse = $null
|
||||
|
||||
do {
|
||||
$downloadAttempt++
|
||||
try {
|
||||
Write-Log "Download attempt ${downloadAttempt}/${maxDownloadAttempts}"
|
||||
$downloadResponse = Invoke-WebRequest `
|
||||
-Uri $AgentDownloadUrl `
|
||||
-OutFile $zipPath `
|
||||
-UseBasicParsing `
|
||||
-TimeoutSec 30 `
|
||||
-ErrorAction Stop `
|
||||
-PassThru
|
||||
Write-Log "Downloaded agent to $zipPath"
|
||||
break
|
||||
}
|
||||
catch {
|
||||
if ($downloadAttempt -ge $maxDownloadAttempts) {
|
||||
throw
|
||||
}
|
||||
|
||||
$retryDelaysInSeconds = @(2, 4, 8)
|
||||
$retryDelaySeconds = $retryDelaysInSeconds[$downloadAttempt - 1]
|
||||
Write-Log "Download failed (attempt $downloadAttempt): $($_.Exception.Message). Retrying in ${retryDelaySeconds}s..."
|
||||
Start-Sleep -Seconds $retryDelaySeconds
|
||||
}
|
||||
} while ($downloadAttempt -lt $maxDownloadAttempts)
|
||||
|
||||
if ($expectedSha256) {
|
||||
$actualSha256 = (Get-FileHash $zipPath -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
Write-Log "Validating SHA-256 hash against version-dev.json"
|
||||
if ($actualSha256 -ne $expectedSha256) {
|
||||
throw "SHA-256 integrity check FAILED. Expected='$expectedSha256', Actual='$actualSha256'. Download may be tampered or corrupted."
|
||||
}
|
||||
Write-Log "SHA-256 integrity check passed"
|
||||
}
|
||||
else {
|
||||
$expectedMd5Header = $downloadResponse.Headers["Content-MD5"]
|
||||
$expectedMd5 = if ($expectedMd5Header -is [System.Array]) { "$($expectedMd5Header[0])".Trim() } else { "$expectedMd5Header".Trim() }
|
||||
if ($expectedMd5 -notmatch '\S') {
|
||||
Write-Log "WARNING: No SHA-256 and no Content-MD5 header - skipping integrity validation"
|
||||
}
|
||||
else {
|
||||
$actualMd5 = Get-FileMd5Base64 -Path $zipPath
|
||||
Write-Log "Validating Content-MD5 header against downloaded ZIP"
|
||||
if ($actualMd5 -ne $expectedMd5) {
|
||||
throw "MD5 integrity check failed. Expected (Content-MD5)='$expectedMd5', Actual='$actualMd5'"
|
||||
}
|
||||
Write-Log "MD5 integrity check passed"
|
||||
}
|
||||
}
|
||||
|
||||
Expand-Archive -Path $zipPath -DestinationPath $AgentBinPath -Force
|
||||
Write-Log "Extracted agent to $AgentBinPath"
|
||||
|
||||
Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
|
||||
Write-Log "Cleaned up temporary files"
|
||||
|
||||
if (-not (Test-Path $agentExePath)) {
|
||||
throw "Agent executable not found after extraction at $agentExePath"
|
||||
}
|
||||
|
||||
Write-Log "DEV agent installation completed successfully"
|
||||
}
|
||||
catch {
|
||||
Write-Log "ERROR downloading/extracting agent: $($_.Exception.Message)"
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
Write-Log "Calling agent install mode (--install)..."
|
||||
& $agentExePath --install
|
||||
$installExitCode = $LASTEXITCODE
|
||||
if ($installExitCode -ne 0) {
|
||||
throw "Agent install failed with exit code $installExitCode"
|
||||
}
|
||||
Write-Log "Agent install mode completed successfully"
|
||||
Write-Log "===== Bootstrap Completed Successfully (DEV) ====="
|
||||
|
||||
exit 0
|
||||
}
|
||||
catch {
|
||||
Write-Log "===== Bootstrap FAILED (DEV) ====="
|
||||
Write-Log "ERROR: $($_.Exception.Message)"
|
||||
Write-Log "Stack trace: $($_.ScriptStackTrace)"
|
||||
Write-Log "Please check log file: $LogFile"
|
||||
|
||||
$errMsg = "AutopilotMonitor bootstrap (DEV) failed: $($_.Exception.Message)"
|
||||
if ($errMsg.Length -gt 2048) { $errMsg = $errMsg.Substring(0, 1045) + '...' }
|
||||
[Console]::Error.WriteLine($errMsg)
|
||||
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
# Upload DEV Debug Agent Build Script
|
||||
# Builds the Debug output, creates a separate -dev ZIP archive, and uploads it
|
||||
# (plus version-dev.json and the DEV bootstrapper) to Azure Blob Storage.
|
||||
#
|
||||
# Unterschiede zum produktiven Script (build_and_upload_debug_agent_build.ps1):
|
||||
# - ZIP-Name: AutopilotMonitor-Agent-dev.zip (nicht AutopilotMonitor-Agent.zip)
|
||||
# - Integrity-File: version-dev.json (nicht version.json)
|
||||
# - Bootstrap-Upload: Install-AutopilotMonitor-Dev.ps1 (nicht Install-AutopilotMonitor.ps1)
|
||||
# - KEIN Upload von: version.json, Install-AutopilotMonitor.ps1, Test-ShouldBootstrapAgent.ps1
|
||||
# - KEIN Update von: AdminConfiguration Table (Hash-Oracle bleibt produktiv unangetastet)
|
||||
#
|
||||
# => Produktion wird bit-identisch NICHT beeinflusst. Lab-Geraete ziehen via separater
|
||||
# Intune-Assignment das Dev-ZIP ueber den Dev-Bootstrapper.
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Configuration
|
||||
$projectPath = "C:\Code\GitHubRepos\Autopilot-Monitor\src\Agent\AutopilotMonitor.Agent\AutopilotMonitor.Agent.csproj"
|
||||
$summaryDialogProjectPath = "C:\Code\GitHubRepos\Autopilot-Monitor\src\Agent\AutopilotMonitor.SummaryDialog\AutopilotMonitor.SummaryDialog.csproj"
|
||||
$buildConfiguration = "Debug"
|
||||
$sourcePath = "C:\Code\GitHubRepos\Autopilot-Monitor\src\Agent\AutopilotMonitor.Agent\bin\Debug\net48"
|
||||
$summaryDialogOutputPath = "C:\Code\GitHubRepos\Autopilot-Monitor\src\Agent\AutopilotMonitor.SummaryDialog\bin\Debug\net48"
|
||||
$bootstrapScriptPath = "C:\Code\GitHubRepos\Autopilot-Monitor\scripts\Bootstrap\Install-AutopilotMonitor-Dev.ps1"
|
||||
$zipFileName = "AutopilotMonitor-Agent-dev.zip"
|
||||
$versionJsonDevName = "version-dev.json"
|
||||
$tempZipPath = [System.IO.Path]::Combine($env:TEMP, $zipFileName)
|
||||
$tempVersionDevPath = [System.IO.Path]::Combine($env:TEMP, $versionJsonDevName)
|
||||
$bootstrapScriptName = [System.IO.Path]::GetFileName($bootstrapScriptPath)
|
||||
$sasUrl = "https://autopilotmonitor.blob.core.windows.net/agent?sp=cw&st=2026-02-17T16:10:55Z&se=2028-02-18T00:25:55Z&spr=https&sv=2024-11-04&sr=c&sig=kA%2BeZlpqf4fYUvmO5YgFv%2Fk7yr6oQLPA51%2FDSQEl7hs%3D"
|
||||
$sasQuery = $sasUrl.Substring($sasUrl.IndexOf('?'))
|
||||
$blobUrl = "https://autopilotmonitor.blob.core.windows.net/agent/$zipFileName$sasQuery"
|
||||
$bootstrapBlobUrl = "https://autopilotmonitor.blob.core.windows.net/agent/$bootstrapScriptName$sasQuery"
|
||||
$versionDevBlobUrl = "https://autopilotmonitor.blob.core.windows.net/agent/$versionJsonDevName$sasQuery"
|
||||
|
||||
Write-Host "=== DEV Agent Build and Upload ===" -ForegroundColor Magenta
|
||||
Write-Host "Project: $projectPath" -ForegroundColor Gray
|
||||
Write-Host "Build output folder: $sourcePath" -ForegroundColor Gray
|
||||
Write-Host "Dev bootstrap script: $bootstrapScriptPath" -ForegroundColor Gray
|
||||
Write-Host "Dev ZIP name: $zipFileName" -ForegroundColor Gray
|
||||
Write-Host "Dev integrity file: $versionJsonDevName" -ForegroundColor Gray
|
||||
Write-Host "Started at (UTC): $([DateTime]::UtcNow.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Gray
|
||||
|
||||
try {
|
||||
# [1] Build Agent
|
||||
Write-Host "`n[1/7] Building Agent project ($buildConfiguration)..." -ForegroundColor Yellow
|
||||
dotnet build $projectPath -c $buildConfiguration
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Agent build failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
Write-Host " Agent build completed successfully" -ForegroundColor Green
|
||||
|
||||
# Verify EXE version matches version.json (prevents silent MSBuild version timing bugs)
|
||||
$versionJsonCheck = Get-Content (Join-Path $sourcePath "version.json") -Raw | ConvertFrom-Json
|
||||
$exeVersionCheck = [System.Diagnostics.FileVersionInfo]::GetVersionInfo((Join-Path $sourcePath "AutopilotMonitor.Agent.exe")).ProductVersion
|
||||
$exeVersionClean = $exeVersionCheck -replace '\+.*$', ''
|
||||
if ($exeVersionClean -ne $versionJsonCheck.version) {
|
||||
throw "VERSION MISMATCH: EXE reports '$exeVersionClean' but version.json says '$($versionJsonCheck.version)'. MSBuild property evaluation timing issue detected."
|
||||
}
|
||||
Write-Host " Version verified: EXE=$exeVersionClean matches version.json=$($versionJsonCheck.version)" -ForegroundColor Green
|
||||
|
||||
# [2] Build SummaryDialog
|
||||
Write-Host "`n[2/7] Building SummaryDialog project ($buildConfiguration)..." -ForegroundColor Yellow
|
||||
dotnet build $summaryDialogProjectPath -c $buildConfiguration
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "SummaryDialog build failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
Write-Host " SummaryDialog build completed successfully" -ForegroundColor Green
|
||||
|
||||
# [3] Run Agent unit tests
|
||||
Write-Host "`n[3/7] Running Agent unit tests..." -ForegroundColor Yellow
|
||||
$testProjectPath = "C:\Code\GitHubRepos\Autopilot-Monitor\src\Agent\AutopilotMonitor.Agent.Core.Tests\AutopilotMonitor.Agent.Core.Tests.csproj"
|
||||
dotnet test $testProjectPath -c $buildConfiguration --nologo -v quiet
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Agent unit tests failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
Write-Host " All agent tests passed" -ForegroundColor Green
|
||||
|
||||
# Copy SummaryDialog EXE + config into Agent output folder
|
||||
$summaryDialogExe = Join-Path $summaryDialogOutputPath "AutopilotMonitor.SummaryDialog.exe"
|
||||
$summaryDialogConfig = Join-Path $summaryDialogOutputPath "AutopilotMonitor.SummaryDialog.exe.config"
|
||||
if (Test-Path $summaryDialogExe) {
|
||||
Copy-Item $summaryDialogExe -Destination $sourcePath -Force
|
||||
if (Test-Path $summaryDialogConfig) {
|
||||
Copy-Item $summaryDialogConfig -Destination $sourcePath -Force
|
||||
}
|
||||
Write-Host " Copied SummaryDialog.exe + .config into Agent output" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " WARNING: SummaryDialog.exe not found at $summaryDialogExe" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
if (-not (Test-Path $sourcePath)) {
|
||||
throw "Build output folder not found: $sourcePath"
|
||||
}
|
||||
if (-not (Test-Path $bootstrapScriptPath)) {
|
||||
throw "Dev bootstrap script not found: $bootstrapScriptPath"
|
||||
}
|
||||
|
||||
# [4] Create ZIP archive (dev name)
|
||||
Write-Host "`n[4/7] Creating DEV ZIP archive..." -ForegroundColor Yellow
|
||||
if (Test-Path $tempZipPath) {
|
||||
Remove-Item $tempZipPath -Force
|
||||
Write-Host " Existing temporary ZIP removed" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
Compress-Archive -Path "$sourcePath\*" -DestinationPath $tempZipPath -CompressionLevel Optimal
|
||||
$zipSize = (Get-Item $tempZipPath).Length / 1MB
|
||||
Write-Host " ZIP created: $([math]::Round($zipSize, 2)) MB" -ForegroundColor Green
|
||||
|
||||
$sha256Hash = (Get-FileHash $tempZipPath -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
Write-Host " ZIP SHA-256: $sha256Hash" -ForegroundColor Gray
|
||||
|
||||
$exeSha256Hash = (Get-FileHash (Join-Path $sourcePath "AutopilotMonitor.Agent.exe") -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
Write-Host " EXE SHA-256: $exeSha256Hash" -ForegroundColor Gray
|
||||
|
||||
# Build version-dev.json IN TEMP. Prod version.json im bin-Ordner bleibt unberuehrt,
|
||||
# damit ein versehentlicher Prod-Script-Lauf spaeter nicht auf einem verseuchten
|
||||
# Zustand aufsetzt.
|
||||
$versionDevObj = [PSCustomObject]@{
|
||||
version = $versionJsonCheck.version
|
||||
sha256 = $sha256Hash
|
||||
}
|
||||
|
||||
# Parse bootstrap script version from DEV bootstrapper
|
||||
$bootstrapVersion = $null
|
||||
$bootstrapContent = Get-Content $bootstrapScriptPath -Raw
|
||||
if ($bootstrapContent -match '\$ScriptVersion\s*=\s*"([\d\.\-a-zA-Z]+)"') {
|
||||
$bootstrapVersion = $Matches[1]
|
||||
$versionDevObj | Add-Member -NotePropertyName "bootstrapVersion" -NotePropertyValue $bootstrapVersion -Force
|
||||
Write-Host " Dev bootstrap script version: $bootstrapVersion" -ForegroundColor Gray
|
||||
} else {
|
||||
Write-Host " WARNING: Could not parse bootstrap `$ScriptVersion from $bootstrapScriptPath" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
$versionDevObj | ConvertTo-Json -Compress | Set-Content $tempVersionDevPath -Encoding UTF8
|
||||
Write-Host " version-dev.json created: $(Get-Content $tempVersionDevPath -Raw)" -ForegroundColor Gray
|
||||
|
||||
$headers = @{ "x-ms-blob-type" = "BlockBlob" }
|
||||
|
||||
# [5] Upload DEV ZIP
|
||||
Write-Host "`n[5/7] Uploading DEV agent ZIP to Azure Blob Storage..." -ForegroundColor Yellow
|
||||
$fileBytes = [System.IO.File]::ReadAllBytes($tempZipPath)
|
||||
Invoke-RestMethod -Uri $blobUrl `
|
||||
-Method Put `
|
||||
-Headers $headers `
|
||||
-Body $fileBytes `
|
||||
-ContentType "application/zip"
|
||||
Write-Host " DEV agent ZIP upload completed successfully" -ForegroundColor Green
|
||||
|
||||
# [6] Upload DEV bootstrap script
|
||||
Write-Host "`n[6/7] Uploading DEV bootstrap script to Azure Blob Storage..." -ForegroundColor Yellow
|
||||
$scriptBytes = [System.IO.File]::ReadAllBytes($bootstrapScriptPath)
|
||||
Invoke-RestMethod -Uri $bootstrapBlobUrl `
|
||||
-Method Put `
|
||||
-Headers $headers `
|
||||
-Body $scriptBytes `
|
||||
-ContentType "text/plain; charset=utf-8"
|
||||
Write-Host " DEV bootstrap script upload completed successfully" -ForegroundColor Green
|
||||
|
||||
# [7] Upload version-dev.json
|
||||
Write-Host "`n[7/7] Uploading version-dev.json to Azure Blob Storage..." -ForegroundColor Yellow
|
||||
$versionDevBytes = [System.IO.File]::ReadAllBytes($tempVersionDevPath)
|
||||
Invoke-RestMethod -Uri $versionDevBlobUrl `
|
||||
-Method Put `
|
||||
-Headers $headers `
|
||||
-Body $versionDevBytes `
|
||||
-ContentType "application/json"
|
||||
Write-Host " version-dev.json upload completed successfully" -ForegroundColor Green
|
||||
|
||||
# NOTE: Kein Upload von version.json / Install-AutopilotMonitor.ps1 / Test-ShouldBootstrapAgent.ps1
|
||||
# NOTE: Kein AdminConfiguration Table-Update (Prod-Hash-Oracle bleibt unangetastet)
|
||||
|
||||
# Cleanup
|
||||
Remove-Item $tempZipPath -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item $tempVersionDevPath -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "`n=== DEV build and upload completed successfully ===" -ForegroundColor Green
|
||||
Write-Host "Files uploaded: $zipFileName, $bootstrapScriptName, $versionJsonDevName" -ForegroundColor Gray
|
||||
Write-Host "Container: autopilotmonitor/agent" -ForegroundColor Gray
|
||||
Write-Host "Agent version: $($versionJsonCheck.version) | Bootstrap version: $bootstrapVersion" -ForegroundColor Gray
|
||||
Write-Host "Production artifacts (AutopilotMonitor-Agent.zip / version.json / AdminConfiguration) were NOT touched." -ForegroundColor Gray
|
||||
|
||||
} catch {
|
||||
Write-Host "`nERROR: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host "Details: $($_.Exception.ToString())" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
Reference in New Issue
Block a user