diff --git a/libs/qemu-docker/README.md b/libs/qemu-docker/README.md new file mode 100644 index 00000000..9ec2b5af --- /dev/null +++ b/libs/qemu-docker/README.md @@ -0,0 +1,14 @@ +# QEMU Docker Containers + +Docker containers running desktop operating systems via QEMU/KVM for Computer-Using Agents (CUA). + +## Structure + +``` +qemu-docker/ +└── windows/ # Windows 11 container with CUA computer-server +``` + +## Windows Container + +See [windows/README.md](windows/README.md) for complete documentation on the Windows 11 QEMU container. diff --git a/libs/qemu-docker/windows/Dockerfile b/libs/qemu-docker/windows/Dockerfile new file mode 100644 index 00000000..da5a15ce --- /dev/null +++ b/libs/qemu-docker/windows/Dockerfile @@ -0,0 +1,17 @@ +FROM trycua/windows-local:latest + +COPY src/vm/setup/. /oem/ + +COPY --chmod=755 src/entry.sh /entry.sh + +ENV YRES="900" +ENV XRES="1440" +ENV RAM_SIZE="8G" +ENV CPU_CORES="8" +ENV VERSION="win11x64-enterprise-eval" +ENV DISK_SIZE="30G" +ENV ARGUMENTS="-qmp tcp:0.0.0.0:7200,server,nowait" + +EXPOSE 5000 8006 + +ENTRYPOINT ["/entry.sh"] \ No newline at end of file diff --git a/libs/qemu-docker/windows/README.md b/libs/qemu-docker/windows/README.md new file mode 100644 index 00000000..b7309c54 --- /dev/null +++ b/libs/qemu-docker/windows/README.md @@ -0,0 +1,161 @@ +# CUA Windows Container + +Containerized Windows 11 virtual desktop for Computer-Using Agents (CUA). Utilizes QEMU/KVM with Windows 11 and computer-server pre-installed for remote computer control. + +## Features + +- Windows 11 Enterprise running in QEMU/KVM +- Pre-installed CUA computer-server for remote computer control +- Caddy reverse proxy (port 9222 → 1337) for browser automation +- noVNC access for visual desktop interaction +- Automated setup via unattended installation +- Support for both dev (shared folder) and azure (OEM folder) deployment modes +- Python 3.12 with isolated virtual environment for CUA computer-server +- Services run hidden in background via Windows scheduled tasks +- Essential tools pre-installed (Chrome, LibreOffice, VLC, GIMP, VSCode, Thunderbird) + +## Quick Start + +### 1. Download and Prepare setup.iso + +**Download Windows 11 Evaluation ISO:** + +1. Visit [Microsoft Evaluation Center](https://info.microsoft.com/ww-landing-windows-11-enterprise.html) +2. Accept the Terms of Service +3. Download **Windows 11 Enterprise Evaluation (90-day trial, English, United States)** ISO file [~6GB] +4. After downloading, rename the file to `setup.iso` +5. Copy it to the directory `src/vm/image/` + +This ISO is used for automated Windows installation on first run. + +### 2. Build the Image + +```bash +docker build -t cua-windows:dev . +``` + +### 3. First Run - Create Golden Image + +On first run, the container will install Windows from scratch and create a golden image. This takes 15-30 minutes. + +```bash +# Create storage directory +mkdir -p ./storage + +# Run with setup.iso to create golden image +docker run -it --rm \ + --device=/dev/kvm \ + --platform linux/amd64 \ + --name cua-windows \ + --mount type=bind,source=$(pwd)/src/vm/image/setup.iso,target=/custom.iso \ + --cap-add NET_ADMIN \ + -v $(pwd)/storage:/storage \ + -p 8006:8006 \ + -p 5000:5000 \ + -e RAM_SIZE=8G \ + -e CPU_CORES=4 \ + -e DISK_SIZE=20G \ + cua-windows:dev +``` + +**What happens during first run:** + +1. Windows 11 installs automatically using unattended configuration +2. Setup scripts install Python 3.12, Git, and CUA computer-server in isolated venv +3. Windows scheduled tasks created for CUA server and Caddy proxy (run hidden in background) +4. Golden image is saved to `/storage` directory +5. Container exits after setup completes + +### 4. Subsequent Runs - Use Golden Image + +After the golden image is created, subsequent runs boot much faster (30 sec - 2 min): + +```bash +# Run without setup.iso - uses existing golden image +docker run -it --rm \ + --device=/dev/kvm \ + --platform linux/amd64 \ + --name cua-windows \ + --cap-add NET_ADMIN \ + -v $(pwd)/storage:/storage \ + -p 8006:8006 \ + -p 5000:5000 \ + -e RAM_SIZE=8G \ + -e CPU_CORES=4 \ + cua-windows:dev +``` + +**Access points:** + +- **Computer Server API**: `http://localhost:5000` +- **noVNC Browser**: `http://localhost:8006` + +## Container Configuration + +### Ports + +- **5000**: CUA computer-server API endpoint +- **8006**: noVNC web interface for visual desktop access + +### Environment Variables + +- `RAM_SIZE`: RAM allocated to Windows VM (default: "8G", recommended: "8G" for WSL2) +- `CPU_CORES`: CPU cores allocated to VM (default: "8") +- `DISK_SIZE`: VM disk size (default: "30G", minimum: "20G") +- `YRES`: Screen height (default: "900") +- `XRES`: Screen width (default: "1440") +- `VERSION`: Windows version (default: "win11x64-enterprise-eval") + +### Volumes + +- `/storage`: Persistent VM storage (golden image, disk, firmware) +- `/custom.iso`: Mount point for setup.iso (only needed for first run) + +## Architecture + +``` +┌─────────────────────────────────────────────────────────┐ +│ Docker Container (Linux host) │ +│ │ +│ • Port forwarding: localhost:5000 → EMULATOR_IP:5000 │ +│ • Exposes: 5000 (API), 8006 (noVNC) │ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ QEMU VM (Windows 11) │ │ +│ │ │ │ +│ │ • CUA computer-server listens on 5000 │ │ +│ │ │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────┘ +``` + +**Communication Flow:** + +1. External client → `localhost:5000` (host) +2. Docker port mapping → Container's `localhost:5000` +3. socat port forwarding → `20.20.20.21:5000` (VM) +4. CUA computer-server in Windows VM processes request + +## Development + +### Modifying Setup Scripts + +Setup scripts are in `src/vm/setup/`: + +- `install.bat`: Entry point called by Windows setup +- `setup.ps1`: Main setup orchestration (installs software, configures Windows) +- `setup-cua-server.ps1`: CUA server installation with isolated venv +- `on-logon.ps1`: Runs on user logon (starts scheduled tasks) +- `setup-utils.psm1`: Helpers functions for setup + +After modifying, rebuild the image: + +```bash +docker build -t cua-windows:dev . +``` + +## Credits + +- Built on [Dockur Windows](https://github.com/dockur/windows) base image +- Inspired by [Windows Agent Arena](https://github.com/microsoft/WindowsAgentArena) diff --git a/libs/qemu-docker/windows/src/entry.sh b/libs/qemu-docker/windows/src/entry.sh new file mode 100644 index 00000000..96911911 --- /dev/null +++ b/libs/qemu-docker/windows/src/entry.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Create windows.boot file if it doesn't exist (required for proper boot) +if [ -d "/storage" -a ! -f "/storage/windows.boot" ]; then + echo "Creating windows.boot file in /storage..." + touch /storage/windows.boot +fi + +# Start the VM in the background +echo "Starting Windows VM..." +/usr/bin/tini -s /run/entry.sh & +echo "Live stream accessible at localhost:8006" + +echo "Waiting for Windows to boot and CUA computer-server to start..." + +VM_IP="" +while true; do + # Wait from VM and get the IP + if [ -z "$VM_IP" ]; then + VM_IP=$(ps aux | grep dnsmasq | grep -oP '(?<=--dhcp-range=)[0-9.]+' | head -1) + if [ -n "$VM_IP" ]; then + echo "Detected VM IP: $VM_IP" + else + echo "Waiting for VM to start..." + sleep 5 + continue + fi + fi + + # Check if server is ready + response=$(curl --write-out '%{http_code}' --silent --output /dev/null $VM_IP:5000/status) + + if [ "${response:-0}" -eq 200 ]; then + break + fi + + echo "Waiting for CUA computer-server to be ready. This might take a while..." + sleep 5 +done + +echo "VM is up and running, and the CUA Computer Server is ready!" + +echo "Computer server accessible at localhost:5000" + +# Detect initial setup by presence of /custom.iso (setup ISO mount) +if [ ! -f "/custom.iso" ]; then # Keep container alive + echo "Container running. Press Ctrl+C to stop." + tail -f /dev/null +fi diff --git a/libs/qemu-docker/windows/src/vm/image/README.md b/libs/qemu-docker/windows/src/vm/image/README.md new file mode 100644 index 00000000..916aab86 --- /dev/null +++ b/libs/qemu-docker/windows/src/vm/image/README.md @@ -0,0 +1,9 @@ +> Add your Win11E setup.iso to this folder + +**Download Windows 11 Evaluation ISO:** + +1. Visit [Microsoft Evaluation Center](https://info.microsoft.com/ww-landing-windows-11-enterprise.html) +2. Accept the Terms of Service +3. Download **Windows 11 Enterprise Evaluation (90-day trial, English, United States)** ISO file [~6GB] +4. After downloading, rename the file to `setup.iso` +5. Copy it to the current directory. diff --git a/libs/qemu-docker/windows/src/vm/setup/install.bat b/libs/qemu-docker/windows/src/vm/setup/install.bat new file mode 100644 index 00000000..bfda4ea2 --- /dev/null +++ b/libs/qemu-docker/windows/src/vm/setup/install.bat @@ -0,0 +1,31 @@ +@echo off + +SET ScriptFolder=C:\OEM +SET LogFile=%ScriptFolder%\ps_script_log.txt + +echo Running PowerShell script... > %LogFile% + +:: Check for PowerShell availability +where powershell >> %LogFile% 2>&1 +if %ERRORLEVEL% neq 0 ( + echo PowerShell is not available! >> %LogFile% + echo PowerShell is not available! + exit /b 1 +) + +:: Add a 30-second delay +echo Waiting for 30 seconds before continuing... >> %LogFile% +timeout /t 30 /nobreak >> %LogFile% 2>&1 + +:: Run PowerShell script with ExecutionPolicy Bypass and log errors +echo Running setup.ps1... >> %LogFile% + +powershell -ExecutionPolicy Bypass -File "%ScriptFolder%\setup.ps1" >> %LogFile% 2>&1 + +if %ERRORLEVEL% neq 0 ( + echo An error occurred. See %LogFile% for details. +) else ( + echo PowerShell script has completed successfully. +) + +echo PowerShell script has completed. \ No newline at end of file diff --git a/libs/qemu-docker/windows/src/vm/setup/on-logon.ps1 b/libs/qemu-docker/windows/src/vm/setup/on-logon.ps1 new file mode 100644 index 00000000..f9aad48c --- /dev/null +++ b/libs/qemu-docker/windows/src/vm/setup/on-logon.ps1 @@ -0,0 +1,2 @@ +Write-Host "Starting CUA Computer Server task..." +Start-ScheduledTask -TaskName "CUA-Computer-Server" diff --git a/libs/qemu-docker/windows/src/vm/setup/setup-cua-server.ps1 b/libs/qemu-docker/windows/src/vm/setup/setup-cua-server.ps1 new file mode 100644 index 00000000..40956b67 --- /dev/null +++ b/libs/qemu-docker/windows/src/vm/setup/setup-cua-server.ps1 @@ -0,0 +1,180 @@ +# Setup CUA Computer Server on Windows 11 +# Creates a scheduled task to run computer server in background + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Continue' + +# Import shared utilities +$scriptFolder = "C:\OEM" +Import-Module (Join-Path $scriptFolder -ChildPath "setup-utils.psm1") + +# --- Logging --- +$LogDir = "C:\Windows\Temp" +if (!(Test-Path $LogDir)) { New-Item -ItemType Directory -Force -Path $LogDir | Out-Null } +$RunId = (Get-Date -Format 'yyyyMMdd_HHmmss') + "_" + $PID +$script:LogFile = Join-Path $LogDir ("setup_cua_server_" + $RunId + ".log") + +Write-Log -LogFile $script:LogFile -Message "=== Installing CUA Computer Server ===" + +# Ensure Chocolatey and Python 3.12 are present +try { + $ChocoExe = Resolve-ChocoPath + if ($ChocoExe) { + Write-Log -LogFile $script:LogFile -Message "Installing Python 3.12 via Chocolatey" + try { + & $ChocoExe install -y python312 | Out-Null + } catch { + Write-Log -LogFile $script:LogFile -Message "Python 3.12 install warning: $($_.Exception.Message)" + } + } else { + Write-Log -LogFile $script:LogFile -Message "Chocolatey not available; skipping python312 install" + } +} catch { + Write-Log -LogFile $script:LogFile -Message "Chocolatey bootstrap warning: $($_.Exception.Message)" +} + +# Create venv +$HomeDir = $env:USERPROFILE +$CuaDir = Join-Path $HomeDir '.cua-server' +$VenvDir = Join-Path $CuaDir 'venv' +New-Item -ItemType Directory -Force -Path $CuaDir | Out-Null + +Write-Log -LogFile $script:LogFile -Message "Creating Python virtual environment at $VenvDir" +$ExistingVenvPython = Join-Path $VenvDir 'Scripts\python.exe' +if (Test-Path -LiteralPath $ExistingVenvPython) { + Write-Log -LogFile $script:LogFile -Message "Existing venv detected; skipping creation" +} else { + try { + & py -m venv $VenvDir + Write-Log -LogFile $script:LogFile -Message "Virtual environment created successfully" + } catch { + Write-Log -LogFile $script:LogFile -Message "venv creation error: $($_.Exception.Message)" + throw + } +} + +$PyExe = Join-Path $VenvDir 'Scripts\python.exe' +$PipExe = Join-Path $VenvDir 'Scripts\pip.exe' +$ActivateScript = Join-Path $VenvDir 'Scripts\Activate.ps1' + +Write-Log -LogFile $script:LogFile -Message "Activating virtual environment" +& $ActivateScript + +Write-Log -LogFile $script:LogFile -Message "Upgrading pip, setuptools, and wheel" +try { + & $PipExe install --upgrade pip setuptools wheel 2>&1 | Tee-Object -FilePath $script:LogFile -Append | Out-Null +} catch { + Write-Log -LogFile $script:LogFile -Message "pip bootstrap warning: $($_.Exception.Message)" +} + +Write-Log -LogFile $script:LogFile -Message "Installing cua-computer-server" +try { + & $PipExe install --upgrade cua-computer-server 2>&1 | Tee-Object -FilePath $script:LogFile -Append | Out-Null + Write-Log -LogFile $script:LogFile -Message "cua-computer-server installed successfully" +} catch { + Write-Log -LogFile $script:LogFile -Message "Server install error: $($_.Exception.Message)" + throw +} + +# Open firewall for port 5000 +Write-Log -LogFile $script:LogFile -Message "Opening firewall for port 5000" +try { + netsh advfirewall firewall add rule name="CUA Computer Server 5000" dir=in action=allow protocol=TCP localport=5000 | Out-Null + Write-Log -LogFile $script:LogFile -Message "Firewall rule added successfully" +} catch { + Write-Log -LogFile $script:LogFile -Message "Firewall rule warning: $($_.Exception.Message)" +} + +# Create start script with auto-restart +$StartScript = Join-Path $CuaDir 'start-server.ps1' +$StartScriptContent = @" +param() + +`$env:PYTHONUNBUFFERED = '1' + +`$LogFile = Join-Path '$CuaDir' 'server.log' +`$ActivateScript = '$ActivateScript' +`$PipExe = '$PipExe' +`$Python = '$PyExe' + +function Start-Server { + Write-Output "Activating virtual environment and updating cua-computer-server..." | Out-File -FilePath `$LogFile -Append + & `$ActivateScript + & `$PipExe install --upgrade cua-computer-server 2>&1 | Out-File -FilePath `$LogFile -Append + + Write-Output "Starting CUA Computer Server on port 5000..." | Out-File -FilePath `$LogFile -Append + & `$Python -m computer_server --port 5000 2>&1 | Out-File -FilePath `$LogFile -Append + return `$LASTEXITCODE +} + +while (`$true) { + Start-Server + `$code = `$LASTEXITCODE + Write-Output "Server exited with code: `$code. Restarting in 5s..." | Out-File -FilePath `$LogFile -Append + Start-Sleep -Seconds 5 +} +"@ + +Set-Content -Path $StartScript -Value $StartScriptContent -Encoding UTF8 +Write-Log -LogFile $script:LogFile -Message "Start script created at $StartScript" + +# Create VBScript wrapper to launch PowerShell hidden +$VbsWrapper = Join-Path $CuaDir 'start-server-hidden.vbs' +$VbsContent = @" +Set objShell = CreateObject("WScript.Shell") +objShell.Run "powershell.exe -NoProfile -ExecutionPolicy Bypass -File ""$StartScript""", 0, False +"@ +Set-Content -Path $VbsWrapper -Value $VbsContent -Encoding ASCII +Write-Log -LogFile $script:LogFile -Message "VBScript wrapper created at $VbsWrapper" + +# Create scheduled task to run at logon +try { + $TaskName = 'CUA-Computer-Server' + $Username = 'Docker' # Default user for Dockur Windows + + # Remove existing task if present + $existingTask = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue + if ($existingTask) { + Write-Log -LogFile $script:LogFile -Message "Removing existing scheduled task: $TaskName" + Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false + } + + # Create action to run VBScript wrapper (hidden) + $Action = New-ScheduledTaskAction -Execute 'wscript.exe' -Argument "`"$VbsWrapper`"" + + # Trigger: At logon of user + $UserId = "$env:COMPUTERNAME\$Username" + $Trigger = New-ScheduledTaskTrigger -AtLogOn -User $UserId + + # Principal: Run in background without window (S4U = Service For User) + $Principal = New-ScheduledTaskPrincipal -UserId $UserId -LogonType S4U -RunLevel Highest + + # Task settings - hide window + $Settings = New-ScheduledTaskSettingsSet ` + -AllowStartIfOnBatteries ` + -DontStopIfGoingOnBatteries ` + -StartWhenAvailable ` + -RestartCount 999 ` + -RestartInterval (New-TimeSpan -Minutes 1) ` + -ExecutionTimeLimit (New-TimeSpan -Days 365) ` + -Hidden + + # Register the task + Write-Log -LogFile $script:LogFile -Message "Registering scheduled task '$TaskName' to run as $Username at logon (hidden)" + Register-ScheduledTask ` + -TaskName $TaskName ` + -Action $Action ` + -Trigger $Trigger ` + -Principal $Principal ` + -Settings $Settings ` + -Force | Out-Null + + Write-Log -LogFile $script:LogFile -Message "Scheduled task '$TaskName' registered successfully (runs hidden in background)" + +} catch { + Write-Log -LogFile $script:LogFile -Message "Scheduled task setup error: $($_.Exception.Message)" + throw +} + +Write-Log -LogFile $script:LogFile -Message "=== CUA Computer Server setup completed ===" +exit 0 diff --git a/libs/qemu-docker/windows/src/vm/setup/setup-utils.psm1 b/libs/qemu-docker/windows/src/vm/setup/setup-utils.psm1 new file mode 100644 index 00000000..0b5578d6 --- /dev/null +++ b/libs/qemu-docker/windows/src/vm/setup/setup-utils.psm1 @@ -0,0 +1,121 @@ +function Write-Log { + param( + [Parameter(Mandatory=$true)] + [string]$LogFile, + + [Parameter(Mandatory=$true)] + [string]$Message + ) + + $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' + "$timestamp`t$Message" | Tee-Object -FilePath $LogFile -Append + Write-Host "$timestamp`t$Message" +} + +function Resolve-ChocoPath { + param( + [switch]$SkipInstall + ) + + $inst = [Environment]::GetEnvironmentVariable('ChocolateyInstall','Machine') + if ($inst) { + $exe = Join-Path $inst 'bin\choco.exe' + if (Test-Path $exe) { return $exe } + } + $fallback = 'C:\ProgramData\chocolatey\bin\choco.exe' + if (Test-Path $fallback) { return $fallback } + try { + $cmd = (Get-Command choco -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source) + if ($cmd) { return $cmd } + } catch {} + + if (-not $SkipInstall) { + Write-Host "Chocolatey not found. Installing..." + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + + return Resolve-ChocoPath -SkipInstall + } + + return $null +} + +function Add-ToEnvPath { + param ( + [string]$NewPath + ) + + # Get the current PATH environment variable + $envPath = [Environment]::GetEnvironmentVariable("PATH", "Machine") + + # Append the new path to the existing PATH + $newPath = "$envPath;$NewPath" + + # Set the updated PATH environment variable + [Environment]::SetEnvironmentVariable("PATH", $newPath, "Machine") + + # Fetch updates from the shell + $env:PATH += ";${newPath}" +} + +function Register-LogonTask { + param( + + [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Name of the scheduled task")] + [string] + $TaskName, + + [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Path to the .py script")] + [string] + $ScriptPath, + + [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Arguments to the .py script")] + [string] + $Arguments = "", + + [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Local Account username")] + [string] + $LocalUser, + + [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Local Account password")] + [string] + $LocalPassword, + + [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Whether to execute the command as SYSTEM")] + [switch] + $AsSystem = $false, + + [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "logging file")] + [string] + $LogFilePath + ) + + $scriptDirectory = Split-Path $ScriptPath + + $taskActionArgument = "-ExecutionPolicy Bypass -windowstyle hidden -Command `"try { . '$ScriptPath' $Arguments } catch { Write `$_.Exception.Message | Out-File $($TaskName)_Log.txt } finally { } `"" + $taskAction = New-ScheduledTaskAction -Execute "$PSHome\powershell.exe" -Argument $taskActionArgument -WorkingDirectory $scriptDirectory + + $params = @{ + Force = $True + Action = $taskAction + RunLevel = "Highest" + TaskName = $TaskName + } + + $taskTrigger = New-ScheduledTaskTrigger -AtLogOn + $params.Add("Trigger", $taskTrigger) + + if ($AsSystem) { + $params.Add("User", "NT AUTHORITY\SYSTEM") + } + else { + $params.Add("User", $LocalUser) + if ($LocalPassword) { + $params.Add("Password", $LocalPassword) + } + } + + Write-Host "Registering scheduled task '$TaskName' to run 'powershell.exe $taskActionArgument'..." + Register-ScheduledTask @params +} diff --git a/libs/qemu-docker/windows/src/vm/setup/setup.ps1 b/libs/qemu-docker/windows/src/vm/setup/setup.ps1 new file mode 100644 index 00000000..85c0aff3 --- /dev/null +++ b/libs/qemu-docker/windows/src/vm/setup/setup.ps1 @@ -0,0 +1,49 @@ +$ErrorActionPreference = "Continue" + +$scriptFolder = "C:\OEM" + +Import-Module (Join-Path $scriptFolder -ChildPath "setup-utils.psm1") + +Set-StrictMode -Version Latest + +# Set TLS version to 1.2 or higher +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13 + +# Install Git via Chocolatey +$ChocoExe = Resolve-ChocoPath +if ($ChocoExe) { + Write-Host "Installing Git via Chocolatey..." + try { + & $ChocoExe install -y git | Out-Null + Add-ToEnvPath -NewPath "C:\Program Files\Git\bin" + Write-Host "Git installed successfully." + } catch { + Write-Host "Git install warning: $($_.Exception.Message)" + } +} else { + Write-Host "Chocolatey not available; skipping Git install" +} + +# CUA Computer Server Setup +Write-Host "Setting up CUA Computer Server..." +$cuaServerSetupScript = Join-Path $scriptFolder -ChildPath "setup-cua-server.ps1" +if (Test-Path $cuaServerSetupScript) { + & $cuaServerSetupScript + Write-Host "CUA Computer Server setup completed." +} else { + Write-Host "ERROR: setup-cua-server.ps1 not found at $cuaServerSetupScript" +} + +# Register on-logon task +$onLogonTaskName = "WindowsArena_OnLogon" +$onLogonScriptPath = "$scriptFolder\on-logon.ps1" +if (Get-ScheduledTask -TaskName $onLogonTaskName -ErrorAction SilentlyContinue) { + Write-Host "Scheduled task $onLogonTaskName already exists." +} else { + Write-Host "Registering new task $onLogonTaskName..." + Register-LogonTask -TaskName $onLogonTaskName -ScriptPath $onLogonScriptPath -LocalUser "Docker" +} + +Start-Sleep -Seconds 10 +Write-Host "Starting $onLogonTaskName task in background..." +Start-Process -WindowStyle Hidden -FilePath "powershell.exe" -ArgumentList "-Command", "Start-ScheduledTask -TaskName '$onLogonTaskName'" \ No newline at end of file