diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d829430 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,134 @@ +# eDNC Special Character Fix - Claude Code Instructions + +## Project Overview + +PowerShell utility that monitors DNC folders and removes invalid special characters (0xFF) from .pun files in real-time. Deployed to CNC workstations via network share. + +## Technology Stack + +- **Language:** PowerShell 5.1+ +- **Deployment:** Network share (S:\DT\cameron\eDNC-Fix\) → Local (C:\eDNC-Fix\) +- **Logging:** ShopDB API (http://geitshopdb/api.asp) +- **Version Control:** Gitea (localhost:3000/cproudlock/edncfix) + +## IMPORTANT: After Making Changes + +**Always do the following after any code changes:** + +1. **Update version numbers** in ALL of these files: + - `eDNC-SpecialCharFix.ps1` - `$ScriptVersion` variable (line ~81) + - `eDNC-SpecialCharFix.ps1` - `.NOTES` section Version field + - `version.ini` - `Version=x.x.x` + - `README.md` - Version History table + +2. **Commit and push to Gitea:** + ```bash + cd /home/camp/projects/powershell/edncfix + git add -A + git commit -m "vX.X.X: Description of changes" + git push + ``` + +3. **Version format:** Use semantic versioning (MAJOR.MINOR.PATCH) + - MAJOR: Breaking changes + - MINOR: New features + - PATCH: Bug fixes + +## File Structure + +``` +/home/camp/projects/powershell/edncfix/ +├── eDNC-SpecialCharFix.ps1 # Main script +├── Run-eDNCFix.bat # Manual launcher (auto-elevates) +├── Install-ScheduledTask.ps1 # Creates Windows scheduled task +├── Deploy.bat # Copies from S: to C:\eDNC-Fix\ +├── version.ini # Version file for auto-updates +├── README.md # Documentation +└── CLAUDE.md # This file +``` + +## Configuration (Hardcoded) + +| Setting | Value | Location | +|---------|-------|----------| +| Watch Folder | `C:\Dnc_Files\Q` | eDNC-SpecialCharFix.ps1 | +| File Filter | `*.pun` | eDNC-SpecialCharFix.ps1 | +| Update Source | `S:\DT\cameron\eDNC-Fix` | eDNC-SpecialCharFix.ps1 | +| API URL | `http://geitshopdb/api.asp` | eDNC-SpecialCharFix.ps1 | +| Update Interval | 300 seconds (5 min) | eDNC-SpecialCharFix.ps1 | + +## ShopDB API Integration + +The script logs events to ShopDB via the API. Reference the ShopDB API documentation at: +- **ShopDB Project:** `/home/camp/projects/windows/shopdb/` +- **API File:** `/home/camp/projects/windows/shopdb/api.asp` +- **Standards Doc:** `/home/camp/projects/windows/shopdb/docs/STANDARDS.md` + +### API Endpoint: logDNCEvent + +**Method:** POST +**URL:** `http://geitshopdb/api.asp` + +**Parameters:** +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| action | string | Yes | Must be "logDNCEvent" | +| hostname | string | Yes | PC hostname | +| eventType | string | Yes | Event type: started, cleaned, ok, failed, error, stopped | +| filename | string | No | File being processed | +| bytesRemoved | int | No | Number of bytes removed | +| version | string | No | Script version | +| message | string | No | Additional details | +| watchFolder | string | No | Folder being watched | +| fileFilter | string | No | File filter pattern | + +**Database Tables:** +- `ednc_logs` - Individual event log entries +- `ednc_installations` - Per-hostname installation tracking + +### API Endpoint: getDNCStats + +**Method:** GET +**URL:** `http://geitshopdb/api.asp?action=getDNCStats` + +Returns JSON with all eDNC installations and their stats. + +## Deployment Workflow + +1. **Development:** Edit files in `/home/camp/projects/powershell/edncfix/` +2. **Update versions:** Bump all version numbers +3. **Commit:** Push to Gitea +4. **Stage:** Copy files to `S:\DT\cameron\eDNC-Fix\` +5. **Deploy:** On target PC, run `Deploy.bat` from S: drive +6. **Install:** Run `Install-ScheduledTask.ps1` as Admin + +## Auto-Update Mechanism + +Running instances check `S:\DT\cameron\eDNC-Fix\version.ini` every 5 minutes. +If a newer version is found, they automatically: +1. Copy new files from S: to C:\eDNC-Fix\ +2. Restart themselves + +**To deploy an update to all PCs:** +1. Update version.ini with new version number +2. Copy updated files to S:\DT\cameron\eDNC-Fix\ +3. Wait up to 5 minutes for auto-update + +## Quick Reference + +### Test API endpoint: +```bash +curl -X POST http://192.168.122.151:8080/api.asp \ + -d "action=logDNCEvent&hostname=TESTPC&eventType=started&version=1.5.0" +``` + +### Check installations: +```bash +curl "http://192.168.122.151:8080/api.asp?action=getDNCStats" +``` + +### View logs in database: +```sql +SELECT * FROM ednc_logs ORDER BY created DESC LIMIT 20; +SELECT * FROM ednc_installations; +``` diff --git a/README.md b/README.md index d5a02e7..dd929d3 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ The script uses exponential backoff (500ms → 1s → 2s → 4s → up to 16s) f | Version | Date | Changes | |---------|------|---------| +| 1.5.0 | 2025-12-12 | API logging to ShopDB (started, cleaned, failed, stopped events) | | 1.4.0 | 2025-12-12 | Auto-update from S:\DT\cameron\eDNC-Fix\version.ini every 5 min | | 1.3.1 | 2025-12-12 | Added Install-ScheduledTask.ps1 for running as SYSTEM service | | 1.3.0 | 2025-12-12 | Fixed header UI, live status/stats, auto-elevate to Administrator | diff --git a/eDNC-SpecialCharFix.ps1 b/eDNC-SpecialCharFix.ps1 index 540335e..ce90ff5 100644 --- a/eDNC-SpecialCharFix.ps1 +++ b/eDNC-SpecialCharFix.ps1 @@ -36,9 +36,13 @@ .NOTES Author: GE Aerospace - Rutland - Version: 1.4.0 + Version: 1.5.0 Date: 2025-12-12 + v1.5.0 - API logging: + - Logs events (started, cleaned, ok, failed, error, stopped) to ShopDB API + - Tracks installations and stats per hostname + v1.4.0 - Auto-update: - Checks S:\DT\cameron\eDNC-Fix\version.ini every 5 minutes - Auto-downloads and restarts if newer version found @@ -78,7 +82,7 @@ param( ) # Script info -$ScriptVersion = "1.4.0" +$ScriptVersion = "1.5.0" $ScriptName = "eDNC Special Character Fix" # Auto-update settings @@ -87,6 +91,10 @@ $LocalPath = "C:\eDNC-Fix" $UpdateCheckInterval = 300 # Check every 5 minutes (in seconds) $script:LastUpdateCheck = [DateTime]::MinValue +# API logging settings +$ApiUrl = "http://geitshopdb/api.asp" +$script:Hostname = $env:COMPUTERNAME + # Header display function function Show-Header { param([int]$Cleaned = 0, [int]$Failed = 0, [string]$Status = "Watching...") @@ -205,6 +213,35 @@ function Invoke-Update { } } +# API logging function +function Send-DNCEvent { + param( + [string]$EventType, + [string]$Filename = "", + [int]$BytesRemoved = 0, + [string]$Message = "" + ) + + try { + $body = @{ + action = "logDNCEvent" + hostname = $script:Hostname + filename = $Filename + eventType = $EventType + bytesRemoved = $BytesRemoved + version = $ScriptVersion + message = $Message + watchFolder = $WatchFolder + fileFilter = $FileFilter + } + + $null = Invoke-WebRequest -Uri $ApiUrl -Method POST -Body $body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing -TimeoutSec 5 + } + catch { + # Silently fail - don't disrupt file watching for API issues + } +} + # Initialize console Clear-Host $script:HeaderHeight = Show-Header -Status "Initializing..." @@ -223,6 +260,9 @@ Show-Header -Status "Watching for files... (Ctrl+C to stop)" | Out-Null Write-Host "Removing bytes: $($CharactersToRemove -join ', ') (0x$($CharactersToRemove | ForEach-Object { '{0:X2}' -f $_ } | Join-String -Separator ', 0x'))" -ForegroundColor DarkGray Write-Host "" +# Log startup to API +Send-DNCEvent -EventType "started" -Message "Script started" + # Statistics $script:FilesProcessed = 0 $script:BytesRemoved = 0 @@ -267,6 +307,25 @@ $action = { [Console]::SetCursorPosition(0, $savedPos) } + # Helper to log to API + $logToApi = { + param($eventType, $file, $bytes, $msg) + try { + $body = @{ + action = "logDNCEvent" + hostname = $Event.MessageData.Hostname + filename = $file + eventType = $eventType + bytesRemoved = $bytes + version = $Event.MessageData.Version + message = $msg + watchFolder = $Event.MessageData.WatchFolder + fileFilter = $Event.MessageData.FileFilter + } + $null = Invoke-WebRequest -Uri $Event.MessageData.ApiUrl -Method POST -Body $body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing -TimeoutSec 5 + } catch { } + } + # Debounce check - skip if we processed this file recently $now = Get-Date if ($script:RecentlyProcessed.ContainsKey($path)) { @@ -328,9 +387,11 @@ $action = { $script:BytesRemoved += $removed & $updateStatus "CLEANED: $fileName ($removed bytes)" "Green" & $updateStats + & $logToApi "cleaned" $fileName $removed "Removed $removed byte(s)" } else { Write-Host " [OK] No special characters found" -ForegroundColor Gray & $updateStatus "OK: $fileName (no changes)" "Gray" + & $logToApi "ok" $fileName 0 "No changes needed" } # Mark as recently processed @@ -350,6 +411,7 @@ $action = { $script:FailedFiles++ & $updateStatus "FAILED: $fileName" "Red" & $updateStats + & $logToApi "failed" $fileName 0 "Could not access file after $maxRetries attempts" } } catch { @@ -357,6 +419,7 @@ $action = { $script:FailedFiles++ & $updateStatus "ERROR: $fileName" "Red" & $updateStats + & $logToApi "error" $fileName 0 $_.Exception.Message break } finally { @@ -374,6 +437,10 @@ $messageData = @{ DebounceSeconds = $script:DebounceSeconds StatusLine = 14 # Line number for status updates FileFilter = $FileFilter + ApiUrl = $ApiUrl + Hostname = $script:Hostname + Version = $ScriptVersion + WatchFolder = $WatchFolder } # Register event handlers @@ -397,6 +464,9 @@ try { } } finally { + # Log shutdown to API + Send-DNCEvent -EventType "stopped" -Message "Script stopped. Cleaned: $script:FilesProcessed, Failed: $script:FailedFiles" + # Cleanup on exit $watcher.EnableRaisingEvents = $false $watcher.Dispose() diff --git a/version.ini b/version.ini index 9b9e9ac..fef5dc5 100644 --- a/version.ini +++ b/version.ini @@ -1,2 +1,2 @@ [eDNC-Fix] -Version=1.4.0 +Version=1.5.0