working install and uninstall flow in Vagrant
This commit is contained in:
@@ -2,16 +2,120 @@
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$InstallerPath,
|
||||
[Parameter(Mandatory)][string]$ResultPath,
|
||||
[int]$TimeoutSeconds = 600
|
||||
[int]$TimeoutSeconds = 600,
|
||||
[string]$TracePath = $(Join-Path (Split-Path -Parent $ResultPath) "trace"),
|
||||
[string]$OperationName = "installer",
|
||||
[string]$InstallerArgumentsBase64 = "",
|
||||
[string[]]$InstallerArguments = @("--headed", "--automation")
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Write-TraceEvent {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$Phase,
|
||||
[object]$Detail = $null
|
||||
)
|
||||
|
||||
try {
|
||||
New-Item -ItemType Directory -Force -Path $TracePath | Out-Null
|
||||
$event = [ordered]@{
|
||||
time = (Get-Date).ToUniversalTime().ToString("o")
|
||||
pid = $PID
|
||||
script = Split-Path -Leaf $PSCommandPath
|
||||
phase = $Phase
|
||||
detail = $Detail
|
||||
}
|
||||
$event | ConvertTo-Json -Depth 12 -Compress | Add-Content -LiteralPath (Join-Path $TracePath "guest-events.jsonl") -Encoding UTF8
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to write trace event '$Phase': $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function Write-DiagnosticFile {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$Name,
|
||||
[Parameter(Mandatory)][scriptblock]$Capture
|
||||
)
|
||||
|
||||
$path = Join-Path $TracePath $Name
|
||||
try {
|
||||
$value = & $Capture
|
||||
$value | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $path -Encoding UTF8
|
||||
}
|
||||
catch {
|
||||
[ordered]@{
|
||||
error = $_.Exception.Message
|
||||
type = $_.Exception.GetType().FullName
|
||||
} | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $path -Encoding UTF8
|
||||
}
|
||||
}
|
||||
|
||||
function Export-InstallerDiagnostics {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$Reason,
|
||||
[System.Diagnostics.Process]$InstallerProcess = $null
|
||||
)
|
||||
|
||||
Write-TraceEvent -Phase "installer_diagnostics_start" -Detail @{ reason = $Reason; installerPid = $(if ($InstallerProcess) { $InstallerProcess.Id } else { $null }) }
|
||||
Write-DiagnosticFile -Name "interactive-context.json" -Capture {
|
||||
[ordered]@{
|
||||
reason = $Reason
|
||||
computerName = $env:COMPUTERNAME
|
||||
userName = $env:USERNAME
|
||||
sessionName = $env:SESSIONNAME
|
||||
installerPath = $InstallerPath
|
||||
installerArgs = $InstallerArguments
|
||||
operationName = $OperationName
|
||||
resultPath = $ResultPath
|
||||
tracePath = $TracePath
|
||||
timeoutSeconds = $TimeoutSeconds
|
||||
installerPid = $(if ($InstallerProcess) { $InstallerProcess.Id } else { $null })
|
||||
installerExited = $(if ($InstallerProcess) { $InstallerProcess.HasExited } else { $null })
|
||||
}
|
||||
}
|
||||
Write-DiagnosticFile -Name "interactive-processes.json" -Capture {
|
||||
Get-CimInstance Win32_Process |
|
||||
Where-Object { $_.Name -match 'covenant|Covenant|powershell|pwsh|dotnet' } |
|
||||
Select-Object ProcessId, ParentProcessId, Name, CommandLine, CreationDate
|
||||
}
|
||||
Write-DiagnosticFile -Name "interactive-windows.json" -Capture {
|
||||
Get-Process |
|
||||
Where-Object { $_.MainWindowHandle -ne 0 -or $_.ProcessName -match 'covenant|Covenant|powershell|pwsh' } |
|
||||
Select-Object Id, ProcessName, MainWindowTitle, MainWindowHandle, StartTime
|
||||
}
|
||||
Write-DiagnosticFile -Name "interactive-application-events.json" -Capture {
|
||||
Get-WinEvent -FilterHashtable @{ LogName = "Application"; StartTime = (Get-Date).AddHours(-2) } -MaxEvents 200 -ErrorAction SilentlyContinue |
|
||||
Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message
|
||||
}
|
||||
Write-TraceEvent -Phase "installer_diagnostics_finish" -Detail @{ reason = $Reason }
|
||||
}
|
||||
|
||||
$installer = $null
|
||||
$startedAt = Get-Date
|
||||
|
||||
try {
|
||||
if (-not [string]::IsNullOrWhiteSpace($InstallerArgumentsBase64)) {
|
||||
$argumentsJson = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($InstallerArgumentsBase64))
|
||||
$decodedArguments = ConvertFrom-Json -InputObject $argumentsJson
|
||||
$InstallerArguments = @()
|
||||
foreach ($argument in $decodedArguments) {
|
||||
$InstallerArguments += [string]$argument
|
||||
}
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $TracePath | Out-Null
|
||||
Write-TraceEvent -Phase "interactive_installer_start" -Detail @{
|
||||
installerPath = $InstallerPath
|
||||
installerArgs = $InstallerArguments
|
||||
operationName = $OperationName
|
||||
resultPath = $ResultPath
|
||||
tracePath = $TracePath
|
||||
timeoutSeconds = $TimeoutSeconds
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $InstallerPath)) {
|
||||
throw "Installer not found: $InstallerPath"
|
||||
}
|
||||
@@ -22,17 +126,47 @@ try {
|
||||
}
|
||||
Remove-Item -LiteralPath $ResultPath -Force -ErrorAction SilentlyContinue
|
||||
|
||||
$installer = Start-Process -FilePath $InstallerPath -ArgumentList @("--headed", "--automation") -PassThru
|
||||
$env:COVENANT_SETUP_TRACE_DIR = $TracePath
|
||||
Write-TraceEvent -Phase "trace_environment_set" -Detail @{ name = "COVENANT_SETUP_TRACE_DIR"; value = $TracePath }
|
||||
|
||||
if (-not $installer.WaitForExit($TimeoutSeconds * 1000)) {
|
||||
Stop-Process -Id $installer.Id -Force -ErrorAction SilentlyContinue
|
||||
throw "Installer timed out after $TimeoutSeconds seconds."
|
||||
$installer = Start-Process -FilePath $InstallerPath -ArgumentList $InstallerArguments -PassThru
|
||||
Write-TraceEvent -Phase "installer_process_started" -Detail @{ pid = $installer.Id; operationName = $OperationName }
|
||||
|
||||
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
|
||||
$lastPoll = Get-Date "2000-01-01"
|
||||
while (-not $installer.HasExited) {
|
||||
if ((Get-Date) -ge $deadline) {
|
||||
Export-InstallerDiagnostics -Reason "installer_timeout" -InstallerProcess $installer
|
||||
Stop-Process -Id $installer.Id -Force -ErrorAction SilentlyContinue
|
||||
throw "Installer timed out after $TimeoutSeconds seconds."
|
||||
}
|
||||
|
||||
if (((Get-Date) - $lastPoll).TotalSeconds -ge 10) {
|
||||
$lastPoll = Get-Date
|
||||
$installer.Refresh()
|
||||
Write-TraceEvent -Phase "installer_still_running" -Detail @{
|
||||
pid = $installer.Id
|
||||
operationName = $OperationName
|
||||
elapsedSeconds = [int]((Get-Date) - $startedAt).TotalSeconds
|
||||
responding = $installer.Responding
|
||||
mainWindow = $installer.MainWindowTitle
|
||||
}
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds 2
|
||||
$installer.Refresh()
|
||||
}
|
||||
|
||||
Write-TraceEvent -Phase "installer_process_exited" -Detail @{ pid = $installer.Id; exitCode = $installer.ExitCode; operationName = $OperationName }
|
||||
Export-InstallerDiagnostics -Reason "installer_exit" -InstallerProcess $installer
|
||||
|
||||
$result = [ordered]@{
|
||||
success = ($installer.ExitCode -eq 0)
|
||||
exitCode = [int]$installer.ExitCode
|
||||
installerPath = $InstallerPath
|
||||
installerArgs = $InstallerArguments
|
||||
operationName = $OperationName
|
||||
tracePath = $TracePath
|
||||
startedAt = $startedAt.ToString("o")
|
||||
finishedAt = (Get-Date).ToString("o")
|
||||
}
|
||||
@@ -43,9 +177,15 @@ try {
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-TraceEvent -Phase "interactive_installer_error" -Detail @{
|
||||
error = $_.Exception.Message
|
||||
type = $_.Exception.GetType().FullName
|
||||
}
|
||||
Export-InstallerDiagnostics -Reason "interactive_installer_error" -InstallerProcess $installer
|
||||
$failure = [ordered]@{
|
||||
success = $false
|
||||
error = $_.Exception.Message
|
||||
tracePath = $TracePath
|
||||
startedAt = $startedAt.ToString("o")
|
||||
finishedAt = (Get-Date).ToString("o")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user