lightman-agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent.config.template.json +30 -0
- package/bin/cms-agent.js +233 -0
- package/nssm/nssm.exe +0 -0
- package/package.json +52 -0
- package/public/assets/index-CcBNCz6h.css +1 -0
- package/public/assets/index-H-8HDl46.js +1 -0
- package/public/index.html +19 -0
- package/scripts/guardian.ps1 +75 -0
- package/scripts/install-linux.sh +134 -0
- package/scripts/install-rpi.sh +117 -0
- package/scripts/install-windows.ps1 +529 -0
- package/scripts/launch-kiosk.vbs +101 -0
- package/scripts/lightman-agent.logrotate +12 -0
- package/scripts/lightman-agent.service +38 -0
- package/scripts/lightman-shell.bat +128 -0
- package/scripts/reinstall-windows.ps1 +26 -0
- package/scripts/restore-desktop.ps1 +32 -0
- package/scripts/setup.ps1 +116 -0
- package/scripts/setup.sh +115 -0
- package/scripts/uninstall-linux.sh +50 -0
- package/scripts/uninstall-windows.ps1 +54 -0
- package/src/commands/display.ts +177 -0
- package/src/commands/kiosk.ts +113 -0
- package/src/commands/maintenance.ts +106 -0
- package/src/commands/network.ts +129 -0
- package/src/commands/power.ts +163 -0
- package/src/commands/rpi.ts +45 -0
- package/src/commands/screenshot.ts +166 -0
- package/src/commands/serial.ts +17 -0
- package/src/commands/update.ts +124 -0
- package/src/index.ts +652 -0
- package/src/lib/config.ts +69 -0
- package/src/lib/identity.ts +40 -0
- package/src/lib/logger.ts +137 -0
- package/src/lib/platform.ts +10 -0
- package/src/lib/rpi.ts +180 -0
- package/src/lib/screens.ts +128 -0
- package/src/lib/types.ts +176 -0
- package/src/services/commands.ts +107 -0
- package/src/services/health.ts +161 -0
- package/src/services/kiosk.ts +395 -0
- package/src/services/localEvents.ts +60 -0
- package/src/services/logForwarder.ts +72 -0
- package/src/services/multiScreenKiosk.ts +324 -0
- package/src/services/oscBridge.ts +186 -0
- package/src/services/powerScheduler.ts +260 -0
- package/src/services/provisioning.ts +120 -0
- package/src/services/serialBridge.ts +230 -0
- package/src/services/serviceLauncher.ts +183 -0
- package/src/services/staticServer.ts +226 -0
- package/src/services/updater.ts +249 -0
- package/src/services/watchdog.ts +310 -0
- package/src/services/websocket.ts +152 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
# LIGHTMAN Agent - Complete Windows Installer
|
|
2
|
+
# Uses NSSM for rock-solid Windows Service. Shell replacement for kiosk.
|
|
3
|
+
# Cleans up any previous installation automatically before installing.
|
|
4
|
+
#
|
|
5
|
+
# Run as Administrator:
|
|
6
|
+
# powershell -ExecutionPolicy Bypass -File install-windows.ps1 -Slug "F-AV01" -Server "http://192.168.1.180:3401"
|
|
7
|
+
#
|
|
8
|
+
# Shell Replacement mode (RECOMMENDED for kiosk machines):
|
|
9
|
+
# powershell -ExecutionPolicy Bypass -File install-windows.ps1 -Slug "F-AV01" -Server "http://..." -ShellReplace
|
|
10
|
+
#Requires -RunAsAdministrator
|
|
11
|
+
|
|
12
|
+
param(
|
|
13
|
+
[Parameter(Mandatory=$true)] [string]$Slug,
|
|
14
|
+
[Parameter(Mandatory=$true)] [string]$Server,
|
|
15
|
+
[string]$Timezone = "Asia/Kolkata",
|
|
16
|
+
[string]$Username = "",
|
|
17
|
+
[switch]$ShellReplace = $false
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
$ErrorActionPreference = "Stop"
|
|
21
|
+
|
|
22
|
+
$InstallDir = "C:\Program Files\Lightman\Agent"
|
|
23
|
+
$LogDir = "C:\ProgramData\Lightman\logs"
|
|
24
|
+
$ChromeData = "C:\ProgramData\Lightman\chrome-kiosk"
|
|
25
|
+
$NssmDir = "C:\ProgramData\Lightman\nssm"
|
|
26
|
+
$NssmExe = "$NssmDir\nssm.exe"
|
|
27
|
+
$ServiceName = "LightmanAgent"
|
|
28
|
+
$GuardianTask = "LIGHTMAN Guardian"
|
|
29
|
+
$KioskTask = "LIGHTMAN Kiosk Browser"
|
|
30
|
+
$AgentTask = "LIGHTMAN Agent"
|
|
31
|
+
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
32
|
+
$AgentDir = Split-Path -Parent $ScriptDir
|
|
33
|
+
|
|
34
|
+
if (-not $Username) { $Username = $env:USERNAME }
|
|
35
|
+
|
|
36
|
+
Write-Host ""
|
|
37
|
+
Write-Host "=============================================" -ForegroundColor Cyan
|
|
38
|
+
Write-Host " LIGHTMAN Agent - Complete Windows Installer" -ForegroundColor Cyan
|
|
39
|
+
Write-Host "=============================================" -ForegroundColor Cyan
|
|
40
|
+
Write-Host " Device slug : $Slug"
|
|
41
|
+
Write-Host " Server URL : $Server"
|
|
42
|
+
Write-Host " Username : $Username"
|
|
43
|
+
Write-Host " Mode : $(if ($ShellReplace) { 'Shell Replacement' } else { 'Standard' })"
|
|
44
|
+
Write-Host ""
|
|
45
|
+
|
|
46
|
+
# ============================================================
|
|
47
|
+
# PHASE 0: NUKE EVERYTHING FROM PREVIOUS INSTALLS
|
|
48
|
+
# ============================================================
|
|
49
|
+
Write-Host "--- Phase 0: Cleaning previous installation ---" -ForegroundColor Cyan
|
|
50
|
+
$ErrorActionPreference = "Continue"
|
|
51
|
+
|
|
52
|
+
# Stop and remove NSSM service
|
|
53
|
+
Write-Host "[0a] Removing old services..." -ForegroundColor Yellow
|
|
54
|
+
if (Test-Path $NssmExe) {
|
|
55
|
+
& $NssmExe stop $ServiceName 2>$null
|
|
56
|
+
& $NssmExe remove $ServiceName confirm 2>$null
|
|
57
|
+
}
|
|
58
|
+
foreach ($sn in @($ServiceName, "lightmanagent.exe", "LightmanAgent.exe")) {
|
|
59
|
+
sc.exe stop $sn 2>$null; sc.exe delete $sn 2>$null
|
|
60
|
+
}
|
|
61
|
+
$oldSvc = Get-Service -DisplayName "LIGHTMAN*" -ErrorAction SilentlyContinue
|
|
62
|
+
if ($oldSvc) { Stop-Service -Name $oldSvc.Name -Force -ErrorAction SilentlyContinue; sc.exe delete $oldSvc.Name 2>$null }
|
|
63
|
+
|
|
64
|
+
# Remove scheduled tasks (from previous task-scheduler-based installs)
|
|
65
|
+
Write-Host "[0b] Removing old scheduled tasks..." -ForegroundColor Yellow
|
|
66
|
+
foreach ($tn in @($AgentTask, $KioskTask, $GuardianTask)) {
|
|
67
|
+
$t = Get-ScheduledTask -TaskName $tn -ErrorAction SilentlyContinue
|
|
68
|
+
if ($t) { Stop-ScheduledTask -TaskName $tn -ErrorAction SilentlyContinue; Unregister-ScheduledTask -TaskName $tn -Confirm:$false -ErrorAction SilentlyContinue }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Kill processes
|
|
72
|
+
Write-Host "[0c] Killing node.exe and Chrome..." -ForegroundColor Yellow
|
|
73
|
+
Get-Process -Name "node" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
|
74
|
+
Get-Process -Name "chrome" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
|
75
|
+
Start-Sleep -Seconds 2
|
|
76
|
+
|
|
77
|
+
# Remove old files (keep NSSM and logs)
|
|
78
|
+
Write-Host "[0d] Removing old agent files..." -ForegroundColor Yellow
|
|
79
|
+
Remove-Item -Path $InstallDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
80
|
+
Remove-Item -Path "C:\ProgramData\Lightman\kiosk-url.txt" -Force -ErrorAction SilentlyContinue
|
|
81
|
+
|
|
82
|
+
# Remove firewall rule
|
|
83
|
+
Remove-NetFirewallRule -DisplayName "LIGHTMAN Agent WebSocket" -ErrorAction SilentlyContinue
|
|
84
|
+
|
|
85
|
+
$ErrorActionPreference = "Stop"
|
|
86
|
+
Start-Sleep -Seconds 2
|
|
87
|
+
Write-Host " Clean slate" -ForegroundColor Green
|
|
88
|
+
Write-Host ""
|
|
89
|
+
|
|
90
|
+
# ============================================================
|
|
91
|
+
# PART 1: BUILD & INSTALL
|
|
92
|
+
# ============================================================
|
|
93
|
+
|
|
94
|
+
# --- 1. Node.js ---
|
|
95
|
+
Write-Host "[1/19] Checking Node.js..." -ForegroundColor Yellow
|
|
96
|
+
try {
|
|
97
|
+
$nodeVersion = (node -v) -replace 'v', ''
|
|
98
|
+
if ([int]($nodeVersion.Split('.')[0]) -lt 20) { throw "old" }
|
|
99
|
+
Write-Host " Found Node.js v$nodeVersion"
|
|
100
|
+
} catch {
|
|
101
|
+
Write-Host " Installing Node.js v20.18.0..." -ForegroundColor Yellow
|
|
102
|
+
$installer = "$env:TEMP\node-setup.msi"
|
|
103
|
+
Invoke-WebRequest -Uri "https://nodejs.org/dist/v20.18.0/node-v20.18.0-x64.msi" -OutFile $installer -UseBasicParsing
|
|
104
|
+
Start-Process msiexec.exe -ArgumentList "/i `"$installer`" /qn /norestart" -Wait -NoNewWindow
|
|
105
|
+
Remove-Item $installer -Force -ErrorAction SilentlyContinue
|
|
106
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
107
|
+
if (-not (Get-Command node -ErrorAction SilentlyContinue)) { Write-Host " FATAL: Node.js install failed!" -ForegroundColor Red; exit 1 }
|
|
108
|
+
Write-Host " Node.js installed" -ForegroundColor Green
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# --- 2. Build ---
|
|
112
|
+
Write-Host "[2/19] Building agent..." -ForegroundColor Yellow
|
|
113
|
+
Push-Location $AgentDir
|
|
114
|
+
$ErrorActionPreference = "Continue"
|
|
115
|
+
& npm install 2>&1 | Out-Host
|
|
116
|
+
& npm run build 2>&1 | Out-Host
|
|
117
|
+
$ErrorActionPreference = "Stop"
|
|
118
|
+
if (-not (Test-Path "$AgentDir\dist\index.js")) { Write-Host " FATAL: Build failed!" -ForegroundColor Red; exit 1 }
|
|
119
|
+
Pop-Location
|
|
120
|
+
Write-Host " Build successful"
|
|
121
|
+
|
|
122
|
+
# --- 3. Directories ---
|
|
123
|
+
Write-Host "[3/19] Creating directories..." -ForegroundColor Yellow
|
|
124
|
+
foreach ($d in @($InstallDir, $LogDir, $ChromeData, $NssmDir)) { New-Item -ItemType Directory -Force -Path $d | Out-Null }
|
|
125
|
+
|
|
126
|
+
# --- 4. Copy files ---
|
|
127
|
+
Write-Host "[4/19] Copying agent files..." -ForegroundColor Yellow
|
|
128
|
+
Copy-Item "$AgentDir\dist" "$InstallDir\dist" -Recurse -Force
|
|
129
|
+
Copy-Item "$AgentDir\package.json" "$InstallDir\package.json" -Force
|
|
130
|
+
if (Test-Path "$AgentDir\package-lock.json") { Copy-Item "$AgentDir\package-lock.json" "$InstallDir\package-lock.json" -Force }
|
|
131
|
+
Copy-Item "$AgentDir\agent.config.template.json" "$InstallDir\agent.config.template.json" -Force
|
|
132
|
+
if (Test-Path "$AgentDir\public") { Copy-Item "$AgentDir\public" "$InstallDir\public" -Recurse -Force }
|
|
133
|
+
|
|
134
|
+
# --- 5. Install deps ---
|
|
135
|
+
Write-Host "[5/19] Installing dependencies..." -ForegroundColor Yellow
|
|
136
|
+
Push-Location $InstallDir
|
|
137
|
+
$ErrorActionPreference = "Continue"
|
|
138
|
+
& npm ci --omit=dev --ignore-scripts 2>&1 | Out-Host
|
|
139
|
+
if ($LASTEXITCODE -ne 0) { & npm install --omit=dev --ignore-scripts 2>&1 | Out-Host }
|
|
140
|
+
$ErrorActionPreference = "Stop"
|
|
141
|
+
Pop-Location
|
|
142
|
+
|
|
143
|
+
# --- 6. Generate config ---
|
|
144
|
+
Write-Host "[6/19] Generating config..." -ForegroundColor Yellow
|
|
145
|
+
if ($ShellReplace) {
|
|
146
|
+
& "$ScriptDir\setup.ps1" -Slug $Slug -Server $Server -Timezone $Timezone -InstallDir $InstallDir -ShellMode
|
|
147
|
+
} else {
|
|
148
|
+
& "$ScriptDir\setup.ps1" -Slug $Slug -Server $Server -Timezone $Timezone -InstallDir $InstallDir
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# --- 7. Fix BOM ---
|
|
152
|
+
Write-Host "[7/19] Fixing config encoding..." -ForegroundColor Yellow
|
|
153
|
+
$configPath = Join-Path $InstallDir "agent.config.json"
|
|
154
|
+
if (-not (Test-Path $configPath)) { Write-Host " FATAL: config not created!" -ForegroundColor Red; exit 1 }
|
|
155
|
+
$raw = [System.IO.File]::ReadAllText($configPath)
|
|
156
|
+
[System.IO.File]::WriteAllText($configPath, $raw.TrimStart([char]0xFEFF), [System.Text.UTF8Encoding]::new($false))
|
|
157
|
+
|
|
158
|
+
# --- 8. Verify config ---
|
|
159
|
+
Write-Host "[8/19] Verifying config..." -ForegroundColor Yellow
|
|
160
|
+
Push-Location $InstallDir
|
|
161
|
+
$ErrorActionPreference = "Continue"
|
|
162
|
+
$jsonCheck = & node -e "try{const c=JSON.parse(require('fs').readFileSync('agent.config.json','utf8'));console.log('OK slug='+c.deviceSlug+' shellMode='+(c.kiosk&&c.kiosk.shellMode||false))}catch(e){console.log('FAIL: '+e.message);process.exit(1)}" 2>&1
|
|
163
|
+
$ErrorActionPreference = "Stop"
|
|
164
|
+
if ($LASTEXITCODE -ne 0) { Write-Host " FATAL: invalid config: $jsonCheck" -ForegroundColor Red; Pop-Location; exit 1 }
|
|
165
|
+
Pop-Location
|
|
166
|
+
Write-Host " $jsonCheck"
|
|
167
|
+
|
|
168
|
+
# --- 9. Download NSSM ---
|
|
169
|
+
Write-Host "[9/19] Setting up NSSM..." -ForegroundColor Yellow
|
|
170
|
+
if (-not (Test-Path $NssmExe)) {
|
|
171
|
+
# Check bundled copy first (fastest, no internet needed)
|
|
172
|
+
$bundled = Join-Path $AgentDir "nssm\nssm.exe"
|
|
173
|
+
if (Test-Path $bundled) {
|
|
174
|
+
Copy-Item $bundled $NssmExe -Force
|
|
175
|
+
Write-Host " Using bundled NSSM"
|
|
176
|
+
} else {
|
|
177
|
+
# Download from multiple sources
|
|
178
|
+
$nssmZip = "$env:TEMP\nssm.zip"
|
|
179
|
+
$downloaded = $false
|
|
180
|
+
$urls = @(
|
|
181
|
+
"https://nssm.cc/release/nssm-2.24.zip",
|
|
182
|
+
"https://nssm.cc/ci/nssm-2.24-101-g897c7ad.zip"
|
|
183
|
+
)
|
|
184
|
+
foreach ($url in $urls) {
|
|
185
|
+
if ($downloaded) { break }
|
|
186
|
+
Write-Host " Downloading from $url ..."
|
|
187
|
+
try {
|
|
188
|
+
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
189
|
+
Invoke-WebRequest -Uri $url -OutFile $nssmZip -UseBasicParsing -TimeoutSec 60
|
|
190
|
+
if ((Test-Path $nssmZip) -and (Get-Item $nssmZip).Length -gt 10000) {
|
|
191
|
+
$downloaded = $true
|
|
192
|
+
}
|
|
193
|
+
} catch {
|
|
194
|
+
Write-Host " Failed: $_" -ForegroundColor DarkYellow
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if ($downloaded) {
|
|
198
|
+
Expand-Archive -Path $nssmZip -DestinationPath "$env:TEMP\nssm-extract" -Force
|
|
199
|
+
# Find nssm.exe in extracted folder (handles different zip structures)
|
|
200
|
+
$found = Get-ChildItem "$env:TEMP\nssm-extract" -Recurse -Filter "nssm.exe" | Where-Object { $_.DirectoryName -like "*win64*" } | Select-Object -First 1
|
|
201
|
+
if (-not $found) { $found = Get-ChildItem "$env:TEMP\nssm-extract" -Recurse -Filter "nssm.exe" | Select-Object -First 1 }
|
|
202
|
+
if ($found) { Copy-Item $found.FullName $NssmExe -Force }
|
|
203
|
+
Remove-Item $nssmZip -Force -ErrorAction SilentlyContinue
|
|
204
|
+
Remove-Item "$env:TEMP\nssm-extract" -Recurse -Force -ErrorAction SilentlyContinue
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (-not (Test-Path $NssmExe)) {
|
|
209
|
+
Write-Host ""
|
|
210
|
+
Write-Host " NSSM download failed. Manual fix:" -ForegroundColor Red
|
|
211
|
+
Write-Host " 1. Download nssm-2.24.zip from https://nssm.cc/release/nssm-2.24.zip" -ForegroundColor Yellow
|
|
212
|
+
Write-Host " 2. Extract win64\nssm.exe to: $NssmExe" -ForegroundColor Yellow
|
|
213
|
+
Write-Host " 3. Re-run this script" -ForegroundColor Yellow
|
|
214
|
+
Write-Host ""
|
|
215
|
+
Write-Host " OR bundle it in the repo:" -ForegroundColor Yellow
|
|
216
|
+
Write-Host " Copy nssm.exe to: $AgentDir\nssm\nssm.exe" -ForegroundColor Yellow
|
|
217
|
+
exit 1
|
|
218
|
+
}
|
|
219
|
+
Write-Host " NSSM ready: $NssmExe"
|
|
220
|
+
|
|
221
|
+
# --- 10. Install Windows Service via NSSM ---
|
|
222
|
+
Write-Host "[10/19] Installing Windows Service..." -ForegroundColor Yellow
|
|
223
|
+
|
|
224
|
+
# Clean slate
|
|
225
|
+
$ErrorActionPreference = "Continue"
|
|
226
|
+
& $NssmExe stop $ServiceName 2>$null
|
|
227
|
+
& $NssmExe remove $ServiceName confirm 2>$null
|
|
228
|
+
sc.exe delete $ServiceName 2>$null
|
|
229
|
+
Start-Sleep -Seconds 2
|
|
230
|
+
$ErrorActionPreference = "Stop"
|
|
231
|
+
|
|
232
|
+
$nodePath = (Get-Command node).Source
|
|
233
|
+
|
|
234
|
+
# Install
|
|
235
|
+
& $NssmExe install $ServiceName $nodePath "dist\index.js"
|
|
236
|
+
if ($LASTEXITCODE -ne 0) { Write-Host " FATAL: NSSM install failed!" -ForegroundColor Red; exit 1 }
|
|
237
|
+
|
|
238
|
+
# Configure
|
|
239
|
+
& $NssmExe set $ServiceName AppDirectory $InstallDir
|
|
240
|
+
& $NssmExe set $ServiceName DisplayName "LIGHTMAN Agent"
|
|
241
|
+
& $NssmExe set $ServiceName Description "LIGHTMAN kiosk agent - display management and monitoring"
|
|
242
|
+
& $NssmExe set $ServiceName Start SERVICE_AUTO_START
|
|
243
|
+
& $NssmExe set $ServiceName AppStdout "$LogDir\service-stdout.log"
|
|
244
|
+
& $NssmExe set $ServiceName AppStderr "$LogDir\service-stderr.log"
|
|
245
|
+
& $NssmExe set $ServiceName AppStdoutCreationDisposition 4
|
|
246
|
+
& $NssmExe set $ServiceName AppStderrCreationDisposition 4
|
|
247
|
+
& $NssmExe set $ServiceName AppRotateFiles 1
|
|
248
|
+
& $NssmExe set $ServiceName AppRotateBytes 5242880
|
|
249
|
+
& $NssmExe set $ServiceName AppRestartDelay 10000
|
|
250
|
+
& $NssmExe set $ServiceName AppExit Default Restart
|
|
251
|
+
|
|
252
|
+
# Verify service was created
|
|
253
|
+
Start-Sleep -Seconds 2
|
|
254
|
+
$svcCheck = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
|
255
|
+
if (-not $svcCheck) {
|
|
256
|
+
$svcCheck = Get-Service -DisplayName "LIGHTMAN*" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
257
|
+
}
|
|
258
|
+
if (-not $svcCheck) {
|
|
259
|
+
Write-Host " FATAL: Service was not created!" -ForegroundColor Red
|
|
260
|
+
exit 1
|
|
261
|
+
}
|
|
262
|
+
Write-Host " Service installed: $($svcCheck.Name)" -ForegroundColor Green
|
|
263
|
+
|
|
264
|
+
# Recovery policy
|
|
265
|
+
sc.exe failure $svcCheck.Name reset= 86400 actions= restart/5000/restart/10000/restart/30000 2>$null
|
|
266
|
+
|
|
267
|
+
# --- 11. Start service ---
|
|
268
|
+
Write-Host "[11/19] Starting service..." -ForegroundColor Yellow
|
|
269
|
+
Start-Service -Name $svcCheck.Name -ErrorAction SilentlyContinue
|
|
270
|
+
Start-Sleep -Seconds 5
|
|
271
|
+
$svcCheck.Refresh()
|
|
272
|
+
|
|
273
|
+
if ($svcCheck.Status -eq 'Running') {
|
|
274
|
+
Write-Host " Service is RUNNING" -ForegroundColor Green
|
|
275
|
+
} else {
|
|
276
|
+
Write-Host " Service status: $($svcCheck.Status) - check $LogDir" -ForegroundColor Yellow
|
|
277
|
+
Start-Sleep -Seconds 3
|
|
278
|
+
Start-Service -Name $svcCheck.Name -ErrorAction SilentlyContinue
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
# Wait for port 3403
|
|
282
|
+
$portUp = $false
|
|
283
|
+
for ($i = 0; $i -lt 10; $i++) {
|
|
284
|
+
$ErrorActionPreference = "Continue"
|
|
285
|
+
$n = netstat -an 2>$null | findstr ":3403.*LISTENING" 2>$null
|
|
286
|
+
$ErrorActionPreference = "Stop"
|
|
287
|
+
if ($n) { $portUp = $true; break }
|
|
288
|
+
Start-Sleep -Seconds 2
|
|
289
|
+
}
|
|
290
|
+
if ($portUp) { Write-Host " Port 3403 LISTENING" -ForegroundColor Green }
|
|
291
|
+
else { Write-Host " Port 3403 not yet up (may take a moment)" -ForegroundColor Yellow }
|
|
292
|
+
|
|
293
|
+
# --- 12. Firewall ---
|
|
294
|
+
Write-Host "[12/19] Configuring firewall..." -ForegroundColor Yellow
|
|
295
|
+
$ErrorActionPreference = "Continue"
|
|
296
|
+
if (-not (Get-NetFirewallRule -DisplayName "LIGHTMAN Agent WebSocket" -ErrorAction SilentlyContinue)) {
|
|
297
|
+
New-NetFirewallRule -DisplayName "LIGHTMAN Agent WebSocket" -Direction Outbound -Action Allow -Protocol TCP -RemotePort 3001 -Description "LIGHTMAN Agent" | Out-Null
|
|
298
|
+
Write-Host " Created"
|
|
299
|
+
} else { Write-Host " Already exists" }
|
|
300
|
+
|
|
301
|
+
# ============================================================
|
|
302
|
+
# PART 2: KIOSK CONFIGURATION
|
|
303
|
+
# ============================================================
|
|
304
|
+
$ErrorActionPreference = "Continue"
|
|
305
|
+
Write-Host ""
|
|
306
|
+
Write-Host "--- Configuring Kiosk Mode ---" -ForegroundColor Cyan
|
|
307
|
+
Write-Host ""
|
|
308
|
+
|
|
309
|
+
# --- 13. Auto-login ---
|
|
310
|
+
Write-Host "[13/19] Enabling auto-login..." -ForegroundColor Yellow
|
|
311
|
+
$RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
|
|
312
|
+
$targetUser = Get-LocalUser -Name $Username -ErrorAction SilentlyContinue
|
|
313
|
+
$isMsAccount = $targetUser -and $targetUser.PrincipalSource -eq 'MicrosoftAccount'
|
|
314
|
+
|
|
315
|
+
if ($isMsAccount) {
|
|
316
|
+
$KioskUser = "kiosk"
|
|
317
|
+
$existingKiosk = Get-LocalUser -Name $KioskUser -ErrorAction SilentlyContinue
|
|
318
|
+
if (-not $existingKiosk) { net user $KioskUser "" /add 2>$null; net localgroup Administrators $KioskUser /add 2>$null }
|
|
319
|
+
else { net user $KioskUser "" 2>$null }
|
|
320
|
+
$HidePath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList"
|
|
321
|
+
if (-not (Test-Path $HidePath)) { New-Item -Path $HidePath -Force | Out-Null }
|
|
322
|
+
Set-ItemProperty -Path $HidePath -Name $Username -Value 0
|
|
323
|
+
$Username = $KioskUser
|
|
324
|
+
Write-Host " Created kiosk account, auto-login: $Username" -ForegroundColor Green
|
|
325
|
+
} else {
|
|
326
|
+
net user $Username "" 2>$null
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
$PwdLess = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PasswordLess\Device"
|
|
330
|
+
if (Test-Path $PwdLess) { Set-ItemProperty -Path $PwdLess -Name "DevicePasswordLessBuildVersion" -Value 0 }
|
|
331
|
+
|
|
332
|
+
$Passport = "HKLM:\SOFTWARE\Policies\Microsoft\PassportForWork"
|
|
333
|
+
if (-not (Test-Path $Passport)) { New-Item -Path $Passport -Force | Out-Null }
|
|
334
|
+
Set-ItemProperty -Path $Passport -Name "Enabled" -Value 0
|
|
335
|
+
|
|
336
|
+
Set-ItemProperty -Path $RegPath -Name "AutoAdminLogon" -Value "1"
|
|
337
|
+
Set-ItemProperty -Path $RegPath -Name "DefaultUserName" -Value $Username
|
|
338
|
+
Set-ItemProperty -Path $RegPath -Name "DefaultPassword" -Value ""
|
|
339
|
+
Set-ItemProperty -Path $RegPath -Name "DefaultDomainName" -Value ""
|
|
340
|
+
Set-ItemProperty -Path $RegPath -Name "DisableCAD" -Value 1
|
|
341
|
+
Set-ItemProperty -Path $RegPath -Name "AutoRestartShell" -Value 1
|
|
342
|
+
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "DisableAutomaticRestartSignOn" -Value 0
|
|
343
|
+
$OOBE = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\OOBE"
|
|
344
|
+
if (-not (Test-Path $OOBE)) { New-Item -Path $OOBE -Force | Out-Null }
|
|
345
|
+
Set-ItemProperty -Path $OOBE -Name "DisablePrivacyExperience" -Value 1
|
|
346
|
+
Write-Host " Auto-login enabled for: $Username"
|
|
347
|
+
|
|
348
|
+
# --- 14. Lock screen ---
|
|
349
|
+
Write-Host "[14/19] Removing lock screen..." -ForegroundColor Yellow
|
|
350
|
+
$LP = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Personalization"
|
|
351
|
+
if (-not (Test-Path $LP)) { New-Item -Path $LP -Force | Out-Null }
|
|
352
|
+
Set-ItemProperty -Path $LP -Name "NoLockScreen" -Value 1
|
|
353
|
+
|
|
354
|
+
$SD = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\SessionData"
|
|
355
|
+
if (Test-Path $SD) { Set-ItemProperty -Path $SD -Name "AllowLockScreen" -Value 0 -ErrorAction SilentlyContinue }
|
|
356
|
+
|
|
357
|
+
$CC = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent"
|
|
358
|
+
if (-not (Test-Path $CC)) { New-Item -Path $CC -Force | Out-Null }
|
|
359
|
+
Set-ItemProperty -Path $CC -Name "DisableWindowsConsumerFeatures" -Value 1
|
|
360
|
+
Set-ItemProperty -Path $CC -Name "DisableCloudOptimizedContent" -Value 1
|
|
361
|
+
$CCU = "HKCU:\SOFTWARE\Policies\Microsoft\Windows\CloudContent"
|
|
362
|
+
if (-not (Test-Path $CCU)) { New-Item -Path $CCU -Force | Out-Null }
|
|
363
|
+
Set-ItemProperty -Path $CCU -Name "DisableWindowsSpotlightFeatures" -Value 1
|
|
364
|
+
Set-ItemProperty -Path $CCU -Name "DisableTailoredExperiencesWithDiagnosticData" -Value 1
|
|
365
|
+
|
|
366
|
+
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "EnableFirstLogonAnimation" -Value 0
|
|
367
|
+
$SP = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
|
|
368
|
+
Set-ItemProperty -Path $SP -Name "DisableLockWorkstation" -Value 1
|
|
369
|
+
Set-ItemProperty -Path $SP -Name "HideFastUserSwitching" -Value 1
|
|
370
|
+
|
|
371
|
+
$DL = "HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
|
|
372
|
+
if (-not (Test-Path $DL)) { New-Item -Path $DL -Force | Out-Null }
|
|
373
|
+
Set-ItemProperty -Path $DL -Name "EnableGoodbye" -Value 0
|
|
374
|
+
|
|
375
|
+
$PS = "HKLM:\SOFTWARE\Policies\Microsoft\Power\PowerSettings\0e796bdb-100d-47d6-a2d5-f7d2daa51f51"
|
|
376
|
+
if (-not (Test-Path $PS)) { New-Item -Path $PS -Force | Out-Null }
|
|
377
|
+
Set-ItemProperty -Path $PS -Name "ACSettingIndex" -Value 0
|
|
378
|
+
Set-ItemProperty -Path $PS -Name "DCSettingIndex" -Value 0
|
|
379
|
+
powercfg /SETACVALUEINDEX SCHEME_CURRENT SUB_NONE CONSOLELOCK 0 2>&1 | Out-Null
|
|
380
|
+
powercfg /SETDCVALUEINDEX SCHEME_CURRENT SUB_NONE CONSOLELOCK 0 2>&1 | Out-Null
|
|
381
|
+
powercfg /SETACTIVE SCHEME_CURRENT 2>&1 | Out-Null
|
|
382
|
+
|
|
383
|
+
Set-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name "ScreenSaverIsSecure" -Value "0"
|
|
384
|
+
Set-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name "ScreenSaveActive" -Value "0"
|
|
385
|
+
Set-ItemProperty -Path $SP -Name "InactivityTimeoutSecs" -Value 0 -ErrorAction SilentlyContinue
|
|
386
|
+
try { Disable-ScheduledTask -TaskName "\Microsoft\Windows\Shell\CreateObjectTask" -ErrorAction SilentlyContinue | Out-Null } catch { }
|
|
387
|
+
Write-Host " Lock screen fully disabled"
|
|
388
|
+
|
|
389
|
+
# --- 15. Sleep ---
|
|
390
|
+
Write-Host "[15/19] Disabling sleep..." -ForegroundColor Yellow
|
|
391
|
+
powercfg /change monitor-timeout-ac 0 2>&1 | Out-Null
|
|
392
|
+
powercfg /change standby-timeout-ac 0 2>&1 | Out-Null
|
|
393
|
+
powercfg /change hibernate-timeout-ac 0 2>&1 | Out-Null
|
|
394
|
+
|
|
395
|
+
# --- 16. Harden ---
|
|
396
|
+
Write-Host "[16/19] Hardening Windows..." -ForegroundColor Yellow
|
|
397
|
+
$WU = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"
|
|
398
|
+
if (-not (Test-Path $WU)) { New-Item -Path $WU -Force | Out-Null }
|
|
399
|
+
Set-ItemProperty -Path $WU -Name "NoAutoRebootWithLoggedOnUsers" -Value 1
|
|
400
|
+
Set-ItemProperty -Path $WU -Name "AUOptions" -Value 2
|
|
401
|
+
$WUM = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
|
|
402
|
+
if (-not (Test-Path $WUM)) { New-Item -Path $WUM -Force | Out-Null }
|
|
403
|
+
Set-ItemProperty -Path $WUM -Name "SetAutoRestartNotificationDisable" -Value 1
|
|
404
|
+
Set-ItemProperty -Path $WUM -Name "SetActiveHours" -Value 1
|
|
405
|
+
Set-ItemProperty -Path $WUM -Name "ActiveHoursStart" -Value 0
|
|
406
|
+
Set-ItemProperty -Path $WUM -Name "ActiveHoursEnd" -Value 23
|
|
407
|
+
|
|
408
|
+
$NP = "HKCU:\SOFTWARE\Policies\Microsoft\Windows\Explorer"
|
|
409
|
+
if (-not (Test-Path $NP)) { New-Item -Path $NP -Force | Out-Null }
|
|
410
|
+
Set-ItemProperty -Path $NP -Name "DisableNotificationCenter" -Value 1
|
|
411
|
+
$TP = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\PushNotifications"
|
|
412
|
+
if (-not (Test-Path $TP)) { New-Item -Path $TP -Force | Out-Null }
|
|
413
|
+
Set-ItemProperty -Path $TP -Name "ToastEnabled" -Value 0
|
|
414
|
+
|
|
415
|
+
$WER = "HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting"
|
|
416
|
+
if (-not (Test-Path $WER)) { New-Item -Path $WER -Force | Out-Null }
|
|
417
|
+
Set-ItemProperty -Path $WER -Name "DontShowUI" -Value 1
|
|
418
|
+
Set-ItemProperty -Path $WER -Name "Disabled" -Value 1
|
|
419
|
+
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Windows" -Name "ErrorMode" -Value 2 -ErrorAction SilentlyContinue
|
|
420
|
+
|
|
421
|
+
$SR = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search"
|
|
422
|
+
if (-not (Test-Path $SR)) { New-Item -Path $SR -Force | Out-Null }
|
|
423
|
+
Set-ItemProperty -Path $SR -Name "AllowCortana" -Value 0
|
|
424
|
+
Write-Host " Done"
|
|
425
|
+
|
|
426
|
+
# --- 17. Kiosk Chrome ---
|
|
427
|
+
if ($ShellReplace) {
|
|
428
|
+
Write-Host "[17/19] SHELL REPLACEMENT..." -ForegroundColor Magenta
|
|
429
|
+
|
|
430
|
+
# Copy shell BAT (reads slug from agent.config.json - single source of truth)
|
|
431
|
+
$shellSource = Join-Path $ScriptDir "lightman-shell.bat"
|
|
432
|
+
$shellTarget = Join-Path $InstallDir "lightman-shell.bat"
|
|
433
|
+
if (Test-Path $shellSource) { Copy-Item $shellSource $shellTarget -Force }
|
|
434
|
+
|
|
435
|
+
# No sidecar file needed - shell BAT reads directly from agent.config.json
|
|
436
|
+
|
|
437
|
+
# Replace shell
|
|
438
|
+
$ShellReg = "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
|
|
439
|
+
if (-not (Test-Path $ShellReg)) { New-Item -Path $ShellReg -Force | Out-Null }
|
|
440
|
+
Set-ItemProperty -Path $ShellReg -Name "Shell" -Value """$shellTarget"""
|
|
441
|
+
$HKLMShell = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
|
|
442
|
+
$orig = (Get-ItemProperty -Path $HKLMShell -Name "Shell" -ErrorAction SilentlyContinue).Shell
|
|
443
|
+
if ($orig -and $orig -notlike "*lightman*") { Set-ItemProperty -Path $HKLMShell -Name "Shell_Original" -Value $orig }
|
|
444
|
+
Set-ItemProperty -Path $HKLMShell -Name "Shell" -Value """$shellTarget"""
|
|
445
|
+
|
|
446
|
+
Write-Host " Shell replaced -> lightman-shell.bat" -ForegroundColor Green
|
|
447
|
+
Write-Host " Recovery: scripts\restore-desktop.ps1" -ForegroundColor Yellow
|
|
448
|
+
|
|
449
|
+
# Remove kiosk task if exists
|
|
450
|
+
$kt = Get-ScheduledTask -TaskName $KioskTask -ErrorAction SilentlyContinue
|
|
451
|
+
if ($kt) { Unregister-ScheduledTask -TaskName $KioskTask -Confirm:$false }
|
|
452
|
+
} else {
|
|
453
|
+
Write-Host "[17/19] Standard mode - kiosk browser task..." -ForegroundColor Yellow
|
|
454
|
+
$vbs = Join-Path $ScriptDir "launch-kiosk.vbs"
|
|
455
|
+
$vbsT = Join-Path $InstallDir "launch-kiosk.vbs"
|
|
456
|
+
if (Test-Path $vbs) { Copy-Item $vbs $vbsT -Force }
|
|
457
|
+
$kt = Get-ScheduledTask -TaskName $KioskTask -ErrorAction SilentlyContinue
|
|
458
|
+
if ($kt) { Unregister-ScheduledTask -TaskName $KioskTask -Confirm:$false }
|
|
459
|
+
$kA = New-ScheduledTaskAction -Execute "wscript.exe" -Argument """$vbsT""" -WorkingDirectory $InstallDir
|
|
460
|
+
$kT1 = New-ScheduledTaskTrigger -AtLogOn -User $Username
|
|
461
|
+
$kT2 = New-ScheduledTaskTrigger -AtStartup
|
|
462
|
+
$kS = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
|
|
463
|
+
Register-ScheduledTask -TaskName $KioskTask -Action $kA -Trigger @($kT1,$kT2) -Settings $kS -RunLevel Highest -Description "Chrome kiosk at logon/startup" -Force | Out-Null
|
|
464
|
+
Write-Host " Kiosk browser task registered"
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
# --- 18. Guardian ---
|
|
468
|
+
Write-Host "[18/19] Registering Guardian..." -ForegroundColor Yellow
|
|
469
|
+
$gSrc = Join-Path $ScriptDir "guardian.ps1"
|
|
470
|
+
$gDst = Join-Path $InstallDir "guardian.ps1"
|
|
471
|
+
if (Test-Path $gSrc) { Copy-Item $gSrc $gDst -Force }
|
|
472
|
+
$gt = Get-ScheduledTask -TaskName $GuardianTask -ErrorAction SilentlyContinue
|
|
473
|
+
if ($gt) { Unregister-ScheduledTask -TaskName $GuardianTask -Confirm:$false }
|
|
474
|
+
$gA = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -WindowStyle Hidden -File ""$gDst""" -WorkingDirectory $InstallDir
|
|
475
|
+
$gT = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 5) -RepetitionDuration (New-TimeSpan -Days 365)
|
|
476
|
+
$gS = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Minutes 2)
|
|
477
|
+
$gP = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
|
478
|
+
Register-ScheduledTask -TaskName $GuardianTask -Action $gA -Trigger $gT -Settings $gS -Principal $gP -Description "LIGHTMAN health check every 5 min" -Force | Out-Null
|
|
479
|
+
|
|
480
|
+
foreach ($task in @("\Microsoft\Windows\UpdateOrchestrator\Reboot","\Microsoft\Windows\UpdateOrchestrator\Schedule Retry Scan","\Microsoft\Windows\WindowsUpdate\Scheduled Start")) {
|
|
481
|
+
try { Disable-ScheduledTask -TaskName $task -ErrorAction SilentlyContinue | Out-Null } catch { }
|
|
482
|
+
}
|
|
483
|
+
Write-Host " Guardian registered"
|
|
484
|
+
|
|
485
|
+
# --- 19. Final verification ---
|
|
486
|
+
Write-Host "[19/19] Verification..." -ForegroundColor Yellow
|
|
487
|
+
Start-Sleep -Seconds 3
|
|
488
|
+
|
|
489
|
+
$finalSvc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
|
490
|
+
if (-not $finalSvc) { $finalSvc = Get-Service -DisplayName "LIGHTMAN*" -ErrorAction SilentlyContinue | Select-Object -First 1 }
|
|
491
|
+
$svcStatus = if ($finalSvc) { "$($finalSvc.Status)" } else { "NOT FOUND" }
|
|
492
|
+
|
|
493
|
+
$cfgOk = $false
|
|
494
|
+
try {
|
|
495
|
+
Push-Location $InstallDir
|
|
496
|
+
$cfgResult = & node -e "const c=JSON.parse(require('fs').readFileSync('agent.config.json','utf8'));console.log(JSON.stringify({slug:c.deviceSlug,shell:c.kiosk&&c.kiosk.shellMode||false}))" 2>&1
|
|
497
|
+
$cfgData = $cfgResult | ConvertFrom-Json
|
|
498
|
+
Pop-Location
|
|
499
|
+
$cfgOk = $true
|
|
500
|
+
} catch { Pop-Location }
|
|
501
|
+
|
|
502
|
+
Write-Host ""
|
|
503
|
+
Write-Host "=============================================" -ForegroundColor Green
|
|
504
|
+
Write-Host " INSTALLATION COMPLETE" -ForegroundColor Green
|
|
505
|
+
Write-Host "=============================================" -ForegroundColor Green
|
|
506
|
+
Write-Host ""
|
|
507
|
+
Write-Host " Slug : $Slug"
|
|
508
|
+
Write-Host " Server : $Server"
|
|
509
|
+
Write-Host " Install : $InstallDir"
|
|
510
|
+
Write-Host " Logs : $LogDir"
|
|
511
|
+
Write-Host " User : $Username"
|
|
512
|
+
Write-Host ""
|
|
513
|
+
Write-Host " Service : $svcStatus" -ForegroundColor $(if ($svcStatus -eq 'Running') { 'Green' } else { 'Red' })
|
|
514
|
+
if ($cfgOk) {
|
|
515
|
+
Write-Host " Config slug: $($cfgData.slug)" -ForegroundColor $(if ($cfgData.slug -eq $Slug) { 'Green' } else { 'Red' })
|
|
516
|
+
Write-Host " Shell mode : $($cfgData.shell)" -ForegroundColor $(if ($cfgData.shell -eq $ShellReplace.IsPresent) { 'Green' } else { 'Red' })
|
|
517
|
+
}
|
|
518
|
+
Write-Host ""
|
|
519
|
+
Write-Host " Manage:" -ForegroundColor DarkGray
|
|
520
|
+
Write-Host " $NssmExe stop $ServiceName" -ForegroundColor DarkGray
|
|
521
|
+
Write-Host " $NssmExe start $ServiceName" -ForegroundColor DarkGray
|
|
522
|
+
Write-Host " $NssmExe restart $ServiceName" -ForegroundColor DarkGray
|
|
523
|
+
Write-Host ""
|
|
524
|
+
Write-Host " BIOS (manual):" -ForegroundColor Red
|
|
525
|
+
Write-Host " After Power Loss = Power On" -ForegroundColor Red
|
|
526
|
+
Write-Host " Wake-on-LAN = Enabled" -ForegroundColor Red
|
|
527
|
+
Write-Host ""
|
|
528
|
+
Write-Host " REBOOT NOW: Restart-Computer" -ForegroundColor Yellow
|
|
529
|
+
Write-Host ""
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
' LIGHTMAN Kiosk Launcher
|
|
2
|
+
' Runs at user logon AND at system startup to start the kiosk browser.
|
|
3
|
+
' Waits for the agent service to be ready before launching Chrome.
|
|
4
|
+
' If the agent is already managing Chrome, this script exits gracefully.
|
|
5
|
+
|
|
6
|
+
Set objShell = CreateObject("WScript.Shell")
|
|
7
|
+
Set objFSO = CreateObject("Scripting.FileSystemObject")
|
|
8
|
+
|
|
9
|
+
' --- Configuration ---
|
|
10
|
+
configPath = "C:\Program Files\Lightman\Agent\agent.config.json"
|
|
11
|
+
maxWaitSeconds = 120 ' Max time to wait for agent service
|
|
12
|
+
checkIntervalMs = 5000 ' Check every 5 seconds
|
|
13
|
+
|
|
14
|
+
' --- Wait for config file to exist (agent might still be installing) ---
|
|
15
|
+
If Not objFSO.FileExists(configPath) Then
|
|
16
|
+
WScript.Sleep 10000
|
|
17
|
+
If Not objFSO.FileExists(configPath) Then
|
|
18
|
+
WScript.Quit 1
|
|
19
|
+
End If
|
|
20
|
+
End If
|
|
21
|
+
|
|
22
|
+
' --- Read config ---
|
|
23
|
+
Set objFile = objFSO.OpenTextFile(configPath, 1)
|
|
24
|
+
jsonText = objFile.ReadAll
|
|
25
|
+
objFile.Close
|
|
26
|
+
|
|
27
|
+
browserPath = ExtractJsonValue(jsonText, "browserPath")
|
|
28
|
+
defaultUrl = ExtractJsonValue(jsonText, "defaultUrl")
|
|
29
|
+
|
|
30
|
+
If browserPath = "" Or defaultUrl = "" Then
|
|
31
|
+
WScript.Quit 1
|
|
32
|
+
End If
|
|
33
|
+
|
|
34
|
+
' --- Wait for network connectivity ---
|
|
35
|
+
' Try to ping the server (extract hostname from URL)
|
|
36
|
+
waitedMs = 0
|
|
37
|
+
Do While waitedMs < (maxWaitSeconds * 1000)
|
|
38
|
+
' Check if Chrome is already running (agent's KioskManager may have launched it)
|
|
39
|
+
Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
|
|
40
|
+
Set colProcesses = objWMI.ExecQuery("SELECT ProcessId FROM Win32_Process WHERE Name = 'chrome.exe'")
|
|
41
|
+
If colProcesses.Count > 0 Then
|
|
42
|
+
' Chrome already running - agent is handling it. Exit gracefully.
|
|
43
|
+
WScript.Quit 0
|
|
44
|
+
End If
|
|
45
|
+
|
|
46
|
+
' Check if LIGHTMAN service is running
|
|
47
|
+
Set colServices = objWMI.ExecQuery("SELECT State FROM Win32_Service WHERE DisplayName LIKE 'LIGHTMAN%'")
|
|
48
|
+
serviceRunning = False
|
|
49
|
+
For Each svc In colServices
|
|
50
|
+
If LCase(svc.State) = "running" Then
|
|
51
|
+
serviceRunning = True
|
|
52
|
+
End If
|
|
53
|
+
Next
|
|
54
|
+
|
|
55
|
+
If serviceRunning Then
|
|
56
|
+
' Service is running - give it a few more seconds to launch Chrome itself
|
|
57
|
+
WScript.Sleep 15000
|
|
58
|
+
|
|
59
|
+
' Re-check if Chrome appeared (agent launched it)
|
|
60
|
+
Set colProcesses2 = objWMI.ExecQuery("SELECT ProcessId FROM Win32_Process WHERE Name = 'chrome.exe'")
|
|
61
|
+
If colProcesses2.Count > 0 Then
|
|
62
|
+
' Agent launched Chrome successfully. Exit.
|
|
63
|
+
WScript.Quit 0
|
|
64
|
+
End If
|
|
65
|
+
|
|
66
|
+
' Agent is running but hasn't launched Chrome yet - we'll do it
|
|
67
|
+
Exit Do
|
|
68
|
+
End If
|
|
69
|
+
|
|
70
|
+
WScript.Sleep checkIntervalMs
|
|
71
|
+
waitedMs = waitedMs + checkIntervalMs
|
|
72
|
+
Loop
|
|
73
|
+
|
|
74
|
+
' --- Build Chrome kiosk args ---
|
|
75
|
+
chromeArgs = "--kiosk --noerrdialogs --disable-infobars --disable-session-crashed-bubble --no-first-run --no-default-browser-check --start-fullscreen --disable-translate --disable-extensions --autoplay-policy=no-user-gesture-required"
|
|
76
|
+
|
|
77
|
+
userDataDir = ExtractJsonValue(jsonText, "user-data-dir")
|
|
78
|
+
If userDataDir = "" Then
|
|
79
|
+
userDataDir = "C:\ProgramData\Lightman\chrome-kiosk"
|
|
80
|
+
End If
|
|
81
|
+
chromeArgs = chromeArgs & " --user-data-dir=""" & userDataDir & """"
|
|
82
|
+
|
|
83
|
+
' --- Launch Chrome ---
|
|
84
|
+
objShell.Run """" & browserPath & """ " & chromeArgs & " """ & defaultUrl & """", 1, False
|
|
85
|
+
|
|
86
|
+
' ========================================================
|
|
87
|
+
' Helper: extract a string value from JSON by key
|
|
88
|
+
' ========================================================
|
|
89
|
+
Function ExtractJsonValue(json, key)
|
|
90
|
+
ExtractJsonValue = ""
|
|
91
|
+
pos = InStr(json, """" & key & """")
|
|
92
|
+
If pos = 0 Then Exit Function
|
|
93
|
+
pos = InStr(pos, json, ":")
|
|
94
|
+
If pos = 0 Then Exit Function
|
|
95
|
+
pos = InStr(pos, json, """")
|
|
96
|
+
If pos = 0 Then Exit Function
|
|
97
|
+
pos = pos + 1
|
|
98
|
+
endPos = InStr(pos, json, """")
|
|
99
|
+
If endPos = 0 Then Exit Function
|
|
100
|
+
ExtractJsonValue = Mid(json, pos, endPos - pos)
|
|
101
|
+
End Function
|