Claw-Gripper.ps1
|
<#PSScriptInfo .VERSION 1.1.0 .GUID 9b7d86ef-6b5c-40b9-853a-ffa88368831b .AUTHOR Grip Security .COMPANYNAME Grip Security .COPYRIGHT (c) Grip Security .TAGS GripSecurity,OpenClaw,Discovery,Audit,Forensics,WSL .LICENSEURI https://grip.security .PROJECTURI https://grip.security .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES 1.1.0 - Documentation and packaging polish. -Json now outputs JSON to stdout (in addition to optional -JsonPath file output). Core scan logic unchanged. .PRIVATEDATA #> <# .SYNOPSIS Claw Gripper (v1.1) - Deep Discovery. .DESCRIPTION Performs a deep discovery scan for OpenClaw installations on the local machine. Specifically captures: - ComputerName - Platform (Windows / WSL distro name) - OpenClaw Version (best-effort) - Installed Skills (best-effort) - State directory path (best-effort) Output is printed as a table by default. Optionally outputs JSON to stdout and/or writes JSON results to a file path. .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() } |