nox-openclaw-hunter 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.
Files changed (211) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +140 -0
  3. package/bin/nox.js +2 -0
  4. package/dist/branding.d.ts +39 -0
  5. package/dist/branding.d.ts.map +1 -0
  6. package/dist/branding.js +66 -0
  7. package/dist/branding.js.map +1 -0
  8. package/dist/cli.d.ts +15 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +94 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands/export.d.ts +21 -0
  13. package/dist/commands/export.d.ts.map +1 -0
  14. package/dist/commands/export.js +616 -0
  15. package/dist/commands/export.js.map +1 -0
  16. package/dist/commands/index.d.ts +8 -0
  17. package/dist/commands/index.d.ts.map +1 -0
  18. package/dist/commands/index.js +8 -0
  19. package/dist/commands/index.js.map +1 -0
  20. package/dist/commands/isolate.d.ts +30 -0
  21. package/dist/commands/isolate.d.ts.map +1 -0
  22. package/dist/commands/isolate.js +547 -0
  23. package/dist/commands/isolate.js.map +1 -0
  24. package/dist/commands/purge.d.ts +22 -0
  25. package/dist/commands/purge.d.ts.map +1 -0
  26. package/dist/commands/purge.js +295 -0
  27. package/dist/commands/purge.js.map +1 -0
  28. package/dist/commands/scan.d.ts +23 -0
  29. package/dist/commands/scan.d.ts.map +1 -0
  30. package/dist/commands/scan.js +155 -0
  31. package/dist/commands/scan.js.map +1 -0
  32. package/dist/detector/app-bundle.d.ts +13 -0
  33. package/dist/detector/app-bundle.d.ts.map +1 -0
  34. package/dist/detector/app-bundle.js +27 -0
  35. package/dist/detector/app-bundle.js.map +1 -0
  36. package/dist/detector/cli-binary.d.ts +12 -0
  37. package/dist/detector/cli-binary.d.ts.map +1 -0
  38. package/dist/detector/cli-binary.js +66 -0
  39. package/dist/detector/cli-binary.js.map +1 -0
  40. package/dist/detector/config.d.ts +21 -0
  41. package/dist/detector/config.d.ts.map +1 -0
  42. package/dist/detector/config.js +337 -0
  43. package/dist/detector/config.js.map +1 -0
  44. package/dist/detector/detection-config.d.ts +24 -0
  45. package/dist/detector/detection-config.d.ts.map +1 -0
  46. package/dist/detector/detection-config.js +242 -0
  47. package/dist/detector/detection-config.js.map +1 -0
  48. package/dist/detector/docker.d.ts +10 -0
  49. package/dist/detector/docker.d.ts.map +1 -0
  50. package/dist/detector/docker.js +94 -0
  51. package/dist/detector/docker.js.map +1 -0
  52. package/dist/detector/index.d.ts +50 -0
  53. package/dist/detector/index.d.ts.map +1 -0
  54. package/dist/detector/index.js +155 -0
  55. package/dist/detector/index.js.map +1 -0
  56. package/dist/detector/network.d.ts +34 -0
  57. package/dist/detector/network.d.ts.map +1 -0
  58. package/dist/detector/network.js +205 -0
  59. package/dist/detector/network.js.map +1 -0
  60. package/dist/detector/process.d.ts +16 -0
  61. package/dist/detector/process.d.ts.map +1 -0
  62. package/dist/detector/process.js +47 -0
  63. package/dist/detector/process.js.map +1 -0
  64. package/dist/detector/service.d.ts +17 -0
  65. package/dist/detector/service.d.ts.map +1 -0
  66. package/dist/detector/service.js +51 -0
  67. package/dist/detector/service.js.map +1 -0
  68. package/dist/enforcer/docker-cleaner.d.ts +30 -0
  69. package/dist/enforcer/docker-cleaner.d.ts.map +1 -0
  70. package/dist/enforcer/docker-cleaner.js +163 -0
  71. package/dist/enforcer/docker-cleaner.js.map +1 -0
  72. package/dist/enforcer/file-remover.d.ts +34 -0
  73. package/dist/enforcer/file-remover.d.ts.map +1 -0
  74. package/dist/enforcer/file-remover.js +137 -0
  75. package/dist/enforcer/file-remover.js.map +1 -0
  76. package/dist/enforcer/index.d.ts +33 -0
  77. package/dist/enforcer/index.d.ts.map +1 -0
  78. package/dist/enforcer/index.js +142 -0
  79. package/dist/enforcer/index.js.map +1 -0
  80. package/dist/enforcer/process-killer.d.ts +18 -0
  81. package/dist/enforcer/process-killer.d.ts.map +1 -0
  82. package/dist/enforcer/process-killer.js +80 -0
  83. package/dist/enforcer/process-killer.js.map +1 -0
  84. package/dist/enforcer/service-stopper.d.ts +23 -0
  85. package/dist/enforcer/service-stopper.d.ts.map +1 -0
  86. package/dist/enforcer/service-stopper.js +95 -0
  87. package/dist/enforcer/service-stopper.js.map +1 -0
  88. package/dist/index.d.ts +6 -0
  89. package/dist/index.d.ts.map +1 -0
  90. package/dist/index.js +10 -0
  91. package/dist/index.js.map +1 -0
  92. package/dist/isolator/firewall.d.ts +25 -0
  93. package/dist/isolator/firewall.d.ts.map +1 -0
  94. package/dist/isolator/firewall.js +114 -0
  95. package/dist/isolator/firewall.js.map +1 -0
  96. package/dist/isolator/index.d.ts +63 -0
  97. package/dist/isolator/index.d.ts.map +1 -0
  98. package/dist/isolator/index.js +201 -0
  99. package/dist/isolator/index.js.map +1 -0
  100. package/dist/isolator/lockdown.d.ts +22 -0
  101. package/dist/isolator/lockdown.d.ts.map +1 -0
  102. package/dist/isolator/lockdown.js +401 -0
  103. package/dist/isolator/lockdown.js.map +1 -0
  104. package/dist/isolator/quarantine.d.ts +39 -0
  105. package/dist/isolator/quarantine.d.ts.map +1 -0
  106. package/dist/isolator/quarantine.js +364 -0
  107. package/dist/isolator/quarantine.js.map +1 -0
  108. package/dist/mdm/index.d.ts +93 -0
  109. package/dist/mdm/index.d.ts.map +1 -0
  110. package/dist/mdm/index.js +414 -0
  111. package/dist/mdm/index.js.map +1 -0
  112. package/dist/mdm/intune.d.ts +69 -0
  113. package/dist/mdm/intune.d.ts.map +1 -0
  114. package/dist/mdm/intune.js +409 -0
  115. package/dist/mdm/intune.js.map +1 -0
  116. package/dist/mdm/jamf.d.ts +58 -0
  117. package/dist/mdm/jamf.d.ts.map +1 -0
  118. package/dist/mdm/jamf.js +441 -0
  119. package/dist/mdm/jamf.js.map +1 -0
  120. package/dist/mdm/jumpcloud.d.ts +73 -0
  121. package/dist/mdm/jumpcloud.d.ts.map +1 -0
  122. package/dist/mdm/jumpcloud.js +470 -0
  123. package/dist/mdm/jumpcloud.js.map +1 -0
  124. package/dist/mdm/templates/detect.ps1.d.ts +30 -0
  125. package/dist/mdm/templates/detect.ps1.d.ts.map +1 -0
  126. package/dist/mdm/templates/detect.ps1.js +463 -0
  127. package/dist/mdm/templates/detect.ps1.js.map +1 -0
  128. package/dist/mdm/templates/detect.sh.d.ts +30 -0
  129. package/dist/mdm/templates/detect.sh.d.ts.map +1 -0
  130. package/dist/mdm/templates/detect.sh.js +474 -0
  131. package/dist/mdm/templates/detect.sh.js.map +1 -0
  132. package/dist/mdm/templates/enforce.ps1.d.ts +33 -0
  133. package/dist/mdm/templates/enforce.ps1.d.ts.map +1 -0
  134. package/dist/mdm/templates/enforce.ps1.js +681 -0
  135. package/dist/mdm/templates/enforce.ps1.js.map +1 -0
  136. package/dist/mdm/templates/enforce.sh.d.ts +33 -0
  137. package/dist/mdm/templates/enforce.sh.d.ts.map +1 -0
  138. package/dist/mdm/templates/enforce.sh.js +591 -0
  139. package/dist/mdm/templates/enforce.sh.js.map +1 -0
  140. package/dist/platform/darwin.d.ts +6 -0
  141. package/dist/platform/darwin.d.ts.map +1 -0
  142. package/dist/platform/darwin.js +192 -0
  143. package/dist/platform/darwin.js.map +1 -0
  144. package/dist/platform/index.d.ts +43 -0
  145. package/dist/platform/index.d.ts.map +1 -0
  146. package/dist/platform/index.js +27 -0
  147. package/dist/platform/index.js.map +1 -0
  148. package/dist/platform/linux.d.ts +6 -0
  149. package/dist/platform/linux.d.ts.map +1 -0
  150. package/dist/platform/linux.js +134 -0
  151. package/dist/platform/linux.js.map +1 -0
  152. package/dist/platform/windows.d.ts +6 -0
  153. package/dist/platform/windows.d.ts.map +1 -0
  154. package/dist/platform/windows.js +134 -0
  155. package/dist/platform/windows.js.map +1 -0
  156. package/dist/reporter/console.d.ts +27 -0
  157. package/dist/reporter/console.d.ts.map +1 -0
  158. package/dist/reporter/console.js +431 -0
  159. package/dist/reporter/console.js.map +1 -0
  160. package/dist/reporter/index.d.ts +11 -0
  161. package/dist/reporter/index.d.ts.map +1 -0
  162. package/dist/reporter/index.js +13 -0
  163. package/dist/reporter/index.js.map +1 -0
  164. package/dist/reporter/json.d.ts +61 -0
  165. package/dist/reporter/json.d.ts.map +1 -0
  166. package/dist/reporter/json.js +75 -0
  167. package/dist/reporter/json.js.map +1 -0
  168. package/dist/reporter/webhook.d.ts +57 -0
  169. package/dist/reporter/webhook.d.ts.map +1 -0
  170. package/dist/reporter/webhook.js +230 -0
  171. package/dist/reporter/webhook.js.map +1 -0
  172. package/dist/types/config.d.ts +116 -0
  173. package/dist/types/config.d.ts.map +1 -0
  174. package/dist/types/config.js +6 -0
  175. package/dist/types/config.js.map +1 -0
  176. package/dist/types/detection.d.ts +85 -0
  177. package/dist/types/detection.d.ts.map +1 -0
  178. package/dist/types/detection.js +5 -0
  179. package/dist/types/detection.js.map +1 -0
  180. package/dist/types/enforcement.d.ts +33 -0
  181. package/dist/types/enforcement.d.ts.map +1 -0
  182. package/dist/types/enforcement.js +5 -0
  183. package/dist/types/enforcement.js.map +1 -0
  184. package/dist/types/index.d.ts +8 -0
  185. package/dist/types/index.d.ts.map +1 -0
  186. package/dist/types/index.js +8 -0
  187. package/dist/types/index.js.map +1 -0
  188. package/dist/types/isolation.d.ts +55 -0
  189. package/dist/types/isolation.d.ts.map +1 -0
  190. package/dist/types/isolation.js +5 -0
  191. package/dist/types/isolation.js.map +1 -0
  192. package/dist/utils/exec.d.ts +48 -0
  193. package/dist/utils/exec.d.ts.map +1 -0
  194. package/dist/utils/exec.js +103 -0
  195. package/dist/utils/exec.js.map +1 -0
  196. package/dist/utils/fs.d.ts +34 -0
  197. package/dist/utils/fs.d.ts.map +1 -0
  198. package/dist/utils/fs.js +111 -0
  199. package/dist/utils/fs.js.map +1 -0
  200. package/dist/utils/index.d.ts +7 -0
  201. package/dist/utils/index.d.ts.map +1 -0
  202. package/dist/utils/index.js +7 -0
  203. package/dist/utils/index.js.map +1 -0
  204. package/dist/utils/logger.d.ts +14 -0
  205. package/dist/utils/logger.d.ts.map +1 -0
  206. package/dist/utils/logger.js +48 -0
  207. package/dist/utils/logger.js.map +1 -0
  208. package/docs/intune.md +390 -0
  209. package/docs/jamf.md +400 -0
  210. package/docs/jumpcloud.md +510 -0
  211. package/package.json +65 -0
