Private/New-CountdownScript.ps1

function New-CountdownScript {
    [CmdletBinding()]
    [OutputType([string])]
    param(
        [string]$ProjectPath,

        # Countdown duration. The 120 s default is the WATCHED-mode human verification window and is
        # deliberately unchanged; unattended runs simply omit Countdown.ps1 from the chain entirely.
        [ValidateRange(5, 3600)]
        [int]$Seconds = 120
    )

    $sandboxPath = Join-Path $ProjectPath 'Sandbox'
    if (-not (Test-Path $sandboxPath)) {
        New-Item -ItemType Directory -Path $sandboxPath -Force | Out-Null
    }

    # Human-readable duration + initial mm:ss for the generated WinForms labels.
    $durationText = if ($Seconds % 60 -eq 0) { "$([int]($Seconds / 60)) minute$(if ($Seconds -ne 60) { 's' })" } else { "$Seconds seconds" }
    $initialLabel = '{0:00}:{1:00}' -f [math]::Floor($Seconds / 60), ($Seconds % 60)

    $countdownScript = @'
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
 
Write-Host "`n========================================" -ForegroundColor Green
Write-Host "INSTALLATION COMPLETED SUCCESSFULLY!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host "The application has been installed." -ForegroundColor White
Write-Host "You can now test the application functionality." -ForegroundColor Cyan
 
# Create a countdown form
$form = New-Object System.Windows.Forms.Form
$form.Text = "Uninstallation Countdown"
$form.Size = New-Object System.Drawing.Size(500,250)
$form.StartPosition = "CenterScreen"
$form.Topmost = $true
$form.FormBorderStyle = "FixedDialog"
$form.MaximizeBox = $false
 
# Title label
$titleLabel = New-Object System.Windows.Forms.Label
$titleLabel.Location = New-Object System.Drawing.Point(30,20)
$titleLabel.Size = New-Object System.Drawing.Size(440,30)
$titleLabel.Font = New-Object System.Drawing.Font("Arial",14,[System.Drawing.FontStyle]::Bold)
$titleLabel.Text = "Installation Completed Successfully!"
$titleLabel.ForeColor = [System.Drawing.Color]::Green
$titleLabel.TextAlign = "MiddleCenter"
$form.Controls.Add($titleLabel)
 
# Instructions label
$instructionLabel = New-Object System.Windows.Forms.Label
$instructionLabel.Location = New-Object System.Drawing.Point(30,60)
$instructionLabel.Size = New-Object System.Drawing.Size(440,40)
$instructionLabel.Font = New-Object System.Drawing.Font("Arial",10)
$instructionLabel.Text = "Please test the application now.`nUninstallation will begin automatically in __DURATION__."
$instructionLabel.TextAlign = "MiddleCenter"
$form.Controls.Add($instructionLabel)
 
# Countdown label
$countdownLabel = New-Object System.Windows.Forms.Label
$countdownLabel.Location = New-Object System.Drawing.Point(30,120)
$countdownLabel.Size = New-Object System.Drawing.Size(440,40)
$countdownLabel.Font = New-Object System.Drawing.Font("Arial",16,[System.Drawing.FontStyle]::Bold)
$countdownLabel.Text = "Time remaining: __INITIAL__"
$countdownLabel.ForeColor = [System.Drawing.Color]::Blue
$countdownLabel.TextAlign = "MiddleCenter"
$form.Controls.Add($countdownLabel)
 
# Skip button
$skipButton = New-Object System.Windows.Forms.Button
$skipButton.Location = New-Object System.Drawing.Point(200,170)
$skipButton.Size = New-Object System.Drawing.Size(100,30)
$skipButton.Text = "Skip Wait"
$skipButton.Font = New-Object System.Drawing.Font("Arial",10)
$form.Controls.Add($skipButton)
 
# Timer for countdown
$timer = New-Object System.Windows.Forms.Timer
$secondsRemaining = __SECONDS__
$timer.Interval = 1000 # 1 second
 
$timer.Add_Tick({
    $script:secondsRemaining--
 
    $minutes = [Math]::Floor($script:secondsRemaining / 60)
    $seconds = $script:secondsRemaining % 60
 
    $countdownLabel.Text = "Time remaining: $($minutes.ToString("00")):$($seconds.ToString("00"))"
 
    if ($script:secondsRemaining -le 0) {
        $timer.Stop()
        $form.Close()
    }
 
    # Change color as time runs out
    if ($script:secondsRemaining -le 30) {
        $countdownLabel.ForeColor = [System.Drawing.Color]::Red
    } elseif ($script:secondsRemaining -le 60) {
        $countdownLabel.ForeColor = [System.Drawing.Color]::Orange
    }
})
 
# Skip button click event
$skipButton.Add_Click({
    $timer.Stop()
    $form.Close()
})
 
# Start the timer and show the form
$timer.Start()
$form.ShowDialog()
 
Write-Host "`n========================================" -ForegroundColor Yellow
Write-Host "STARTING UNINSTALLATION PROCESS" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Yellow
'@


    # Fill the duration placeholders (numeric literal + label texts — nothing untrusted).
    $countdownScript = $countdownScript -replace '__SECONDS__', $Seconds
    $countdownScript = $countdownScript -replace '__DURATION__', $durationText
    $countdownScript = $countdownScript -replace '__INITIAL__', $initialLabel

    $countdownPath = Join-Path $sandboxPath 'Countdown.ps1'
    # UTF-8 WITH BOM: this runs under Windows PowerShell 5.1 inside the sandbox, which decodes a BOM-less
    # file as ANSI (PS7's Set-Content -Encoding UTF8 writes no BOM) — non-ASCII text would mojibake.
    [System.IO.File]::WriteAllText($countdownPath, $countdownScript, (New-Object System.Text.UTF8Encoding($true)))

    return $countdownPath
}