Claw-Gripper.ps1
|
<#PSScriptInfo .VERSION 1.1.1 .GUID 9b7d86ef-6b5c-40b9-853a-ffa88368831b .AUTHOR Grip Security .COMPANYNAME Grip Security .COPYRIGHT (c) Grip Security .TAGS GripSecurity OpenClaw Discovery Audit MDM WSL .LICENSEURI https://grip.security/ .PROJECTURI https://grip.security/ .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES 1.1.1 - Metadata refresh (description/tags). No functional changes. .PRIVATEDATA #> <# .SYNOPSIS Claw Gripper (v1.1) - Deep Discovery. .DESCRIPTION Claw Gripper helps security teams quickly identify **where OpenClaw is running** — and what it can do on each endpoint. Built by **Grip Security** for fast, reliable discovery. Scans **Windows + WSL** (when available). Captures: - Device + Platform / Distro - OpenClaw Version + Installed Skills (best-effort) - Installation State Directory Path (best-effort) Clean table output by default. **MDM-ready** JSON export to stdout and/or file for fleet reporting and automation. .PARAMETER Json If specified, outputs JSON to stdout (in addition to the standard table output). .PARAMETER JsonPath If specified, writes JSON output to the provided path. .PARAMETER Mdm If specified, suppresses the "Press any key to close..." prompt (MDM / non-interactive friendly). .PARAMETER NoPause If specified, suppresses the "Press any key to close..." prompt. .EXAMPLE .\Claw-Gripper.ps1 Runs the scan and prints a table. .EXAMPLE .\Claw-Gripper.ps1 -Json Runs the scan, prints a table, and also outputs JSON to stdout. .EXAMPLE .\Claw-Gripper.ps1 -JsonPath "C:\Temp\claw_gripper.json" Runs the scan, prints a table, and writes results to the specified JSON file. .NOTES - Windows-focused: uses Win32_UserProfile and optionally queries WSL distros via wsl.exe. - If WSL is not available, the script continues and reports Windows findings only. #> [CmdletBinding()] param( [switch]$Json, [string]$JsonPath, [switch]$Mdm, [switch]$NoPause ) $ErrorActionPreference = "Continue" # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- function Get-ClawGripperSkills { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$StatePath ) $skills = @() # Check both the standard 'skills' folder and the workspace 'skills' $skillPaths = @( (Join-Path $StatePath "skills"), (Join-Path $StatePath "workspace/skills") ) foreach ($sp in $skillPaths) { if (Test-Path $sp) { $skills += (Get-ChildItem $sp -Directory -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) } } return ($skills | Sort-Object -Unique) -join ", " } # --------------------------------------------------------------------------- # Core audit logic # --------------------------------------------------------------------------- function Invoke-ClawGripperAudit { [CmdletBinding()] param() $findings = New-Object System.Collections.Generic.List[object] $stateDirs = New-Object System.Collections.Generic.List[string] $compName = $env:COMPUTERNAME Write-Host "... Scanning for installations on $compName" -ForegroundColor Gray # 1) WINDOWS SCAN try { $profiles = Get-CimInstance Win32_UserProfile -ErrorAction Stop | Where-Object { $_.LocalPath } foreach ($p in $profiles) { $d = Join-Path $p.LocalPath ".openclaw" if (Test-Path $d) { $stateDirs.Add("Windows|$d") } } } catch { # Keep going; this may fail on environments without CIM/WMI access. } # 2) WSL SCAN (Ubuntu/Linux) try { $distros = wsl.exe --list --quiet 2>$null | Where-Object { $_ -match "\w" } foreach ($d in $distros) { $distroName = $d.Trim().Replace("`0", "") $wslPath = "\\wsl.localhost\$distroName\home" if (Test-Path $wslPath) { $linuxUsers = Get-ChildItem $wslPath -Directory -ErrorAction SilentlyContinue foreach ($lUser in $linuxUsers) { $target = Join-Path $lUser.FullName ".openclaw" if (Test-Path $target) { $stateDirs.Add("$distroName|$target") } } } } } catch { # WSL not present / not accessible; continue. } foreach ($entry in ($stateDirs | Sort-Object -Unique)) { $parts = $entry -split "\|", 2 $platform = $parts[0] $finalPath = $parts[1] $version = "Unknown" $skills = Get-ClawGripperSkills -StatePath $finalPath if ($platform -ne "Windows") { # Linux version check via WSL try { $rawVer = wsl.exe -d $platform -e openclaw --version 2>$null $version = ($rawVer -join " ").Trim() } catch { $version = "Found (CLI unreachable)" } } else { # Windows version check try { $cmd = Get-Command openclaw -ErrorAction SilentlyContinue if ($cmd) { $version = (& $cmd.Source --version 2>$null) -join " " } } catch { # Keep defaults } } if ([string]::IsNullOrWhiteSpace($version)) { $version = "Detected (No Version info)" } if ([string]::IsNullOrWhiteSpace($skills)) { $skills = "None Found" } $findings.Add([pscustomobject]@{ ComputerName = $compName Platform = $platform Version = $version Skills = $skills Path = $finalPath }) } return $findings } # --------------------------------------------------------------------------- # Execution # --------------------------------------------------------------------------- $results = Invoke-ClawGripperAudit if ($results.Count -eq 0) { Write-Host "RESULT: No OpenClaw installations found on $env:COMPUTERNAME" -ForegroundColor Green } else { Write-Host "RESULT: Found $($results.Count) installations:`n" -ForegroundColor Yellow $results | Format-Table ComputerName, Platform, Version, Skills -AutoSize } # JSON output (stdout and/or file) if ($Json -or $JsonPath) { $jsonText = $results | ConvertTo-Json -Depth 5 if ($Json) { $jsonText } if ($JsonPath) { try { $jsonText | Set-Content -Path $JsonPath -Encoding utf8 } catch { Write-Warning "Failed to write JSON to path '$JsonPath'. Error: $($_.Exception.Message)" } } } if (-not $Mdm -and -not $NoPause) { Write-Host "`nScan Finished. Press any key to close..." $null = [Console]::ReadKey() } |