@@ -0,0 +1,681 @@
1
+ /**
2
+ * PowerShell enforcement script template for MDM deployment.
3
+ * Targets Windows systems.
4
+ */
5
+ import { VERSION, COMPANY } from '../../branding.js';
6
+ /**
7
+ * Escape a string for safe use in PowerShell scripts.
8
+ * Escapes characters that could enable script injection.
9
+ */
10
+ function escapePowerShellString(str) {
11
+ // Remove null bytes
12
+ let escaped = str.replace(/\0/g, '');
13
+ // Escape backticks (PowerShell escape character)
14
+ escaped = escaped.replace(/`/g, '``');
15
+ // Escape dollar signs (variable interpolation)
16
+ escaped = escaped.replace(/\$/g, '`$');
17
+ // Escape double quotes
18
+ escaped = escaped.replace(/"/g, '`"');
19
+ return escaped;
20
+ }
21
+ /**
22
+ * Validate URL format for MDM scripts.
23
+ */
24
+ function validateMdmUrl(url) {
25
+ try {
26
+ const parsed = new URL(url);
27
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
28
+ throw new Error('Invalid protocol');
29
+ }
30
+ return escapePowerShellString(url);
31
+ }
32
+ catch {
33
+ throw new Error(`Invalid webhook URL: ${url}`);
34
+ }
35
+ }
36
+ /**
37
+ * Generate enforcement PowerShell script.
38
+ */
39
+ export function generateEnforcePowerShellScript(options = {}) {
40
+ const { webhookUrl, webhookToken, gatewayPort = 18789, verbose = false, dryRun = false, quarantine = false, } = options;
41
+ // Validate and sanitize inputs to prevent script injection
42
+ const safeWebhookUrl = webhookUrl ? validateMdmUrl(webhookUrl) : undefined;
43
+ const safeWebhookToken = webhookToken ? escapePowerShellString(webhookToken) : undefined;
44
+ // Validate gateway port
45
+ if (gatewayPort < 1 || gatewayPort > 65535 || !Number.isInteger(gatewayPort)) {
46
+ throw new Error(`Invalid gateway port: ${gatewayPort}`);
47
+ }
48
+ const webhookSection = safeWebhookUrl
49
+ ? `
50
+ # Webhook configuration
51
+ $WebhookUrl = "${safeWebhookUrl}"
52
+ $WebhookToken = "${safeWebhookToken || ''}"
53
+
54
+ function Send-Webhook {
55
+ param(
56
+ [string]$Status,
57
+ [string]$Severity,
58
+ [string]$Details
59
+ )
60
+
61
+ $payload = @{
62
+ event = "openclaw.enforcement"
63
+ version = "1.0"
64
+ timestamp = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
65
+ status = $Status
66
+ severity = $Severity
67
+ host = @{
68
+ hostname = $env:COMPUTERNAME
69
+ os = "Windows"
70
+ osVersion = [System.Environment]::OSVersion.VersionString
71
+ arch = $env:PROCESSOR_ARCHITECTURE
72
+ user = $env:USERNAME
73
+ domain = $env:USERDOMAIN
74
+ }
75
+ actions = $Details
76
+ dryRun = $${dryRun ? 'true' : 'false'}
77
+ source = @{
78
+ tool = "nox-openclaw-detector"
79
+ version = "${VERSION}"
80
+ vendor = "${COMPANY}"
81
+ }
82
+ } | ConvertTo-Json -Depth 10
83
+
84
+ try {
85
+ $headers = @{
86
+ "Content-Type" = "application/json"
87
+ }
88
+ if ($WebhookToken) {
89
+ $headers["Authorization"] = "Bearer $WebhookToken"
90
+ }
91
+
92
+ Invoke-RestMethod -Uri $WebhookUrl -Method Post -Headers $headers -Body $payload -TimeoutSec 30 -ErrorAction SilentlyContinue | Out-Null
93
+ } catch {
94
+ # Silently ignore webhook errors
95
+ }
96
+ }
97
+ `
98
+ : '';
99
+ const verboseLog = verbose
100
+ ? `
101
+ function Write-VerboseLog {
102
+ param([string]$Message)
103
+ Write-Host "[DEBUG] $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') $Message" -ForegroundColor Gray
104
+ }
105
+ `
106
+ : `
107
+ function Write-VerboseLog {
108
+ param([string]$Message)
109
+ # No-op when not verbose
110
+ }
111
+ `;
112
+ const quarantineSection = quarantine
113
+ ? `
114
+ # Quarantine configuration
115
+ $QuarantineBase = "C:\\ProgramData\\NoxQuarantine"
116
+ $QuarantineId = "$(Get-Date -Format 'yyyyMMdd_HHmmss')_$env:USERNAME"
117
+ $QuarantineDir = Join-Path $QuarantineBase $QuarantineId
118
+
119
+ function Initialize-Quarantine {
120
+ if ($DryRun) {
121
+ Log-Action "[DRY RUN] Would create quarantine directory: $QuarantineDir"
122
+ return
123
+ }
124
+
125
+ New-Item -ItemType Directory -Path "$QuarantineDir\\binaries" -Force | Out-Null
126
+ New-Item -ItemType Directory -Path "$QuarantineDir\\config" -Force | Out-Null
127
+ New-Item -ItemType Directory -Path "$QuarantineDir\\services" -Force | Out-Null
128
+ New-Item -ItemType Directory -Path "$QuarantineDir\\registry" -Force | Out-Null
129
+
130
+ # Create manifest
131
+ $manifest = @{
132
+ id = $QuarantineId
133
+ timestamp = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
134
+ hostname = $env:COMPUTERNAME
135
+ user = $env:USERNAME
136
+ artifacts = @()
137
+ } | ConvertTo-Json
138
+
139
+ $manifest | Out-File (Join-Path $QuarantineDir "manifest.json") -Encoding UTF8
140
+
141
+ Log-Action "Quarantine directory created: $QuarantineDir"
142
+ }
143
+
144
+ function Move-ToQuarantine {
145
+ param(
146
+ [string]$Source,
147
+ [string]$Category
148
+ )
149
+
150
+ $destDir = Join-Path $QuarantineDir $Category
151
+ $destPath = Join-Path $destDir (Split-Path $Source -Leaf)
152
+
153
+ if ($DryRun) {
154
+ Log-Action "[DRY RUN] Would quarantine: $Source -> $destPath"
155
+ return
156
+ }
157
+
158
+ if (Test-Path $Source) {
159
+ try {
160
+ Move-Item -Path $Source -Destination $destPath -Force -ErrorAction Stop
161
+ Log-Action "Quarantined: $Source -> $destPath"
162
+ } catch {
163
+ # If move fails, try copy and delete
164
+ Copy-Item -Path $Source -Destination $destPath -Recurse -Force -ErrorAction SilentlyContinue
165
+ Remove-Item -Path $Source -Recurse -Force -ErrorAction SilentlyContinue
166
+ Log-Action "Quarantined (via copy): $Source -> $destPath"
167
+ }
168
+ }
169
+ }
170
+ `
171
+ : `
172
+ function Move-ToQuarantine {
173
+ param(
174
+ [string]$Source,
175
+ [string]$Category
176
+ )
177
+ # No quarantine, just remove
178
+ Remove-PathSafely -Path $Source
179
+ }
180
+ `;
181
+ // Build webhook notification section for main function
182
+ const webhookNotificationSection = safeWebhookUrl
183
+ ? `
184
+ if ($OpenClawDetected) {
185
+ if ($FailedActions.Count -eq 0) {
186
+ Send-Webhook -Status "success" -Severity "high" -Details $actionsString
187
+ } else {
188
+ Send-Webhook -Status "partial" -Severity "high" -Details $actionsString
189
+ }
190
+ } else {
191
+ Send-Webhook -Status "clean" -Severity "info" -Details "No OpenClaw installation found"
192
+ }
193
+ `
194
+ : '';
195
+ const dryRunMessage = dryRun
196
+ ? ' Write-Host "[DRY RUN MODE - No changes will be made]" -ForegroundColor Yellow'
197
+ : '';
198
+ const initQuarantine = quarantine ? ' Initialize-Quarantine' : '';
199
+ const quarantineLocation = quarantine
200
+ ? ' Write-Host "Quarantine location: $QuarantineDir"'
201
+ : '';
202
+ const quarantineOrRemove = quarantine
203
+ ? 'Move-ToQuarantine -Source $installPath -Category "binaries"'
204
+ : 'Remove-PathSafely -Path $installPath';
205
+ const quarantineOrRemoveConfig = quarantine
206
+ ? 'Move-ToQuarantine -Source $configPath -Category "config"'
207
+ : 'Remove-PathSafely -Path $configPath';
208
+ const quarantineOrRemoveOther = quarantine
209
+ ? 'Move-ToQuarantine -Source $otherConfig -Category "config"'
210
+ : 'Remove-PathSafely -Path $otherConfig';
211
+ const blockPortSection = quarantine
212
+ ? `
213
+ # Block gateway port via Windows Firewall
214
+ function Block-GatewayPort {
215
+ Log-Action "Blocking gateway port $GatewayPort..."
216
+
217
+ if ($DryRun) {
218
+ Log-Action "[DRY RUN] Would create firewall rule to block port $GatewayPort"
219
+ return
220
+ }
221
+
222
+ try {
223
+ # Remove existing rule if present
224
+ Remove-NetFirewallRule -DisplayName "Nox Block OpenClaw" -ErrorAction SilentlyContinue
225
+
226
+ # Create new blocking rule
227
+ New-NetFirewallRule -DisplayName "Nox Block OpenClaw" -Direction Outbound -Action Block -Protocol TCP -RemotePort $GatewayPort -ErrorAction Stop | Out-Null
228
+
229
+ Log-Action "Created firewall rule to block port $GatewayPort"
230
+ } catch {
231
+ Log-Failure "Could not create firewall rule: $_"
232
+ }
233
+ }
234
+ `
235
+ : `
236
+ # Block gateway port (disabled - quarantine mode not enabled)
237
+ function Block-GatewayPort {
238
+ # Port blocking only enabled in quarantine mode
239
+ }
240
+ `;
241
+ return `<#
242
+ .SYNOPSIS
243
+ Nox OpenClaw Enforcement Script for Windows
244
+
245
+ .DESCRIPTION
246
+ This script removes OpenClaw AI agent installations from Windows systems.
247
+ Generated by nox-openclaw-detector v${VERSION}
248
+ ${COMPANY} - https://nox.security
249
+
250
+ WARNING: This script will remove OpenClaw installations!
251
+ Run as Administrator for full enforcement capabilities.
252
+
253
+ .OUTPUTS
254
+ Exit Code 0 - Enforcement successful
255
+ Exit Code 1 - Enforcement partially failed
256
+ Exit Code 2 - Script error
257
+ Exit Code 3 - Nothing to enforce (clean system)
258
+
259
+ .EXAMPLE
260
+ .\\enforce-openclaw.ps1
261
+
262
+ .NOTES
263
+ Version: ${VERSION}
264
+ Author: ${COMPANY}
265
+ #>
266
+
267
+ #Requires -Version 5.1
268
+ #Requires -RunAsAdministrator
269
+
270
+ [CmdletBinding()]
271
+ param()
272
+
273
+ $ErrorActionPreference = "SilentlyContinue"
274
+
275
+ # Configuration
276
+ $GatewayPort = ${gatewayPort}
277
+ $DryRun = $${dryRun ? 'true' : 'false'}
278
+ $OpenClawDetected = $false
279
+ $EnforcementActions = [System.Collections.ArrayList]::new()
280
+ $FailedActions = [System.Collections.ArrayList]::new()
281
+ ${verboseLog}
282
+ ${webhookSection}
283
+ ${quarantineSection}
284
+
285
+ # Log enforcement action
286
+ function Log-Action {
287
+ param([string]$Message)
288
+ $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
289
+ Write-Host "[$timestamp] $Message"
290
+ [void]$script:EnforcementActions.Add($Message)
291
+ }
292
+
293
+ # Log failed action
294
+ function Log-Failure {
295
+ param([string]$Message)
296
+ $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
297
+ Write-Host "[$timestamp] FAILED: $Message" -ForegroundColor Red
298
+ [void]$script:FailedActions.Add($Message)
299
+ }
300
+
301
+ # Remove file or directory safely
302
+ function Remove-PathSafely {
303
+ param([string]$Path)
304
+
305
+ if (-not (Test-Path $Path)) {
306
+ return $true
307
+ }
308
+
309
+ $script:OpenClawDetected = $true
310
+
311
+ if ($DryRun) {
312
+ Log-Action "[DRY RUN] Would remove: $Path"
313
+ return $true
314
+ }
315
+
316
+ try {
317
+ Remove-Item -Path $Path -Recurse -Force -ErrorAction Stop
318
+ Log-Action "Removed: $Path"
319
+ return $true
320
+ } catch {
321
+ Log-Failure "Could not remove: $Path - $_"
322
+ return $false
323
+ }
324
+ }
325
+
326
+ # Check if running as Administrator
327
+ function Test-Administrator {
328
+ $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
329
+ if (-not $isAdmin) {
330
+ Write-Host "Warning: Not running as Administrator. Some enforcement actions may fail." -ForegroundColor Yellow
331
+ Write-Host "For complete enforcement, run PowerShell as Administrator." -ForegroundColor Yellow
332
+ Write-Host ""
333
+ }
334
+ return $isAdmin
335
+ }
336
+
337
+ # Kill OpenClaw processes
338
+ function Stop-OpenClawProcesses {
339
+ Log-Action "Checking for OpenClaw processes..."
340
+
341
+ $processes = Get-Process -Name "*openclaw*" -ErrorAction SilentlyContinue
342
+
343
+ # Also check by command line
344
+ $wmiProcesses = Get-CimInstance Win32_Process |
345
+ Where-Object { $_.CommandLine -like "*openclaw*" -or $_.ExecutablePath -like "*openclaw*" }
346
+
347
+ $allPids = @()
348
+ if ($processes) { $allPids += $processes.Id }
349
+ if ($wmiProcesses) { $allPids += $wmiProcesses.ProcessId }
350
+ $allPids = $allPids | Select-Object -Unique
351
+
352
+ if ($allPids.Count -gt 0) {
353
+ $script:OpenClawDetected = $true
354
+
355
+ if ($DryRun) {
356
+ Log-Action "[DRY RUN] Would kill processes: $($allPids -join ', ')"
357
+ return
358
+ }
359
+
360
+ foreach ($pid in $allPids) {
361
+ try {
362
+ Stop-Process -Id $pid -Force -ErrorAction Stop
363
+ Log-Action "Killed process: $pid"
364
+ } catch {
365
+ Log-Failure "Could not kill process: $pid"
366
+ }
367
+ }
368
+ } else {
369
+ Write-VerboseLog "No OpenClaw processes found"
370
+ }
371
+ }
372
+
373
+ # Stop and remove Windows services
374
+ function Remove-OpenClawServices {
375
+ Log-Action "Checking for Windows services..."
376
+
377
+ $serviceNames = @(
378
+ "openclaw",
379
+ "OpenClawGateway",
380
+ "bot.molt.gateway"
381
+ )
382
+
383
+ # Find by name patterns
384
+ $services = Get-Service -ErrorAction SilentlyContinue |
385
+ Where-Object { $_.DisplayName -like "*openclaw*" -or $_.Name -like "*openclaw*" -or $serviceNames -contains $_.Name }
386
+
387
+ foreach ($service in $services) {
388
+ $script:OpenClawDetected = $true
389
+
390
+ if ($DryRun) {
391
+ Log-Action "[DRY RUN] Would stop and remove service: $($service.Name)"
392
+ continue
393
+ }
394
+
395
+ try {
396
+ # Stop the service
397
+ if ($service.Status -ne 'Stopped') {
398
+ Stop-Service -Name $service.Name -Force -ErrorAction Stop
399
+ Log-Action "Stopped service: $($service.Name)"
400
+ }
401
+
402
+ # Delete the service
403
+ $result = sc.exe delete $service.Name 2>&1
404
+ if ($LASTEXITCODE -eq 0) {
405
+ Log-Action "Removed service: $($service.Name)"
406
+ } else {
407
+ Log-Failure "Could not remove service: $($service.Name)"
408
+ }
409
+ } catch {
410
+ Log-Failure "Error handling service $($service.Name): $_"
411
+ }
412
+ }
413
+ }
414
+
415
+ # Remove CLI binaries and installation directories
416
+ function Remove-OpenClawBinaries {
417
+ Log-Action "Checking for CLI binaries..."
418
+
419
+ $installPaths = @(
420
+ "$env:LOCALAPPDATA\\Programs\\openclaw",
421
+ "$env:ProgramFiles\\OpenClaw",
422
+ "\${env:ProgramFiles(x86)}\\OpenClaw",
423
+ "$env:USERPROFILE\\AppData\\Local\\Programs\\openclaw",
424
+ "$env:USERPROFILE\\.local\\bin\\openclaw.exe"
425
+ )
426
+
427
+ foreach ($installPath in $installPaths) {
428
+ if (Test-Path $installPath) {
429
+ $script:OpenClawDetected = $true
430
+ ${quarantineOrRemove}
431
+ }
432
+ }
433
+ }
434
+
435
+ # Remove configuration directories
436
+ function Remove-OpenClawConfig {
437
+ Log-Action "Checking for configuration directories..."
438
+
439
+ $configPaths = @(
440
+ "$env:USERPROFILE\\.openclaw",
441
+ "$env:APPDATA\\OpenClaw",
442
+ "$env:LOCALAPPDATA\\OpenClaw"
443
+ )
444
+
445
+ foreach ($configPath in $configPaths) {
446
+ if (Test-Path $configPath) {
447
+ $script:OpenClawDetected = $true
448
+ ${quarantineOrRemoveConfig}
449
+ }
450
+ }
451
+
452
+ # Check other user profiles (requires admin)
453
+ if (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
454
+ $userProfiles = Get-ChildItem "C:\\Users" -Directory -ErrorAction SilentlyContinue |
455
+ Where-Object { $_.Name -notin @("Public", "Default", "Default User", "All Users") }
456
+
457
+ foreach ($profile in $userProfiles) {
458
+ $otherConfigPaths = @(
459
+ (Join-Path $profile.FullName ".openclaw"),
460
+ (Join-Path $profile.FullName "AppData\\Roaming\\OpenClaw"),
461
+ (Join-Path $profile.FullName "AppData\\Local\\OpenClaw")
462
+ )
463
+
464
+ foreach ($otherConfig in $otherConfigPaths) {
465
+ if ((Test-Path $otherConfig) -and ($otherConfig -ne "$env:USERPROFILE\\.openclaw")) {
466
+ $script:OpenClawDetected = $true
467
+ ${quarantineOrRemoveOther}
468
+ }
469
+ }
470
+ }
471
+ }
472
+ }
473
+
474
+ # Remove scheduled tasks
475
+ function Remove-OpenClawScheduledTasks {
476
+ Log-Action "Checking for scheduled tasks..."
477
+
478
+ try {
479
+ $tasks = Get-ScheduledTask -ErrorAction SilentlyContinue |
480
+ Where-Object { $_.TaskName -like "*openclaw*" -or $_.TaskPath -like "*openclaw*" }
481
+
482
+ foreach ($task in $tasks) {
483
+ $script:OpenClawDetected = $true
484
+
485
+ if ($DryRun) {
486
+ Log-Action "[DRY RUN] Would remove scheduled task: $($task.TaskName)"
487
+ continue
488
+ }
489
+
490
+ try {
491
+ Unregister-ScheduledTask -TaskName $task.TaskName -Confirm:$false -ErrorAction Stop
492
+ Log-Action "Removed scheduled task: $($task.TaskName)"
493
+ } catch {
494
+ Log-Failure "Could not remove scheduled task: $($task.TaskName)"
495
+ }
496
+ }
497
+ } catch {
498
+ Write-VerboseLog "Error checking scheduled tasks: $_"
499
+ }
500
+ }
501
+
502
+ # Remove registry entries
503
+ function Remove-OpenClawRegistry {
504
+ Log-Action "Checking for registry entries..."
505
+
506
+ $registryPaths = @(
507
+ "HKLM:\\SOFTWARE\\OpenClaw",
508
+ "HKCU:\\SOFTWARE\\OpenClaw",
509
+ "HKLM:\\SOFTWARE\\WOW6432Node\\OpenClaw"
510
+ )
511
+
512
+ foreach ($regPath in $registryPaths) {
513
+ if (Test-Path $regPath) {
514
+ $script:OpenClawDetected = $true
515
+
516
+ if ($DryRun) {
517
+ Log-Action "[DRY RUN] Would remove registry key: $regPath"
518
+ continue
519
+ }
520
+
521
+ try {
522
+ Remove-Item -Path $regPath -Recurse -Force -ErrorAction Stop
523
+ Log-Action "Removed registry key: $regPath"
524
+ } catch {
525
+ Log-Failure "Could not remove registry key: $regPath"
526
+ }
527
+ }
528
+ }
529
+
530
+ # Remove startup entries
531
+ $runKeys = @(
532
+ "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
533
+ "HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"
534
+ )
535
+
536
+ foreach ($runKey in $runKeys) {
537
+ try {
538
+ $entries = Get-ItemProperty $runKey -ErrorAction SilentlyContinue
539
+ $entries.PSObject.Properties | Where-Object { $_.Value -like "*openclaw*" } | ForEach-Object {
540
+ $script:OpenClawDetected = $true
541
+
542
+ if ($DryRun) {
543
+ Log-Action "[DRY RUN] Would remove startup entry: $($_.Name) from $runKey"
544
+ return
545
+ }
546
+
547
+ try {
548
+ Remove-ItemProperty -Path $runKey -Name $_.Name -Force -ErrorAction Stop
549
+ Log-Action "Removed startup entry: $($_.Name)"
550
+ } catch {
551
+ Log-Failure "Could not remove startup entry: $($_.Name)"
552
+ }
553
+ }
554
+ } catch {}
555
+ }
556
+ }
557
+
558
+ # Clean Docker artifacts
559
+ function Remove-OpenClawDocker {
560
+ $dockerCmd = Get-Command "docker" -ErrorAction SilentlyContinue
561
+ if (-not $dockerCmd) {
562
+ return
563
+ }
564
+
565
+ Log-Action "Checking for Docker artifacts..."
566
+
567
+ try {
568
+ # Stop and remove containers
569
+ $containers = docker ps -a --filter "name=openclaw" --format "{{.ID}}" 2>$null
570
+ if ($containers) {
571
+ $script:OpenClawDetected = $true
572
+
573
+ if ($DryRun) {
574
+ Log-Action "[DRY RUN] Would remove Docker containers: $($containers -join ', ')"
575
+ } else {
576
+ foreach ($container in $containers) {
577
+ docker stop $container 2>$null
578
+ docker rm -f $container 2>$null
579
+ Log-Action "Removed Docker container: $container"
580
+ }
581
+ }
582
+ }
583
+
584
+ # Remove images
585
+ $images = docker images --filter "reference=*openclaw*" --format "{{.ID}}" 2>$null
586
+ if ($images) {
587
+ $script:OpenClawDetected = $true
588
+
589
+ if ($DryRun) {
590
+ Log-Action "[DRY RUN] Would remove Docker images: $($images -join ', ')"
591
+ } else {
592
+ foreach ($image in $images) {
593
+ docker rmi -f $image 2>$null
594
+ Log-Action "Removed Docker image: $image"
595
+ }
596
+ }
597
+ }
598
+ } catch {
599
+ Write-VerboseLog "Error cleaning Docker artifacts: $_"
600
+ }
601
+ }
602
+ ${blockPortSection}
603
+
604
+ # Main enforcement routine
605
+ function Invoke-Enforcement {
606
+ Write-Host "==============================================" -ForegroundColor Cyan
607
+ Write-Host "Nox OpenClaw Enforcement" -ForegroundColor Cyan
608
+ Write-Host "==============================================" -ForegroundColor Cyan
609
+ ${dryRunMessage}
610
+ Write-Host ""
611
+
612
+ Test-Administrator | Out-Null
613
+
614
+ ${initQuarantine}
615
+
616
+ # Execute enforcement actions in order
617
+ Stop-OpenClawProcesses
618
+ Remove-OpenClawServices
619
+ Remove-OpenClawBinaries
620
+ Remove-OpenClawConfig
621
+ Remove-OpenClawScheduledTasks
622
+ Remove-OpenClawRegistry
623
+ Remove-OpenClawDocker
624
+ Block-GatewayPort
625
+
626
+ # Compile results
627
+ $actionsString = if ($EnforcementActions.Count -gt 0) { $EnforcementActions -join "; " } else { "" }
628
+
629
+ Write-Host ""
630
+ Write-Host "==============================================" -ForegroundColor Cyan
631
+ Write-Host "Enforcement Summary" -ForegroundColor Cyan
632
+ Write-Host "==============================================" -ForegroundColor Cyan
633
+
634
+ # Send webhook notification
635
+ ${webhookNotificationSection}
636
+
637
+ if (-not $OpenClawDetected) {
638
+ Write-Host "No OpenClaw installation detected. System is clean." -ForegroundColor Green
639
+ exit 3
640
+ } elseif ($FailedActions.Count -gt 0) {
641
+ Write-Host "Enforcement partially completed with $($FailedActions.Count) failures:" -ForegroundColor Yellow
642
+ foreach ($failure in $FailedActions) {
643
+ Write-Host " - $failure" -ForegroundColor Yellow
644
+ }
645
+ exit 1
646
+ } else {
647
+ Write-Host "Enforcement completed successfully." -ForegroundColor Green
648
+ Write-Host "Actions taken: $($EnforcementActions.Count)"
649
+ ${quarantineLocation}
650
+ exit 0
651
+ }
652
+ }
653
+
654
+ # Run main function
655
+ try {
656
+ Invoke-Enforcement
657
+ } catch {
658
+ Write-Host "Enforcement error: $_" -ForegroundColor Red
659
+ exit 2
660
+ }
661
+ `;
662
+ }
663
+ /**
664
+ * Get script metadata for documentation.
665
+ */
666
+ export function getEnforcePowerShellMetadata() {
667
+ return {
668
+ filename: 'enforce-openclaw.ps1',
669
+ extension: '.ps1',
670
+ platform: 'windows',
671
+ description: 'PowerShell enforcement script for Windows',
672
+ requirements: ['PowerShell 5.1+', 'Administrator privileges', 'Windows 8/Server 2012 or later'],
673
+ exitCodes: {
674
+ 0: 'Enforcement successful',
675
+ 1: 'Enforcement partially failed',
676
+ 2: 'Script error',
677
+ 3: 'Nothing to enforce (clean system)',
678
+ },
679
+ };
680
+ }
681
+ //# sourceMappingURL=enforce.ps1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforce.ps1.js","sourceRoot":"","sources":["../../../src/mdm/templates/enforce.ps1.ts"],"names":[],"mappings":"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"}