nox-openclaw-hunter 1.0.0 → 1.0.2
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/LICENSE +1 -1
- package/README.md +5 -12
- package/dist/banner.d.ts +6 -0
- package/dist/banner.d.ts.map +1 -0
- package/dist/banner.js +31 -0
- package/dist/banner.js.map +1 -0
- package/dist/branding.d.ts +4 -4
- package/dist/branding.d.ts.map +1 -1
- package/dist/branding.js +26 -10
- package/dist/branding.js.map +1 -1
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +979 -104
- package/dist/commands/export.js.map +1 -1
- package/dist/detector/cli-binary.d.ts +7 -3
- package/dist/detector/cli-binary.d.ts.map +1 -1
- package/dist/detector/cli-binary.js +31 -22
- package/dist/detector/cli-binary.js.map +1 -1
- package/dist/detector/config.d.ts.map +1 -1
- package/dist/detector/config.js +88 -3
- package/dist/detector/config.js.map +1 -1
- package/dist/detector/detection-config.d.ts.map +1 -1
- package/dist/detector/detection-config.js +3 -0
- package/dist/detector/detection-config.js.map +1 -1
- package/dist/detector/docker.js +1 -1
- package/dist/detector/docker.js.map +1 -1
- package/dist/detector/process.d.ts.map +1 -1
- package/dist/detector/process.js +12 -1
- package/dist/detector/process.js.map +1 -1
- package/dist/enforcer/file-remover.d.ts +9 -0
- package/dist/enforcer/file-remover.d.ts.map +1 -1
- package/dist/enforcer/file-remover.js +76 -0
- package/dist/enforcer/file-remover.js.map +1 -1
- package/dist/enforcer/index.d.ts.map +1 -1
- package/dist/enforcer/index.js +19 -8
- package/dist/enforcer/index.js.map +1 -1
- package/dist/enforcer/service-stopper.d.ts +1 -0
- package/dist/enforcer/service-stopper.d.ts.map +1 -1
- package/dist/enforcer/service-stopper.js +7 -6
- package/dist/enforcer/service-stopper.js.map +1 -1
- package/dist/isolator/lockdown.d.ts.map +1 -1
- package/dist/isolator/lockdown.js +11 -0
- package/dist/isolator/lockdown.js.map +1 -1
- package/dist/mdm/templates/detect.ps1.d.ts.map +1 -1
- package/dist/mdm/templates/detect.ps1.js +69 -38
- package/dist/mdm/templates/detect.ps1.js.map +1 -1
- package/dist/mdm/templates/detect.sh.d.ts.map +1 -1
- package/dist/mdm/templates/detect.sh.js +5 -1
- package/dist/mdm/templates/detect.sh.js.map +1 -1
- package/dist/mdm/templates/enforce.ps1.d.ts.map +1 -1
- package/dist/mdm/templates/enforce.ps1.js +38 -25
- package/dist/mdm/templates/enforce.ps1.js.map +1 -1
- package/dist/mdm/templates/enforce.sh.d.ts.map +1 -1
- package/dist/mdm/templates/enforce.sh.js +5 -1
- package/dist/mdm/templates/enforce.sh.js.map +1 -1
- package/dist/platform/darwin.d.ts.map +1 -1
- package/dist/platform/darwin.js +132 -27
- package/dist/platform/darwin.js.map +1 -1
- package/dist/platform/linux.d.ts.map +1 -1
- package/dist/platform/linux.js +9 -1
- package/dist/platform/linux.js.map +1 -1
- package/dist/platform/windows.d.ts.map +1 -1
- package/dist/platform/windows.js +8 -5
- package/dist/platform/windows.js.map +1 -1
- package/package.json +5 -5
package/dist/commands/export.js
CHANGED
|
@@ -47,61 +47,353 @@ send_webhook() {
|
|
|
47
47
|
# Generated by nox-openclaw-detector
|
|
48
48
|
# https://nox.security
|
|
49
49
|
|
|
50
|
-
set -
|
|
50
|
+
set -eo pipefail
|
|
51
|
+
|
|
52
|
+
# Set defaults for environment variables that may be unset when running as root
|
|
53
|
+
HOME="\${HOME:-/root}"
|
|
54
|
+
USER="\${USER:-root}"
|
|
51
55
|
|
|
52
56
|
OPENCLAW_FOUND=0
|
|
53
57
|
DETAILS=""
|
|
54
58
|
${webhookSection}
|
|
59
|
+
|
|
60
|
+
# Logging function
|
|
61
|
+
log() {
|
|
62
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Get all user home directories
|
|
66
|
+
get_all_user_homes() {
|
|
67
|
+
local homes=()
|
|
68
|
+
|
|
69
|
+
# macOS users
|
|
70
|
+
if [[ -d "/Users" ]]; then
|
|
71
|
+
for user_dir in /Users/*; do
|
|
72
|
+
if [[ -d "$user_dir" && "$user_dir" != "/Users/Shared" && "$user_dir" != "/Users/Guest" ]]; then
|
|
73
|
+
homes+=("$user_dir")
|
|
74
|
+
fi
|
|
75
|
+
done
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Linux users
|
|
79
|
+
if [[ -d "/home" ]]; then
|
|
80
|
+
for user_dir in /home/*; do
|
|
81
|
+
if [[ -d "$user_dir" ]]; then
|
|
82
|
+
homes+=("$user_dir")
|
|
83
|
+
fi
|
|
84
|
+
done
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Root home
|
|
88
|
+
if [[ -d "/root" ]]; then
|
|
89
|
+
homes+=("/root")
|
|
90
|
+
fi
|
|
91
|
+
if [[ -d "/var/root" ]]; then
|
|
92
|
+
homes+=("/var/root")
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
echo "\${homes[@]}"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
log "=========================================="
|
|
99
|
+
log "Nox OpenClaw Hunter - Detection Scan"
|
|
100
|
+
log "=========================================="
|
|
101
|
+
log "Hostname: $(hostname)"
|
|
102
|
+
log "Platform: $(uname -s) $(uname -m)"
|
|
103
|
+
log "User: $USER"
|
|
104
|
+
log "Date: $(date)"
|
|
105
|
+
log "=========================================="
|
|
106
|
+
log ""
|
|
107
|
+
|
|
55
108
|
# Check if nox CLI is installed
|
|
109
|
+
log "Checking for nox CLI..."
|
|
56
110
|
if command -v nox &>/dev/null; then
|
|
111
|
+
log " [INFO] nox CLI found, using for detection"
|
|
57
112
|
if nox scan --quiet --json > /tmp/nox_scan_result.json 2>/dev/null; then
|
|
58
113
|
SUMMARY=$(cat /tmp/nox_scan_result.json | grep -o '"summary":"[^"]*"' | cut -d'"' -f4 || echo "")
|
|
59
114
|
if [[ "$SUMMARY" != "not-installed" ]]; then
|
|
60
115
|
OPENCLAW_FOUND=1
|
|
61
116
|
DETAILS="Detected via nox CLI: $SUMMARY"
|
|
117
|
+
log " [DETECTED] $DETAILS"
|
|
118
|
+
else
|
|
119
|
+
log " [CLEAN] No OpenClaw detected via nox CLI"
|
|
62
120
|
fi
|
|
63
121
|
rm -f /tmp/nox_scan_result.json
|
|
64
122
|
fi
|
|
65
123
|
${webhookUrl ? 'send_webhook "$([[ $OPENCLAW_FOUND -eq 1 ]] && echo "detected" || echo "clean")" "$DETAILS"' : ''}
|
|
124
|
+
|
|
125
|
+
log ""
|
|
126
|
+
log "=========================================="
|
|
127
|
+
if [[ $OPENCLAW_FOUND -eq 1 ]]; then
|
|
128
|
+
log "RESULT: OpenClaw DETECTED"
|
|
129
|
+
else
|
|
130
|
+
log "RESULT: System CLEAN"
|
|
131
|
+
fi
|
|
132
|
+
log "=========================================="
|
|
66
133
|
exit $OPENCLAW_FOUND
|
|
67
134
|
fi
|
|
68
135
|
|
|
136
|
+
log " [INFO] nox CLI not found, using fallback detection"
|
|
137
|
+
log ""
|
|
138
|
+
|
|
69
139
|
# Fallback: direct detection
|
|
140
|
+
# Scanning for: openclaw, clawbot, clawdbot, moltbot
|
|
70
141
|
|
|
71
|
-
# Check CLI
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
142
|
+
# Check CLI binaries (system-wide and per-user)
|
|
143
|
+
log "Checking for CLI binaries (all locations)..."
|
|
144
|
+
CLI_FOUND=0
|
|
145
|
+
|
|
146
|
+
# System-wide locations
|
|
147
|
+
for cli_name in openclaw clawbot clawdbot moltbot; do
|
|
148
|
+
for bin_dir in /usr/local/bin /opt/homebrew/bin /usr/bin; do
|
|
149
|
+
cli_path="$bin_dir/$cli_name"
|
|
150
|
+
if [[ -f "$cli_path" ]]; then
|
|
151
|
+
OPENCLAW_FOUND=1
|
|
152
|
+
CLI_FOUND=1
|
|
153
|
+
DETAILS="$DETAILS; CLI found at $cli_path"
|
|
154
|
+
log " [DETECTED] CLI binary found at $cli_path"
|
|
155
|
+
fi
|
|
156
|
+
done
|
|
78
157
|
done
|
|
79
158
|
|
|
80
|
-
#
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
159
|
+
# Per-user locations
|
|
160
|
+
for user_home in $(get_all_user_homes); do
|
|
161
|
+
for cli_name in openclaw clawbot clawdbot moltbot; do
|
|
162
|
+
for bin_dir in "$user_home/bin" "$user_home/.local/bin"; do
|
|
163
|
+
cli_path="$bin_dir/$cli_name"
|
|
164
|
+
if [[ -f "$cli_path" ]]; then
|
|
165
|
+
OPENCLAW_FOUND=1
|
|
166
|
+
CLI_FOUND=1
|
|
167
|
+
DETAILS="$DETAILS; CLI found at $cli_path"
|
|
168
|
+
log " [DETECTED] CLI binary found at $cli_path"
|
|
169
|
+
fi
|
|
170
|
+
done
|
|
171
|
+
done
|
|
172
|
+
done
|
|
173
|
+
|
|
174
|
+
if [[ $CLI_FOUND -eq 0 ]]; then
|
|
175
|
+
log " [CLEAN] No CLI binaries found"
|
|
84
176
|
fi
|
|
85
177
|
|
|
86
|
-
# Check
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
178
|
+
# Check config directories for ALL users
|
|
179
|
+
log ""
|
|
180
|
+
log "Checking for config directories (all users)..."
|
|
181
|
+
CONFIG_FOUND=0
|
|
182
|
+
for user_home in $(get_all_user_homes); do
|
|
183
|
+
for config_name in .openclaw .clawbot .clawdbot .moltbot; do
|
|
184
|
+
config_path="$user_home/$config_name"
|
|
185
|
+
if [[ -d "$config_path" ]]; then
|
|
186
|
+
OPENCLAW_FOUND=1
|
|
187
|
+
CONFIG_FOUND=1
|
|
188
|
+
DETAILS="$DETAILS; Config directory found at $config_path"
|
|
189
|
+
log " [DETECTED] Config directory found at $config_path"
|
|
190
|
+
fi
|
|
191
|
+
done
|
|
192
|
+
done
|
|
193
|
+
if [[ $CONFIG_FOUND -eq 0 ]]; then
|
|
194
|
+
log " [CLEAN] No config directories found"
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
# Check macOS app bundles (system-wide and per-user)
|
|
198
|
+
log ""
|
|
199
|
+
log "Checking for macOS app bundles (all locations)..."
|
|
200
|
+
APP_FOUND=0
|
|
201
|
+
for app_name in OpenClaw.app ClawBot.app ClawdBot.app MoltBot.app; do
|
|
202
|
+
# System-wide Applications
|
|
203
|
+
app_path="/Applications/$app_name"
|
|
204
|
+
if [[ -d "$app_path" ]]; then
|
|
205
|
+
OPENCLAW_FOUND=1
|
|
206
|
+
APP_FOUND=1
|
|
207
|
+
DETAILS="$DETAILS; App bundle found at $app_path"
|
|
208
|
+
log " [DETECTED] App bundle found at $app_path"
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
# Per-user Applications folders
|
|
212
|
+
for user_home in $(get_all_user_homes); do
|
|
213
|
+
app_path="$user_home/Applications/$app_name"
|
|
214
|
+
if [[ -d "$app_path" ]]; then
|
|
215
|
+
OPENCLAW_FOUND=1
|
|
216
|
+
APP_FOUND=1
|
|
217
|
+
DETAILS="$DETAILS; App bundle found at $app_path"
|
|
218
|
+
log " [DETECTED] App bundle found at $app_path"
|
|
219
|
+
fi
|
|
220
|
+
done
|
|
221
|
+
done
|
|
222
|
+
if [[ $APP_FOUND -eq 0 ]]; then
|
|
223
|
+
log " [CLEAN] No app bundles found"
|
|
90
224
|
fi
|
|
91
225
|
|
|
92
226
|
# Check gateway port
|
|
227
|
+
log ""
|
|
228
|
+
log "Checking for gateway port 18789..."
|
|
93
229
|
if command -v nc &>/dev/null && nc -z localhost 18789 2>/dev/null; then
|
|
94
230
|
OPENCLAW_FOUND=1
|
|
95
231
|
DETAILS="$DETAILS; Gateway port 18789 listening"
|
|
232
|
+
log " [DETECTED] Gateway port 18789 is listening"
|
|
233
|
+
elif command -v lsof &>/dev/null && lsof -i :18789 -sTCP:LISTEN &>/dev/null; then
|
|
234
|
+
OPENCLAW_FOUND=1
|
|
235
|
+
DETAILS="$DETAILS; Gateway port 18789 listening"
|
|
236
|
+
log " [DETECTED] Gateway port 18789 is listening"
|
|
237
|
+
else
|
|
238
|
+
log " [CLEAN] Gateway port 18789 not listening"
|
|
96
239
|
fi
|
|
97
240
|
|
|
98
241
|
# Check running processes
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
242
|
+
log ""
|
|
243
|
+
log "Checking for running processes (openclaw, clawbot, clawdbot, moltbot)..."
|
|
244
|
+
PROC_FOUND=0
|
|
245
|
+
for proc_name in openclaw clawbot clawdbot moltbot; do
|
|
246
|
+
if pgrep -x "$proc_name" > /dev/null 2>&1; then
|
|
247
|
+
OPENCLAW_FOUND=1
|
|
248
|
+
PROC_FOUND=1
|
|
249
|
+
PIDS=$(pgrep -x "$proc_name" | tr '\\n' ' ')
|
|
250
|
+
DETAILS="$DETAILS; Process $proc_name running (PIDs: $PIDS)"
|
|
251
|
+
log " [DETECTED] $proc_name process running (PIDs: $PIDS)"
|
|
252
|
+
elif pgrep -f "$proc_name" > /dev/null 2>&1; then
|
|
253
|
+
OPENCLAW_FOUND=1
|
|
254
|
+
PROC_FOUND=1
|
|
255
|
+
PIDS=$(pgrep -f "$proc_name" | tr '\\n' ' ')
|
|
256
|
+
DETAILS="$DETAILS; Process $proc_name running (PIDs: $PIDS)"
|
|
257
|
+
log " [DETECTED] $proc_name-related process running (PIDs: $PIDS)"
|
|
258
|
+
fi
|
|
259
|
+
done
|
|
260
|
+
if [[ $PROC_FOUND -eq 0 ]]; then
|
|
261
|
+
log " [CLEAN] No matching processes running"
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
# Check launchd services (macOS) - all users
|
|
265
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
266
|
+
log ""
|
|
267
|
+
log "Checking for launchd services (all users)..."
|
|
268
|
+
LAUNCHD_FOUND=0
|
|
269
|
+
|
|
270
|
+
# System-wide LaunchAgents and LaunchDaemons
|
|
271
|
+
for plist_dir in /Library/LaunchAgents /Library/LaunchDaemons; do
|
|
272
|
+
if [[ -d "$plist_dir" ]]; then
|
|
273
|
+
for pattern in "bot.molt.*" "*openclaw*" "*clawbot*" "*clawdbot*" "*moltbot*"; do
|
|
274
|
+
for plist in "$plist_dir"/$pattern; do
|
|
275
|
+
if [[ -f "$plist" ]]; then
|
|
276
|
+
OPENCLAW_FOUND=1
|
|
277
|
+
LAUNCHD_FOUND=1
|
|
278
|
+
DETAILS="$DETAILS; LaunchAgent found: $plist"
|
|
279
|
+
log " [DETECTED] LaunchAgent/Daemon found: $plist"
|
|
280
|
+
fi
|
|
281
|
+
done
|
|
282
|
+
done
|
|
283
|
+
fi
|
|
284
|
+
done
|
|
285
|
+
|
|
286
|
+
# Per-user LaunchAgents
|
|
287
|
+
for user_home in $(get_all_user_homes); do
|
|
288
|
+
plist_dir="$user_home/Library/LaunchAgents"
|
|
289
|
+
if [[ -d "$plist_dir" ]]; then
|
|
290
|
+
for pattern in "bot.molt.*" "*openclaw*" "*clawbot*" "*clawdbot*" "*moltbot*"; do
|
|
291
|
+
for plist in "$plist_dir"/$pattern; do
|
|
292
|
+
if [[ -f "$plist" ]]; then
|
|
293
|
+
OPENCLAW_FOUND=1
|
|
294
|
+
LAUNCHD_FOUND=1
|
|
295
|
+
DETAILS="$DETAILS; LaunchAgent found: $plist"
|
|
296
|
+
log " [DETECTED] LaunchAgent/Daemon found: $plist"
|
|
297
|
+
fi
|
|
298
|
+
done
|
|
299
|
+
done
|
|
300
|
+
fi
|
|
301
|
+
done
|
|
302
|
+
|
|
303
|
+
if [[ $LAUNCHD_FOUND -eq 0 ]]; then
|
|
304
|
+
log " [CLEAN] No launchd services found"
|
|
305
|
+
fi
|
|
306
|
+
fi
|
|
307
|
+
|
|
308
|
+
# Check systemd services (Linux) - system and user level
|
|
309
|
+
if command -v systemctl &>/dev/null; then
|
|
310
|
+
log ""
|
|
311
|
+
log "Checking for systemd services (system and user level)..."
|
|
312
|
+
SYSTEMD_FOUND=0
|
|
313
|
+
|
|
314
|
+
# System-level services
|
|
315
|
+
for svc_name in openclaw clawbot clawdbot moltbot; do
|
|
316
|
+
if systemctl list-unit-files "$svc_name.service" &>/dev/null 2>&1; then
|
|
317
|
+
OPENCLAW_FOUND=1
|
|
318
|
+
SYSTEMD_FOUND=1
|
|
319
|
+
STATUS=$(systemctl is-active "$svc_name.service" 2>/dev/null || echo "inactive")
|
|
320
|
+
DETAILS="$DETAILS; Systemd service $svc_name found (status: $STATUS)"
|
|
321
|
+
log " [DETECTED] Systemd service $svc_name found (status: $STATUS)"
|
|
322
|
+
fi
|
|
323
|
+
|
|
324
|
+
# Check service file directly
|
|
325
|
+
for svc_path in /etc/systemd/system /usr/lib/systemd/system; do
|
|
326
|
+
if [[ -f "$svc_path/$svc_name.service" ]]; then
|
|
327
|
+
OPENCLAW_FOUND=1
|
|
328
|
+
SYSTEMD_FOUND=1
|
|
329
|
+
DETAILS="$DETAILS; Systemd service file found: $svc_path/$svc_name.service"
|
|
330
|
+
log " [DETECTED] Systemd service file found: $svc_path/$svc_name.service"
|
|
331
|
+
fi
|
|
332
|
+
done
|
|
333
|
+
done
|
|
334
|
+
|
|
335
|
+
# User-level systemd services
|
|
336
|
+
for user_home in $(get_all_user_homes); do
|
|
337
|
+
user_systemd="$user_home/.config/systemd/user"
|
|
338
|
+
if [[ -d "$user_systemd" ]]; then
|
|
339
|
+
for svc_name in openclaw clawbot clawdbot moltbot; do
|
|
340
|
+
if [[ -f "$user_systemd/$svc_name.service" ]]; then
|
|
341
|
+
OPENCLAW_FOUND=1
|
|
342
|
+
SYSTEMD_FOUND=1
|
|
343
|
+
DETAILS="$DETAILS; User systemd service found: $user_systemd/$svc_name.service"
|
|
344
|
+
log " [DETECTED] User systemd service found: $user_systemd/$svc_name.service"
|
|
345
|
+
fi
|
|
346
|
+
done
|
|
347
|
+
fi
|
|
348
|
+
done
|
|
349
|
+
|
|
350
|
+
if [[ $SYSTEMD_FOUND -eq 0 ]]; then
|
|
351
|
+
log " [CLEAN] No systemd services found"
|
|
352
|
+
fi
|
|
353
|
+
fi
|
|
354
|
+
|
|
355
|
+
# Check Docker
|
|
356
|
+
if command -v docker &>/dev/null; then
|
|
357
|
+
log ""
|
|
358
|
+
log "Checking for Docker artifacts..."
|
|
359
|
+
DOCKER_FOUND=0
|
|
360
|
+
for docker_name in openclaw clawbot clawdbot moltbot; do
|
|
361
|
+
CONTAINERS=$(docker ps -a --filter "name=$docker_name" --format "{{.Names}}" 2>/dev/null || true)
|
|
362
|
+
if [[ -n "$CONTAINERS" ]]; then
|
|
363
|
+
OPENCLAW_FOUND=1
|
|
364
|
+
DOCKER_FOUND=1
|
|
365
|
+
DETAILS="$DETAILS; Docker containers ($docker_name): $CONTAINERS"
|
|
366
|
+
log " [DETECTED] Docker containers found ($docker_name): $CONTAINERS"
|
|
367
|
+
fi
|
|
368
|
+
IMAGES=$(docker images --filter "reference=*$docker_name*" --format "{{.Repository}}:{{.Tag}}" 2>/dev/null || true)
|
|
369
|
+
if [[ -n "$IMAGES" ]]; then
|
|
370
|
+
OPENCLAW_FOUND=1
|
|
371
|
+
DOCKER_FOUND=1
|
|
372
|
+
DETAILS="$DETAILS; Docker images ($docker_name): $IMAGES"
|
|
373
|
+
log " [DETECTED] Docker images found ($docker_name): $IMAGES"
|
|
374
|
+
fi
|
|
375
|
+
done
|
|
376
|
+
if [[ $DOCKER_FOUND -eq 0 ]]; then
|
|
377
|
+
log " [CLEAN] No Docker artifacts found"
|
|
378
|
+
fi
|
|
102
379
|
fi
|
|
103
380
|
${webhookUrl ? '\nsend_webhook "$([[ $OPENCLAW_FOUND -eq 1 ]] && echo "detected" || echo "clean")" "$DETAILS"' : ''}
|
|
104
381
|
|
|
382
|
+
# Final summary
|
|
383
|
+
log ""
|
|
384
|
+
log "=========================================="
|
|
385
|
+
log "SCAN SUMMARY"
|
|
386
|
+
log "=========================================="
|
|
387
|
+
if [[ $OPENCLAW_FOUND -eq 1 ]]; then
|
|
388
|
+
log "STATUS: OpenClaw DETECTED"
|
|
389
|
+
log "DETAILS: $DETAILS"
|
|
390
|
+
log "EXIT CODE: 1"
|
|
391
|
+
else
|
|
392
|
+
log "STATUS: System CLEAN - No OpenClaw installation detected"
|
|
393
|
+
log "EXIT CODE: 0"
|
|
394
|
+
fi
|
|
395
|
+
log "=========================================="
|
|
396
|
+
|
|
105
397
|
exit $OPENCLAW_FOUND
|
|
106
398
|
`;
|
|
107
399
|
}
|
|
@@ -140,26 +432,30 @@ $ErrorActionPreference = "SilentlyContinue"
|
|
|
140
432
|
$OpenClawFound = $false
|
|
141
433
|
$Details = @()
|
|
142
434
|
${webhookSection}
|
|
435
|
+
# All known variants: openclaw, moltbot, clawdbot, clawbot
|
|
436
|
+
$Variants = @("openclaw", "moltbot", "clawdbot", "clawbot")
|
|
437
|
+
|
|
143
438
|
# Check common installation paths
|
|
144
|
-
$CliPaths = @(
|
|
145
|
-
|
|
146
|
-
"$env:
|
|
147
|
-
"$env:ProgramFiles
|
|
148
|
-
)
|
|
439
|
+
$CliPaths = @()
|
|
440
|
+
foreach ($variant in $Variants) {
|
|
441
|
+
$CliPaths += "$env:LOCALAPPDATA\\Programs\\$variant\\$variant.exe"
|
|
442
|
+
$CliPaths += "$env:ProgramFiles\\$variant\\$variant.exe"
|
|
443
|
+
$CliPaths += "$env:ProgramFiles(x86)\\$variant\\$variant.exe"
|
|
444
|
+
}
|
|
149
445
|
|
|
150
446
|
foreach ($path in $CliPaths) {
|
|
151
447
|
if (Test-Path $path) {
|
|
152
448
|
$OpenClawFound = $true
|
|
153
449
|
$Details += "CLI found at $path"
|
|
154
|
-
break
|
|
155
450
|
}
|
|
156
451
|
}
|
|
157
452
|
|
|
158
|
-
# Check config
|
|
159
|
-
$ConfigPaths = @(
|
|
160
|
-
|
|
161
|
-
"$env:
|
|
162
|
-
|
|
453
|
+
# Check config directories (all variants)
|
|
454
|
+
$ConfigPaths = @()
|
|
455
|
+
foreach ($variant in $Variants) {
|
|
456
|
+
$ConfigPaths += "$env:USERPROFILE\\.$variant"
|
|
457
|
+
$ConfigPaths += "$env:APPDATA\\$variant"
|
|
458
|
+
}
|
|
163
459
|
|
|
164
460
|
foreach ($path in $ConfigPaths) {
|
|
165
461
|
if (Test-Path $path) {
|
|
@@ -168,11 +464,13 @@ foreach ($path in $ConfigPaths) {
|
|
|
168
464
|
}
|
|
169
465
|
}
|
|
170
466
|
|
|
171
|
-
# Check running processes
|
|
172
|
-
$
|
|
173
|
-
|
|
174
|
-
$
|
|
175
|
-
|
|
467
|
+
# Check running processes (all variants)
|
|
468
|
+
foreach ($variant in $Variants) {
|
|
469
|
+
$processes = Get-Process -Name "*$variant*" -ErrorAction SilentlyContinue
|
|
470
|
+
if ($processes) {
|
|
471
|
+
$OpenClawFound = $true
|
|
472
|
+
$Details += "Process running: $($processes.Name -join ', ')"
|
|
473
|
+
}
|
|
176
474
|
}
|
|
177
475
|
|
|
178
476
|
# Check gateway port
|
|
@@ -182,11 +480,13 @@ if ($portCheck.TcpTestSucceeded) {
|
|
|
182
480
|
$Details += "Gateway port 18789 listening"
|
|
183
481
|
}
|
|
184
482
|
|
|
185
|
-
# Check Windows
|
|
186
|
-
$
|
|
187
|
-
|
|
188
|
-
$
|
|
189
|
-
|
|
483
|
+
# Check Windows services (all variants)
|
|
484
|
+
foreach ($variant in $Variants) {
|
|
485
|
+
$service = Get-Service -Name "*$variant*" -ErrorAction SilentlyContinue
|
|
486
|
+
if ($service) {
|
|
487
|
+
$OpenClawFound = $true
|
|
488
|
+
$Details += "Service found: $($service.Name) ($($service.Status))"
|
|
489
|
+
}
|
|
190
490
|
}
|
|
191
491
|
|
|
192
492
|
$DetailsString = $Details -join "; "
|
|
@@ -230,8 +530,13 @@ send_webhook() {
|
|
|
230
530
|
#
|
|
231
531
|
# WARNING: This script will remove OpenClaw installations!
|
|
232
532
|
# Run with sudo for full purge capabilities.
|
|
533
|
+
# Exit code is always 0 if the script runs to completion - check logs for details.
|
|
233
534
|
|
|
234
|
-
set -
|
|
535
|
+
set -o pipefail
|
|
536
|
+
|
|
537
|
+
# Set defaults for environment variables that may be unset when running as root
|
|
538
|
+
HOME="\${HOME:-/root}"
|
|
539
|
+
USER="\${USER:-root}"
|
|
235
540
|
|
|
236
541
|
PURGE_RESULTS=""
|
|
237
542
|
${webhookSection}
|
|
@@ -240,68 +545,576 @@ log_action() {
|
|
|
240
545
|
PURGE_RESULTS="$PURGE_RESULTS; $1"
|
|
241
546
|
}
|
|
242
547
|
|
|
548
|
+
# Get all user home directories
|
|
549
|
+
get_all_user_homes() {
|
|
550
|
+
local homes=()
|
|
551
|
+
|
|
552
|
+
# macOS users
|
|
553
|
+
if [[ -d "/Users" ]]; then
|
|
554
|
+
for user_dir in /Users/*; do
|
|
555
|
+
if [[ -d "$user_dir" && "$user_dir" != "/Users/Shared" && "$user_dir" != "/Users/Guest" ]]; then
|
|
556
|
+
homes+=("$user_dir")
|
|
557
|
+
fi
|
|
558
|
+
done
|
|
559
|
+
fi
|
|
560
|
+
|
|
561
|
+
# Linux users
|
|
562
|
+
if [[ -d "/home" ]]; then
|
|
563
|
+
for user_dir in /home/*; do
|
|
564
|
+
if [[ -d "$user_dir" ]]; then
|
|
565
|
+
homes+=("$user_dir")
|
|
566
|
+
fi
|
|
567
|
+
done
|
|
568
|
+
fi
|
|
569
|
+
|
|
570
|
+
# Root home
|
|
571
|
+
if [[ -d "/root" ]]; then
|
|
572
|
+
homes+=("/root")
|
|
573
|
+
fi
|
|
574
|
+
if [[ -d "/var/root" ]]; then
|
|
575
|
+
homes+=("/var/root")
|
|
576
|
+
fi
|
|
577
|
+
|
|
578
|
+
echo "\${homes[@]}"
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
log_action "=========================================="
|
|
582
|
+
log_action "Nox OpenClaw Hunter - Purge (All Users)"
|
|
583
|
+
log_action "=========================================="
|
|
584
|
+
|
|
243
585
|
# Check if running as root
|
|
244
|
-
if [[
|
|
586
|
+
if [[ \${EUID:-$(id -u)} -ne 0 ]]; then
|
|
245
587
|
echo "Warning: Not running as root. Some actions may fail."
|
|
588
|
+
echo "For complete purge across all users, run with sudo."
|
|
246
589
|
fi
|
|
247
590
|
|
|
248
|
-
#
|
|
249
|
-
|
|
250
|
-
|
|
591
|
+
# STEP 1: Unload launchd services FIRST to prevent process respawning (macOS)
|
|
592
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
593
|
+
log_action "Unloading launchd services to prevent respawning..."
|
|
594
|
+
|
|
595
|
+
# System-wide LaunchAgents and LaunchDaemons
|
|
596
|
+
for plist_dir in /Library/LaunchAgents /Library/LaunchDaemons; do
|
|
597
|
+
for pattern in "bot.molt.*" "*openclaw*" "*clawbot*" "*clawdbot*" "*moltbot*"; do
|
|
598
|
+
for plist in "$plist_dir"/$pattern; do
|
|
599
|
+
if [[ -f "$plist" ]]; then
|
|
600
|
+
launchctl bootout system "$plist" 2>/dev/null || launchctl unload "$plist" 2>/dev/null || true
|
|
601
|
+
fi
|
|
602
|
+
done
|
|
603
|
+
done
|
|
604
|
+
done
|
|
605
|
+
|
|
606
|
+
# Per-user LaunchAgents - unload for all users
|
|
607
|
+
for user_home in $(get_all_user_homes); do
|
|
608
|
+
plist_dir="$user_home/Library/LaunchAgents"
|
|
609
|
+
username=$(basename "$user_home")
|
|
610
|
+
user_uid=$(id -u "$username" 2>/dev/null || echo "")
|
|
611
|
+
if [[ -d "$plist_dir" ]]; then
|
|
612
|
+
for pattern in "bot.molt.*" "*openclaw*" "*clawbot*" "*clawdbot*" "*moltbot*"; do
|
|
613
|
+
for plist in "$plist_dir"/$pattern; do
|
|
614
|
+
if [[ -f "$plist" ]]; then
|
|
615
|
+
if [[ -n "$user_uid" ]]; then
|
|
616
|
+
launchctl bootout "gui/$user_uid" "$plist" 2>/dev/null || true
|
|
617
|
+
launchctl bootout "user/$user_uid" "$plist" 2>/dev/null || true
|
|
618
|
+
fi
|
|
619
|
+
launchctl unload "$plist" 2>/dev/null || true
|
|
620
|
+
fi
|
|
621
|
+
done
|
|
622
|
+
done
|
|
623
|
+
fi
|
|
624
|
+
done
|
|
625
|
+
log_action "Launchd services unloaded"
|
|
626
|
+
fi
|
|
627
|
+
|
|
628
|
+
# STEP 1b: Stop systemd services FIRST to prevent respawning (Linux)
|
|
629
|
+
if command -v systemctl &>/dev/null; then
|
|
630
|
+
log_action "Stopping systemd services to prevent respawning..."
|
|
631
|
+
for svc_name in openclaw clawbot clawdbot moltbot; do
|
|
632
|
+
systemctl stop "$svc_name.service" 2>/dev/null || true
|
|
633
|
+
systemctl disable "$svc_name.service" 2>/dev/null || true
|
|
634
|
+
done
|
|
635
|
+
|
|
636
|
+
# User-level services
|
|
637
|
+
for user_home in $(get_all_user_homes); do
|
|
638
|
+
username=$(basename "$user_home")
|
|
639
|
+
for svc_name in openclaw clawbot clawdbot moltbot; do
|
|
640
|
+
sudo -u "$username" systemctl --user stop "$svc_name.service" 2>/dev/null || true
|
|
641
|
+
sudo -u "$username" systemctl --user disable "$svc_name.service" 2>/dev/null || true
|
|
642
|
+
done
|
|
643
|
+
done
|
|
644
|
+
log_action "Systemd services stopped"
|
|
645
|
+
fi
|
|
646
|
+
|
|
647
|
+
# STEP 2: Kill running processes
|
|
648
|
+
log_action "Killing processes (openclaw, clawbot, clawdbot, moltbot)..."
|
|
649
|
+
PROCS_KILLED=0
|
|
650
|
+
for proc_name in openclaw clawbot clawdbot moltbot; do
|
|
651
|
+
# Find PIDs first (exclude our own script)
|
|
652
|
+
PIDS=$(pgrep -x "$proc_name" 2>/dev/null || true)
|
|
653
|
+
if [[ -z "$PIDS" ]]; then
|
|
654
|
+
# Try matching command line if exact name match fails
|
|
655
|
+
PIDS=$(pgrep -f "/$proc_name\$" 2>/dev/null || true)
|
|
656
|
+
fi
|
|
657
|
+
|
|
658
|
+
if [[ -n "$PIDS" ]]; then
|
|
659
|
+
for pid in $PIDS; do
|
|
660
|
+
# Skip if it's our own process
|
|
661
|
+
if [[ "$pid" == "$$" ]]; then
|
|
662
|
+
continue
|
|
663
|
+
fi
|
|
664
|
+
kill -9 "$pid" 2>/dev/null && {
|
|
665
|
+
log_action " Killed $proc_name (PID: $pid)"
|
|
666
|
+
PROCS_KILLED=$((PROCS_KILLED + 1))
|
|
667
|
+
} || true
|
|
668
|
+
done
|
|
669
|
+
fi
|
|
670
|
+
|
|
671
|
+
# Also try pkill as backup
|
|
672
|
+
pkill -9 -x "$proc_name" 2>/dev/null || true
|
|
673
|
+
|
|
674
|
+
# On macOS, also try killall
|
|
675
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
676
|
+
killall -9 "$proc_name" 2>/dev/null || true
|
|
677
|
+
fi
|
|
678
|
+
done
|
|
679
|
+
|
|
680
|
+
# Wait briefly for processes to terminate
|
|
681
|
+
sleep 1
|
|
682
|
+
|
|
683
|
+
# Verify processes are gone
|
|
684
|
+
REMAINING=""
|
|
685
|
+
for proc_name in openclaw clawbot clawdbot moltbot; do
|
|
686
|
+
if pgrep -x "$proc_name" >/dev/null 2>&1; then
|
|
687
|
+
REMAINING="$REMAINING $proc_name"
|
|
688
|
+
fi
|
|
689
|
+
done
|
|
251
690
|
|
|
252
|
-
|
|
691
|
+
if [[ -n "$REMAINING" ]]; then
|
|
692
|
+
log_action "WARNING: Some processes may still be running:$REMAINING"
|
|
693
|
+
# Try one more aggressive kill
|
|
694
|
+
for proc_name in $REMAINING; do
|
|
695
|
+
pkill -9 -f "$proc_name" 2>/dev/null || true
|
|
696
|
+
done
|
|
697
|
+
sleep 1
|
|
698
|
+
|
|
699
|
+
# Final check
|
|
700
|
+
STILL_RUNNING=""
|
|
701
|
+
for proc_name in openclaw clawbot clawdbot moltbot; do
|
|
702
|
+
if pgrep -x "$proc_name" >/dev/null 2>&1; then
|
|
703
|
+
STILL_RUNNING="$STILL_RUNNING $proc_name($(pgrep -x "$proc_name" | tr '\\n' ' '))"
|
|
704
|
+
fi
|
|
705
|
+
done
|
|
706
|
+
|
|
707
|
+
if [[ -n "$STILL_RUNNING" ]]; then
|
|
708
|
+
log_action "ERROR: Failed to kill processes:$STILL_RUNNING - may require manual intervention"
|
|
709
|
+
else
|
|
710
|
+
log_action "Process kill completed (after retry)"
|
|
711
|
+
fi
|
|
712
|
+
else
|
|
713
|
+
if [[ $PROCS_KILLED -gt 0 ]]; then
|
|
714
|
+
log_action "Process kill completed ($PROCS_KILLED processes terminated)"
|
|
715
|
+
else
|
|
716
|
+
log_action "Process kill completed (no matching processes found)"
|
|
717
|
+
fi
|
|
718
|
+
fi
|
|
719
|
+
|
|
720
|
+
# Stop and disable launchd services (macOS) - ALL USERS
|
|
253
721
|
if [[ "$(uname)" == "Darwin" ]]; then
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
722
|
+
log_action "Removing launchd services (all users)..."
|
|
723
|
+
LAUNCHD_REMOVED=0
|
|
724
|
+
LAUNCHD_FAILED=0
|
|
725
|
+
|
|
726
|
+
# System-wide LaunchAgents and LaunchDaemons
|
|
727
|
+
for plist_dir in /Library/LaunchAgents /Library/LaunchDaemons; do
|
|
728
|
+
for pattern in "bot.molt.*" "*openclaw*" "*clawbot*" "*clawdbot*" "*moltbot*"; do
|
|
729
|
+
for plist in "$plist_dir"/$pattern; do
|
|
730
|
+
if [[ -f "$plist" ]]; then
|
|
731
|
+
launchctl unload "$plist" 2>/dev/null || true
|
|
732
|
+
rm -f "$plist" 2>/dev/null
|
|
733
|
+
if [[ -f "$plist" ]]; then
|
|
734
|
+
log_action " FAILED to remove launchd plist: $plist"
|
|
735
|
+
LAUNCHD_FAILED=$((LAUNCHD_FAILED + 1))
|
|
736
|
+
else
|
|
737
|
+
log_action " Removed launchd plist: $plist"
|
|
738
|
+
LAUNCHD_REMOVED=$((LAUNCHD_REMOVED + 1))
|
|
739
|
+
fi
|
|
740
|
+
fi
|
|
741
|
+
done
|
|
742
|
+
done
|
|
743
|
+
done
|
|
744
|
+
|
|
745
|
+
# Per-user LaunchAgents
|
|
746
|
+
for user_home in $(get_all_user_homes); do
|
|
747
|
+
plist_dir="$user_home/Library/LaunchAgents"
|
|
748
|
+
if [[ -d "$plist_dir" ]]; then
|
|
749
|
+
for pattern in "bot.molt.*" "*openclaw*" "*clawbot*" "*clawdbot*" "*moltbot*"; do
|
|
750
|
+
for plist in "$plist_dir"/$pattern; do
|
|
751
|
+
if [[ -f "$plist" ]]; then
|
|
752
|
+
launchctl unload "$plist" 2>/dev/null || true
|
|
753
|
+
rm -f "$plist" 2>/dev/null
|
|
754
|
+
if [[ -f "$plist" ]]; then
|
|
755
|
+
log_action " FAILED to remove launchd plist: $plist"
|
|
756
|
+
LAUNCHD_FAILED=$((LAUNCHD_FAILED + 1))
|
|
757
|
+
else
|
|
758
|
+
log_action " Removed launchd plist: $plist"
|
|
759
|
+
LAUNCHD_REMOVED=$((LAUNCHD_REMOVED + 1))
|
|
760
|
+
fi
|
|
761
|
+
fi
|
|
762
|
+
done
|
|
763
|
+
done
|
|
259
764
|
fi
|
|
260
765
|
done
|
|
766
|
+
|
|
767
|
+
if [[ $LAUNCHD_FAILED -gt 0 ]]; then
|
|
768
|
+
log_action "Launchd removal: $LAUNCHD_REMOVED removed, $LAUNCHD_FAILED failed"
|
|
769
|
+
elif [[ $LAUNCHD_REMOVED -gt 0 ]]; then
|
|
770
|
+
log_action "Launchd removal completed ($LAUNCHD_REMOVED services removed)"
|
|
771
|
+
else
|
|
772
|
+
log_action "Launchd removal completed (no launchd services found)"
|
|
773
|
+
fi
|
|
261
774
|
fi
|
|
262
775
|
|
|
263
|
-
# Stop and disable systemd
|
|
776
|
+
# Stop and disable systemd services (Linux) - system and user level
|
|
264
777
|
if command -v systemctl &>/dev/null; then
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
778
|
+
log_action "Removing systemd services (system and user level)..."
|
|
779
|
+
SYSTEMD_REMOVED=0
|
|
780
|
+
SYSTEMD_FAILED=0
|
|
781
|
+
|
|
782
|
+
# System-level services
|
|
783
|
+
for svc_name in openclaw clawbot clawdbot moltbot; do
|
|
784
|
+
systemctl stop "$svc_name.service" 2>/dev/null || true
|
|
785
|
+
systemctl disable "$svc_name.service" 2>/dev/null || true
|
|
786
|
+
|
|
787
|
+
for svc_path in "/etc/systemd/system/$svc_name.service" "/usr/lib/systemd/system/$svc_name.service"; do
|
|
788
|
+
if [[ -f "$svc_path" ]]; then
|
|
789
|
+
rm -f "$svc_path" 2>/dev/null
|
|
790
|
+
if [[ -f "$svc_path" ]]; then
|
|
791
|
+
log_action " FAILED to remove systemd service: $svc_path"
|
|
792
|
+
SYSTEMD_FAILED=$((SYSTEMD_FAILED + 1))
|
|
793
|
+
else
|
|
794
|
+
log_action " Removed systemd service: $svc_path"
|
|
795
|
+
SYSTEMD_REMOVED=$((SYSTEMD_REMOVED + 1))
|
|
796
|
+
fi
|
|
797
|
+
fi
|
|
798
|
+
done
|
|
799
|
+
done
|
|
800
|
+
|
|
801
|
+
# User-level systemd services
|
|
802
|
+
for user_home in $(get_all_user_homes); do
|
|
803
|
+
user_systemd="$user_home/.config/systemd/user"
|
|
804
|
+
if [[ -d "$user_systemd" ]]; then
|
|
805
|
+
for svc_name in openclaw clawbot clawdbot moltbot; do
|
|
806
|
+
svc_path="$user_systemd/$svc_name.service"
|
|
807
|
+
if [[ -f "$svc_path" ]]; then
|
|
808
|
+
rm -f "$svc_path" 2>/dev/null
|
|
809
|
+
if [[ -f "$svc_path" ]]; then
|
|
810
|
+
log_action " FAILED to remove user systemd service: $svc_path"
|
|
811
|
+
SYSTEMD_FAILED=$((SYSTEMD_FAILED + 1))
|
|
812
|
+
else
|
|
813
|
+
log_action " Removed user systemd service: $svc_path"
|
|
814
|
+
SYSTEMD_REMOVED=$((SYSTEMD_REMOVED + 1))
|
|
815
|
+
fi
|
|
816
|
+
fi
|
|
817
|
+
done
|
|
818
|
+
fi
|
|
819
|
+
done
|
|
820
|
+
|
|
268
821
|
systemctl daemon-reload 2>/dev/null || true
|
|
269
|
-
|
|
822
|
+
|
|
823
|
+
if [[ $SYSTEMD_FAILED -gt 0 ]]; then
|
|
824
|
+
log_action "Systemd removal: $SYSTEMD_REMOVED removed, $SYSTEMD_FAILED failed"
|
|
825
|
+
elif [[ $SYSTEMD_REMOVED -gt 0 ]]; then
|
|
826
|
+
log_action "Systemd removal completed ($SYSTEMD_REMOVED services removed)"
|
|
827
|
+
else
|
|
828
|
+
log_action "Systemd removal completed (no systemd services found)"
|
|
829
|
+
fi
|
|
270
830
|
fi
|
|
271
831
|
|
|
272
|
-
# Remove CLI
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
832
|
+
# Remove CLI binaries (system-wide and per-user)
|
|
833
|
+
log_action "Removing CLI binaries (all locations)..."
|
|
834
|
+
CLI_REMOVED=0
|
|
835
|
+
CLI_FAILED=0
|
|
836
|
+
|
|
837
|
+
# System-wide locations
|
|
838
|
+
for cli_name in openclaw clawbot clawdbot moltbot; do
|
|
839
|
+
for bin_dir in /usr/local/bin /opt/homebrew/bin /usr/bin; do
|
|
840
|
+
cli_path="$bin_dir/$cli_name"
|
|
841
|
+
if [[ -f "$cli_path" ]]; then
|
|
842
|
+
rm -f "$cli_path" 2>/dev/null
|
|
843
|
+
if [[ -f "$cli_path" ]]; then
|
|
844
|
+
log_action " FAILED to remove CLI: $cli_path (permission denied)"
|
|
845
|
+
CLI_FAILED=$((CLI_FAILED + 1))
|
|
846
|
+
else
|
|
847
|
+
log_action " Removed CLI: $cli_path"
|
|
848
|
+
CLI_REMOVED=$((CLI_REMOVED + 1))
|
|
849
|
+
fi
|
|
850
|
+
fi
|
|
851
|
+
done
|
|
278
852
|
done
|
|
279
853
|
|
|
280
|
-
#
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
854
|
+
# Per-user locations
|
|
855
|
+
for user_home in $(get_all_user_homes); do
|
|
856
|
+
for cli_name in openclaw clawbot clawdbot moltbot; do
|
|
857
|
+
for bin_dir in "$user_home/bin" "$user_home/.local/bin"; do
|
|
858
|
+
cli_path="$bin_dir/$cli_name"
|
|
859
|
+
if [[ -f "$cli_path" ]]; then
|
|
860
|
+
rm -f "$cli_path" 2>/dev/null
|
|
861
|
+
if [[ -f "$cli_path" ]]; then
|
|
862
|
+
log_action " FAILED to remove CLI: $cli_path (permission denied)"
|
|
863
|
+
CLI_FAILED=$((CLI_FAILED + 1))
|
|
864
|
+
else
|
|
865
|
+
log_action " Removed CLI: $cli_path"
|
|
866
|
+
CLI_REMOVED=$((CLI_REMOVED + 1))
|
|
867
|
+
fi
|
|
868
|
+
fi
|
|
869
|
+
done
|
|
870
|
+
done
|
|
871
|
+
done
|
|
872
|
+
|
|
873
|
+
if [[ $CLI_FAILED -gt 0 ]]; then
|
|
874
|
+
log_action "CLI removal: $CLI_REMOVED removed, $CLI_FAILED failed"
|
|
875
|
+
elif [[ $CLI_REMOVED -gt 0 ]]; then
|
|
876
|
+
log_action "CLI removal completed ($CLI_REMOVED binaries removed)"
|
|
877
|
+
else
|
|
878
|
+
log_action "CLI removal completed (no CLI binaries found)"
|
|
284
879
|
fi
|
|
285
880
|
|
|
286
|
-
# Remove
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
881
|
+
# Remove macOS app bundles (system-wide and per-user)
|
|
882
|
+
log_action "Removing app bundles (all locations)..."
|
|
883
|
+
APP_REMOVED=0
|
|
884
|
+
APP_FAILED=0
|
|
885
|
+
|
|
886
|
+
for app_name in OpenClaw.app ClawBot.app ClawdBot.app MoltBot.app; do
|
|
887
|
+
# System-wide Applications
|
|
888
|
+
if [[ -d "/Applications/$app_name" ]]; then
|
|
889
|
+
rm -rf "/Applications/$app_name" 2>/dev/null
|
|
890
|
+
if [[ -d "/Applications/$app_name" ]]; then
|
|
891
|
+
log_action " FAILED to remove app: /Applications/$app_name (permission denied or protected)"
|
|
892
|
+
APP_FAILED=$((APP_FAILED + 1))
|
|
893
|
+
else
|
|
894
|
+
log_action " Removed app bundle: /Applications/$app_name"
|
|
895
|
+
APP_REMOVED=$((APP_REMOVED + 1))
|
|
896
|
+
fi
|
|
291
897
|
fi
|
|
898
|
+
|
|
899
|
+
# Per-user Applications
|
|
900
|
+
for user_home in $(get_all_user_homes); do
|
|
901
|
+
if [[ -d "$user_home/Applications/$app_name" ]]; then
|
|
902
|
+
rm -rf "$user_home/Applications/$app_name" 2>/dev/null
|
|
903
|
+
if [[ -d "$user_home/Applications/$app_name" ]]; then
|
|
904
|
+
log_action " FAILED to remove app: $user_home/Applications/$app_name (permission denied)"
|
|
905
|
+
APP_FAILED=$((APP_FAILED + 1))
|
|
906
|
+
else
|
|
907
|
+
log_action " Removed app bundle: $user_home/Applications/$app_name"
|
|
908
|
+
APP_REMOVED=$((APP_REMOVED + 1))
|
|
909
|
+
fi
|
|
910
|
+
fi
|
|
911
|
+
done
|
|
292
912
|
done
|
|
293
913
|
|
|
914
|
+
if [[ $APP_FAILED -gt 0 ]]; then
|
|
915
|
+
log_action "App bundle removal: $APP_REMOVED removed, $APP_FAILED failed"
|
|
916
|
+
elif [[ $APP_REMOVED -gt 0 ]]; then
|
|
917
|
+
log_action "App bundle removal completed ($APP_REMOVED bundles removed)"
|
|
918
|
+
else
|
|
919
|
+
log_action "App bundle removal completed (no app bundles found)"
|
|
920
|
+
fi
|
|
921
|
+
|
|
922
|
+
# Remove config directories for ALL USERS
|
|
923
|
+
log_action "Removing config directories (all users)..."
|
|
924
|
+
CONFIG_REMOVED=0
|
|
925
|
+
CONFIG_FAILED=0
|
|
926
|
+
for user_home in $(get_all_user_homes); do
|
|
927
|
+
for config_name in .openclaw .clawbot .clawdbot .moltbot; do
|
|
928
|
+
config_path="$user_home/$config_name"
|
|
929
|
+
if [[ -d "$config_path" ]]; then
|
|
930
|
+
# On macOS: remove extended attributes and clear immutable flags
|
|
931
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
932
|
+
xattr -cr "$config_path" 2>/dev/null || true
|
|
933
|
+
chflags -R nouchg "$config_path" 2>/dev/null || true
|
|
934
|
+
fi
|
|
935
|
+
# On Linux: remove immutable attribute
|
|
936
|
+
if command -v chattr &>/dev/null; then
|
|
937
|
+
chattr -R -i "$config_path" 2>/dev/null || true
|
|
938
|
+
fi
|
|
939
|
+
|
|
940
|
+
# Remove all contents first, then the directory
|
|
941
|
+
find "$config_path" -type f -delete 2>/dev/null || true
|
|
942
|
+
find "$config_path" -type d -empty -delete 2>/dev/null || true
|
|
943
|
+
rm -rf "$config_path" 2>/dev/null || true
|
|
944
|
+
|
|
945
|
+
# If still exists, try moving to temp and deleting
|
|
946
|
+
if [[ -d "$config_path" ]]; then
|
|
947
|
+
temp_path="/tmp/.nox_purge_$$_$(basename "$config_path")"
|
|
948
|
+
mv "$config_path" "$temp_path" 2>/dev/null && rm -rf "$temp_path" 2>/dev/null || true
|
|
949
|
+
fi
|
|
950
|
+
|
|
951
|
+
# Verify removal
|
|
952
|
+
if [[ -d "$config_path" ]]; then
|
|
953
|
+
log_action " FAILED to remove config: $config_path (permission denied or protected)"
|
|
954
|
+
CONFIG_FAILED=$((CONFIG_FAILED + 1))
|
|
955
|
+
else
|
|
956
|
+
log_action " Removed config: $config_path"
|
|
957
|
+
CONFIG_REMOVED=$((CONFIG_REMOVED + 1))
|
|
958
|
+
fi
|
|
959
|
+
fi
|
|
960
|
+
done
|
|
961
|
+
done
|
|
962
|
+
if [[ $CONFIG_FAILED -gt 0 ]]; then
|
|
963
|
+
log_action "Config removal: $CONFIG_REMOVED removed, $CONFIG_FAILED failed"
|
|
964
|
+
elif [[ $CONFIG_REMOVED -gt 0 ]]; then
|
|
965
|
+
log_action "Config removal completed ($CONFIG_REMOVED directories removed)"
|
|
966
|
+
else
|
|
967
|
+
log_action "Config removal completed (no config directories found)"
|
|
968
|
+
fi
|
|
969
|
+
|
|
294
970
|
# Remove Docker containers and images
|
|
295
971
|
if command -v docker &>/dev/null; then
|
|
296
|
-
|
|
297
|
-
|
|
972
|
+
log_action "Cleaning Docker artifacts..."
|
|
973
|
+
for docker_name in openclaw clawbot clawdbot moltbot; do
|
|
974
|
+
docker ps -a --filter "name=$docker_name" --format "{{.ID}}" | xargs -r docker rm -f 2>/dev/null || true
|
|
975
|
+
docker images --filter "reference=*$docker_name*" --format "{{.ID}}" | xargs -r docker rmi -f 2>/dev/null || true
|
|
976
|
+
done
|
|
298
977
|
log_action "Cleaned Docker artifacts"
|
|
299
978
|
fi
|
|
300
979
|
|
|
980
|
+
# Remove npm global packages (all variants)
|
|
981
|
+
log_action "Removing npm global packages..."
|
|
982
|
+
NPM_REMOVED=0
|
|
983
|
+
NPM_FAILED=0
|
|
984
|
+
|
|
985
|
+
# Get npm global directory
|
|
986
|
+
if command -v npm &>/dev/null; then
|
|
987
|
+
NPM_ROOT=$(npm root -g 2>/dev/null || echo "")
|
|
988
|
+
if [[ -n "$NPM_ROOT" && -d "$NPM_ROOT" ]]; then
|
|
989
|
+
for pkg_name in openclaw clawbot clawdbot moltbot; do
|
|
990
|
+
pkg_path="$NPM_ROOT/$pkg_name"
|
|
991
|
+
if [[ -d "$pkg_path" ]]; then
|
|
992
|
+
rm -rf "$pkg_path" 2>/dev/null
|
|
993
|
+
if [[ -d "$pkg_path" ]]; then
|
|
994
|
+
log_action " FAILED to remove npm package: $pkg_path"
|
|
995
|
+
NPM_FAILED=$((NPM_FAILED + 1))
|
|
996
|
+
else
|
|
997
|
+
log_action " Removed npm package: $pkg_path"
|
|
998
|
+
NPM_REMOVED=$((NPM_REMOVED + 1))
|
|
999
|
+
fi
|
|
1000
|
+
fi
|
|
1001
|
+
done
|
|
1002
|
+
fi
|
|
1003
|
+
fi
|
|
1004
|
+
|
|
1005
|
+
# Also check nvm directories for all users
|
|
1006
|
+
for user_home in $(get_all_user_homes); do
|
|
1007
|
+
nvm_dir="$user_home/.nvm/versions/node"
|
|
1008
|
+
if [[ -d "$nvm_dir" ]]; then
|
|
1009
|
+
for node_version in "$nvm_dir"/*; do
|
|
1010
|
+
if [[ -d "$node_version/lib/node_modules" ]]; then
|
|
1011
|
+
for pkg_name in openclaw clawbot clawdbot moltbot; do
|
|
1012
|
+
pkg_path="$node_version/lib/node_modules/$pkg_name"
|
|
1013
|
+
if [[ -d "$pkg_path" ]]; then
|
|
1014
|
+
rm -rf "$pkg_path" 2>/dev/null
|
|
1015
|
+
# Also remove the symlinked binary
|
|
1016
|
+
bin_path="$node_version/bin/$pkg_name"
|
|
1017
|
+
rm -f "$bin_path" 2>/dev/null
|
|
1018
|
+
if [[ -d "$pkg_path" ]]; then
|
|
1019
|
+
log_action " FAILED to remove npm package: $pkg_path"
|
|
1020
|
+
NPM_FAILED=$((NPM_FAILED + 1))
|
|
1021
|
+
else
|
|
1022
|
+
log_action " Removed npm package: $pkg_path"
|
|
1023
|
+
NPM_REMOVED=$((NPM_REMOVED + 1))
|
|
1024
|
+
fi
|
|
1025
|
+
fi
|
|
1026
|
+
done
|
|
1027
|
+
fi
|
|
1028
|
+
done
|
|
1029
|
+
fi
|
|
1030
|
+
done
|
|
1031
|
+
|
|
1032
|
+
if [[ $NPM_FAILED -gt 0 ]]; then
|
|
1033
|
+
log_action "npm removal: $NPM_REMOVED removed, $NPM_FAILED failed"
|
|
1034
|
+
elif [[ $NPM_REMOVED -gt 0 ]]; then
|
|
1035
|
+
log_action "npm removal completed ($NPM_REMOVED packages removed)"
|
|
1036
|
+
else
|
|
1037
|
+
log_action "npm removal completed (no npm packages found)"
|
|
1038
|
+
fi
|
|
1039
|
+
|
|
1040
|
+
# FINAL CLEANUP PASS - catch any respawned processes and recreated files
|
|
1041
|
+
log_action "Running final cleanup pass..."
|
|
1042
|
+
sleep 2
|
|
1043
|
+
|
|
1044
|
+
# Kill any respawned processes
|
|
1045
|
+
RESPAWNED=0
|
|
1046
|
+
for proc_name in openclaw clawbot clawdbot moltbot; do
|
|
1047
|
+
if pgrep -x "$proc_name" >/dev/null 2>&1; then
|
|
1048
|
+
pkill -9 -x "$proc_name" 2>/dev/null || true
|
|
1049
|
+
killall -9 "$proc_name" 2>/dev/null || true
|
|
1050
|
+
RESPAWNED=1
|
|
1051
|
+
log_action " Killed respawned process: $proc_name"
|
|
1052
|
+
fi
|
|
1053
|
+
done
|
|
1054
|
+
|
|
1055
|
+
# Remove any recreated config directories (thorough removal)
|
|
1056
|
+
for user_home in $(get_all_user_homes); do
|
|
1057
|
+
for config_name in .openclaw .clawbot .clawdbot .moltbot; do
|
|
1058
|
+
config_path="$user_home/$config_name"
|
|
1059
|
+
if [[ -d "$config_path" ]]; then
|
|
1060
|
+
# On macOS: remove extended attributes and clear immutable flags
|
|
1061
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
1062
|
+
xattr -cr "$config_path" 2>/dev/null || true
|
|
1063
|
+
chflags -R nouchg "$config_path" 2>/dev/null || true
|
|
1064
|
+
fi
|
|
1065
|
+
# On Linux: remove immutable attribute
|
|
1066
|
+
if command -v chattr &>/dev/null; then
|
|
1067
|
+
chattr -R -i "$config_path" 2>/dev/null || true
|
|
1068
|
+
fi
|
|
1069
|
+
|
|
1070
|
+
# Remove all contents first, then the directory
|
|
1071
|
+
find "$config_path" -type f -delete 2>/dev/null || true
|
|
1072
|
+
find "$config_path" -type d -empty -delete 2>/dev/null || true
|
|
1073
|
+
rm -rf "$config_path" 2>/dev/null || true
|
|
1074
|
+
|
|
1075
|
+
# If still exists, try moving to temp and deleting
|
|
1076
|
+
if [[ -d "$config_path" ]]; then
|
|
1077
|
+
temp_path="/tmp/.nox_purge_$$_$(basename "$config_path")"
|
|
1078
|
+
mv "$config_path" "$temp_path" 2>/dev/null && rm -rf "$temp_path" 2>/dev/null || true
|
|
1079
|
+
fi
|
|
1080
|
+
|
|
1081
|
+
if [[ -d "$config_path" ]]; then
|
|
1082
|
+
log_action " FAILED: Config directory recreated and cannot be removed: $config_path"
|
|
1083
|
+
else
|
|
1084
|
+
log_action " Removed recreated config directory: $config_path"
|
|
1085
|
+
fi
|
|
1086
|
+
fi
|
|
1087
|
+
done
|
|
1088
|
+
done
|
|
1089
|
+
|
|
1090
|
+
# Final verification
|
|
1091
|
+
FINAL_PROCS=""
|
|
1092
|
+
FINAL_CONFIGS=""
|
|
1093
|
+
for proc_name in openclaw clawbot clawdbot moltbot; do
|
|
1094
|
+
if pgrep -x "$proc_name" >/dev/null 2>&1; then
|
|
1095
|
+
FINAL_PROCS="$FINAL_PROCS $proc_name"
|
|
1096
|
+
fi
|
|
1097
|
+
done
|
|
1098
|
+
for user_home in $(get_all_user_homes); do
|
|
1099
|
+
for config_name in .openclaw .clawbot .clawdbot .moltbot; do
|
|
1100
|
+
if [[ -d "$user_home/$config_name" ]]; then
|
|
1101
|
+
FINAL_CONFIGS="$FINAL_CONFIGS $user_home/$config_name"
|
|
1102
|
+
fi
|
|
1103
|
+
done
|
|
1104
|
+
done
|
|
1105
|
+
|
|
1106
|
+
if [[ -n "$FINAL_PROCS" || -n "$FINAL_CONFIGS" ]]; then
|
|
1107
|
+
log_action "WARNING: Some items could not be fully purged:"
|
|
1108
|
+
[[ -n "$FINAL_PROCS" ]] && log_action " Processes still running:$FINAL_PROCS"
|
|
1109
|
+
[[ -n "$FINAL_CONFIGS" ]] && log_action " Config directories still exist:$FINAL_CONFIGS"
|
|
1110
|
+
log_action "Manual intervention may be required"
|
|
1111
|
+
else
|
|
1112
|
+
log_action "Final cleanup pass completed - all items purged successfully"
|
|
1113
|
+
fi
|
|
1114
|
+
|
|
301
1115
|
log_action "Purge complete"
|
|
302
1116
|
${webhookUrl ? '\nsend_webhook "purged" "$PURGE_RESULTS"' : ''}
|
|
303
1117
|
|
|
304
|
-
echo "Purge complete. Results: $PURGE_RESULTS"
|
|
305
1118
|
exit 0
|
|
306
1119
|
`;
|
|
307
1120
|
}
|
|
@@ -344,31 +1157,39 @@ function Send-Webhook {
|
|
|
344
1157
|
$ErrorActionPreference = "SilentlyContinue"
|
|
345
1158
|
$PurgeResults = @()
|
|
346
1159
|
${webhookSection}
|
|
1160
|
+
# All known variants: openclaw, moltbot, clawdbot, clawbot
|
|
1161
|
+
$Variants = @("openclaw", "moltbot", "clawdbot", "clawbot")
|
|
1162
|
+
|
|
347
1163
|
function Log-Action {
|
|
348
1164
|
param([string]$Message)
|
|
349
1165
|
Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $Message"
|
|
350
1166
|
$script:PurgeResults += $Message
|
|
351
1167
|
}
|
|
352
1168
|
|
|
353
|
-
# Kill running processes
|
|
354
|
-
Log-Action "Killing
|
|
355
|
-
|
|
1169
|
+
# Kill running processes (all variants)
|
|
1170
|
+
Log-Action "Killing processes (all variants)..."
|
|
1171
|
+
foreach ($variant in $Variants) {
|
|
1172
|
+
Get-Process -Name "*$variant*" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
|
1173
|
+
}
|
|
356
1174
|
Log-Action "Processes terminated"
|
|
357
1175
|
|
|
358
|
-
# Stop and remove Windows
|
|
359
|
-
$
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
1176
|
+
# Stop and remove Windows services (all variants)
|
|
1177
|
+
foreach ($variant in $Variants) {
|
|
1178
|
+
$services = Get-Service -Name "*$variant*" -ErrorAction SilentlyContinue
|
|
1179
|
+
foreach ($service in $services) {
|
|
1180
|
+
Stop-Service -Name $service.Name -Force -ErrorAction SilentlyContinue
|
|
1181
|
+
sc.exe delete $service.Name 2>$null
|
|
1182
|
+
Log-Action "Stopped and removed service: $($service.Name)"
|
|
1183
|
+
}
|
|
364
1184
|
}
|
|
365
1185
|
|
|
366
|
-
# Remove CLI binaries
|
|
367
|
-
$CliPaths = @(
|
|
368
|
-
|
|
369
|
-
"$env:
|
|
370
|
-
"$env:ProgramFiles
|
|
371
|
-
)
|
|
1186
|
+
# Remove CLI binaries (all variants)
|
|
1187
|
+
$CliPaths = @()
|
|
1188
|
+
foreach ($variant in $Variants) {
|
|
1189
|
+
$CliPaths += "$env:LOCALAPPDATA\\Programs\\$variant"
|
|
1190
|
+
$CliPaths += "$env:ProgramFiles\\$variant"
|
|
1191
|
+
$CliPaths += "$env:ProgramFiles(x86)\\$variant"
|
|
1192
|
+
}
|
|
372
1193
|
|
|
373
1194
|
foreach ($path in $CliPaths) {
|
|
374
1195
|
if (Test-Path $path) {
|
|
@@ -377,11 +1198,12 @@ foreach ($path in $CliPaths) {
|
|
|
377
1198
|
}
|
|
378
1199
|
}
|
|
379
1200
|
|
|
380
|
-
# Remove config directories
|
|
381
|
-
$ConfigPaths = @(
|
|
382
|
-
|
|
383
|
-
"$env:
|
|
384
|
-
|
|
1201
|
+
# Remove config directories (all variants)
|
|
1202
|
+
$ConfigPaths = @()
|
|
1203
|
+
foreach ($variant in $Variants) {
|
|
1204
|
+
$ConfigPaths += "$env:USERPROFILE\\.$variant"
|
|
1205
|
+
$ConfigPaths += "$env:APPDATA\\$variant"
|
|
1206
|
+
}
|
|
385
1207
|
|
|
386
1208
|
foreach ($path in $ConfigPaths) {
|
|
387
1209
|
if (Test-Path $path) {
|
|
@@ -390,22 +1212,75 @@ foreach ($path in $ConfigPaths) {
|
|
|
390
1212
|
}
|
|
391
1213
|
}
|
|
392
1214
|
|
|
393
|
-
# Remove
|
|
394
|
-
|
|
1215
|
+
# Remove npm global packages (all variants)
|
|
1216
|
+
Log-Action "Removing npm global packages..."
|
|
1217
|
+
if (Get-Command npm -ErrorAction SilentlyContinue) {
|
|
1218
|
+
$npmRoot = (npm root -g 2>$null)
|
|
1219
|
+
if ($npmRoot -and (Test-Path $npmRoot)) {
|
|
1220
|
+
foreach ($variant in $Variants) {
|
|
1221
|
+
$pkgPath = Join-Path $npmRoot $variant
|
|
1222
|
+
if (Test-Path $pkgPath) {
|
|
1223
|
+
Remove-Item -Path $pkgPath -Recurse -Force -ErrorAction SilentlyContinue
|
|
1224
|
+
Log-Action "Removed npm package: $pkgPath"
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
# Also check nvm directories for all users (Windows nvm-windows)
|
|
1231
|
+
$userProfiles = Get-ChildItem "C:\\Users" -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notin @("Public", "Default", "Default User", "All Users") }
|
|
1232
|
+
foreach ($profile in $userProfiles) {
|
|
1233
|
+
$nvmDir = Join-Path $profile.FullName ".nvm"
|
|
1234
|
+
if (Test-Path $nvmDir) {
|
|
1235
|
+
Get-ChildItem $nvmDir -Directory -ErrorAction SilentlyContinue | ForEach-Object {
|
|
1236
|
+
$nodeModules = Join-Path $_.FullName "node_modules"
|
|
1237
|
+
if (Test-Path $nodeModules) {
|
|
1238
|
+
foreach ($variant in $Variants) {
|
|
1239
|
+
$pkgPath = Join-Path $nodeModules $variant
|
|
1240
|
+
if (Test-Path $pkgPath) {
|
|
1241
|
+
Remove-Item -Path $pkgPath -Recurse -Force -ErrorAction SilentlyContinue
|
|
1242
|
+
Log-Action "Removed npm package: $pkgPath"
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
# Also check AppData for nvm-windows
|
|
1249
|
+
$nvmWinDir = Join-Path $profile.FullName "AppData\\Roaming\\nvm"
|
|
1250
|
+
if (Test-Path $nvmWinDir) {
|
|
1251
|
+
Get-ChildItem $nvmWinDir -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match "^v\\d" } | ForEach-Object {
|
|
1252
|
+
$nodeModules = Join-Path $_.FullName "node_modules"
|
|
1253
|
+
if (Test-Path $nodeModules) {
|
|
1254
|
+
foreach ($variant in $Variants) {
|
|
1255
|
+
$pkgPath = Join-Path $nodeModules $variant
|
|
1256
|
+
if (Test-Path $pkgPath) {
|
|
1257
|
+
Remove-Item -Path $pkgPath -Recurse -Force -ErrorAction SilentlyContinue
|
|
1258
|
+
Log-Action "Removed npm package: $pkgPath"
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
Log-Action "npm package removal completed"
|
|
1266
|
+
|
|
1267
|
+
# Remove scheduled tasks (all variants)
|
|
1268
|
+
foreach ($variant in $Variants) {
|
|
1269
|
+
Get-ScheduledTask -TaskName "*$variant*" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$false -ErrorAction SilentlyContinue
|
|
1270
|
+
}
|
|
395
1271
|
Log-Action "Removed scheduled tasks"
|
|
396
1272
|
|
|
397
|
-
# Clean Docker (if installed)
|
|
1273
|
+
# Clean Docker (if installed) - all variants
|
|
398
1274
|
if (Get-Command docker -ErrorAction SilentlyContinue) {
|
|
399
|
-
|
|
400
|
-
|
|
1275
|
+
foreach ($variant in $Variants) {
|
|
1276
|
+
docker ps -a --filter "name=$variant" --format "{{.ID}}" 2>$null | ForEach-Object { docker rm -f $_ 2>$null }
|
|
1277
|
+
docker images --filter "reference=*$variant*" --format "{{.ID}}" 2>$null | ForEach-Object { docker rmi -f $_ 2>$null }
|
|
1278
|
+
}
|
|
401
1279
|
Log-Action "Cleaned Docker artifacts"
|
|
402
1280
|
}
|
|
403
1281
|
|
|
404
|
-
$ResultsString = $PurgeResults -join "; "
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
Write-Host ""
|
|
408
|
-
Write-Host "Purge complete. Results: $ResultsString"
|
|
1282
|
+
${webhookUrl ? '$ResultsString = $PurgeResults -join "; "\nSend-Webhook -Status "purged" -Details $ResultsString\n' : ''}
|
|
1283
|
+
Log-Action "Purge complete"
|
|
409
1284
|
exit 0
|
|
410
1285
|
`;
|
|
411
1286
|
}
|