3 Commits
main ... ad2

Author SHA1 Message Date
sysadmin
aed04e8ca4 Add AD scripts and stage import instructions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 09:48:59 -07:00
sysadmin
88dc431cfa Session log 2026-04-03: WO import, 7B support, PG migration started
- 33K work orders imported, 2.27M records linked
- 7B exact-match formatter added (31 params, 120VAC, Packing Check List)
- TXT formatting refined to match QB TAB positions exactly
- PostgreSQL 18 installed on AD2, database created
- SQL Server Express uninstalled
- Full Dataforth audit document generated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 09:47:30 -07:00
sysadmin@dataforth.com
7431bfd52b Update CLAUDE.md: Full Dataforth context, credentials, pipeline state, known issues 2026-03-29 18:09:48 -07:00
10 changed files with 1202 additions and 177 deletions

View File

@@ -1,204 +1,246 @@
# ClaudeTools Project Context # ClaudeTools on AD2 (Dataforth Domain Controller)
## Identity: You Are a Coordinator ## Identity
You are NOT an executor. You coordinate specialized agents and preserve your context window. This is the AD2 workstation instance of ClaudeTools. This machine is a Windows Server on the Dataforth LAN (192.168.0.6). Your scope is Dataforth-only -- you do not need context about other clients.
**Delegate ALL significant work:** ## NO EMOJIS
| Operation | Delegate To | Use ASCII markers: [OK], [ERROR], [WARNING], [SUCCESS], [INFO]
|-----------|------------|
| Database queries/inserts/updates | Database Agent |
| Production code generation | Coding Agent |
| Code review (MANDATORY after changes) | Code Review Agent |
| Test execution | Testing Agent |
| Git commits/push/branch | Gitea Agent |
| Backups/restore | Backup Agent |
| File exploration (broad) | Explore Agent |
| Semantic code search | deep-explore Agent (uses GrepAI) |
| Complex reasoning | General-purpose + Sequential Thinking |
**Do yourself:** Simple responses, reading 1-2 files, presenting results, planning, decisions.
**Rule:** >500 tokens of work = delegate. Code or database = ALWAYS delegate.
**DO NOT** query databases directly (no SSH/mysql/curl to API). **DO NOT** write production code. **DO NOT** run tests. **DO NOT** commit/push. Use the appropriate agent.
--- ---
## Project Overview ## Git & Sync
**Type:** MSP Work Tracking System | **Status:** Production-Ready (Phase 5 Complete) ### Gitea Credentials (no 1Password on this machine)
**Database:** MariaDB 10.6.22 @ 172.16.3.30:3306 | **API:** http://172.16.3.30:8001 - URL: https://git.azcomputerguru.com
**Stats:** 95+ endpoints, 38 tables, JWT auth, AES-256-GCM encryption - Username: mike@azcomputerguru.com
- Password: Gptf*77ttb123!@#-git
- URL-encoded password: Gptf%2A77ttb123%21%40%23-git
- API Token: 9b1da4b79a38ef782268341d25a4b6880572063f
- Remote: https://mike%40azcomputerguru.com:Gptf%2A77ttb123%21%40%23-git@git.azcomputerguru.com/azcomputerguru/claudetools.git
**DB Connection:** Host: 172.16.3.30:3306 | DB: claudetools | User: claudetools | Password: CT_e8fcd5a3952030a79ed6debae6c954ed ### Branch: ad2
**Details:** `.claude/agents/DATABASE_CONNECTION_INFO.md` This machine operates on the `ad2` branch. The main workstation merges into main.
--- ### /save behavior
Save session logs to `session-logs/YYYY-MM-DD-session-ad2.md` (note the -ad2 suffix).
After saving, commit and push to origin/ad2.
## Key Rules ### /sync behavior
```
- **NO EMOJIS** - Use ASCII markers: `[OK]`, `[ERROR]`, `[WARNING]`, `[SUCCESS]`, `[INFO]` git fetch origin
- **No hardcoded credentials** - Use 1Password (`op read "op://Vault/Item/field"`) or encrypted storage git rebase origin/main
- **SSH:** Use system OpenSSH (on Windows: `C:\Windows\System32\OpenSSH\ssh.exe`, never Git for Windows SSH) git push origin ad2
- **Data integrity:** Never use placeholder/fake data. Check credentials.md (op:// refs) or 1Password or ask user.
- **Full coding standards:** `.claude/CODING_GUIDELINES.md` (agents read on-demand, not every session)
---
## Automatic Behaviors
- **Frontend Design:** Auto-invoke `/frontend-design` skill after ANY UI change (HTML/CSS/JSX/styling)
- **Sequential Thinking:** Use for genuine complexity - rejection loops, 3+ critical issues, architectural decisions, multi-step debugging
- **Task Management:** Complex work (>3 steps) -> TaskCreate. Persist to `.claude/active-tasks.json`.
---
## Context Recovery
When user references previous work, use `/context` command. Never ask user for info in:
- `credentials.md` - Infrastructure reference with `op://` paths (secrets in 1Password)
- `session-logs/` - Daily work logs (also in `projects/*/session-logs/` and `clients/*/session-logs/`)
- `SESSION_STATE.md` - Project history
### 1Password Credential Access
Credentials are stored in 1Password across 4 vaults: **Infrastructure**, **Clients**, **Projects**, **MSP Tools**.
**To read a secret:** `op read "op://VaultName/ItemTitle/field_name"`
**Service account (non-interactive):** Set `OP_SERVICE_ACCOUNT_TOKEN` env var. Token stored in `op://Infrastructure/Service Account Auth Token: Agentic_Cli/credential`. The service account has Read & Write on all 4 vaults (except Projects which is read-only -- use desktop app auth for Projects writes).
**Setup on new machines:**
1. Install 1Password CLI: https://developer.1password.com/docs/cli/get-started/
2. Sign in: `op signin` (or use desktop app integration)
3. For non-interactive use, add to shell config: `set -gx OP_SERVICE_ACCOUNT_TOKEN "token_value"`
---
## Commands & Skills
| Command | Purpose |
|---------|---------|
| `/checkpoint` | Dual checkpoint: git commit + database context |
| `/save` | Comprehensive session log (credentials, decisions, changes) |
| `/context` | Search session logs, credentials.md, and 1Password |
| `/1password` | 1Password secrets management integration |
| `/sync` | Sync config from Gitea repository |
| `/create-spec` | Create app specification for AutoCoder |
| `/frontend-design` | Modern frontend design patterns (auto-invoke after UI changes) |
---
## File Placement (Quick Rules)
- **Dataforth DOS work** -> `projects/dataforth-dos/`
- **ClaudeTools API code** -> `api/`, `migrations/` (existing structure)
- **Client work** -> `clients/[client-name]/`
- **Session logs** -> project or client `session-logs/` subfolder; general -> root `session-logs/`
- **Full guide:** `.claude/FILE_PLACEMENT_GUIDE.md` (read when saving files, not every session)
---
## Local AI (Ollama)
Ollama runs locally with GPU acceleration. Use it for tasks that don't need Claude-level reasoning.
### Available Models
| Model | Size | Use For |
|-------|------|---------|
| `qwen3:14b` | 9.3 GB | General sub-tasks: summarization, classification, data extraction, drafting |
| `codestral:22b` | 12 GB | Code-specific sub-tasks: code generation, refactoring suggestions, docstring generation |
| `nomic-embed-text` | 274 MB | Embeddings only (used by GrepAI, not for direct use) |
### GrepAI (Semantic Code Search)
GrepAI indexes the codebase using `nomic-embed-text` embeddings and provides semantic search via MCP server.
**When to use GrepAI instead of Grep/Glob:**
- Finding code by intent ("how does authentication work") rather than exact text
- Exploring unfamiliar areas of the codebase
- Finding related implementations across files
- Context recovery — searching session logs and credentials by meaning
**How to use:**
- **MCP tool:** Use the `grepai` MCP server tools directly (available after MCP loads)
- **deep-explore agent:** Delegate to the `deep-explore` agent for thorough semantic exploration
- **CLI fallback:** `grepai search "your query" --json --compact`
**Maintenance:** The watcher daemon runs in the background and auto-indexes file changes. If search results seem stale, run `grepai watch --stop && grepai watch --background` to restart it.
### Using Ollama for Sub-Tasks
For bulk or repetitive work that doesn't require Claude's full reasoning, offload to local models via Ollama's API:
**When to use Ollama:**
- Processing many items in a loop (e.g., summarizing 50 session logs)
- Generating boilerplate or repetitive code patterns
- Data extraction/classification from structured text
- Draft content that Claude will review/refine
- Any task where speed > quality and results will be verified
**When NOT to use Ollama (use Claude instead):**
- Architectural decisions or complex reasoning
- Security-sensitive code review
- Tasks requiring tool use or multi-step planning
- Final output that goes directly to production
**How to call Ollama:**
```bash
# Simple prompt
curl -s http://localhost:11434/api/generate -d '{"model":"qwen3:14b","prompt":"Summarize this: ...","stream":false}' | jq -r '.response'
# Chat format
curl -s http://localhost:11434/api/chat -d '{"model":"codestral:22b","messages":[{"role":"user","content":"Refactor this function: ..."}],"stream":false}' | jq -r '.message.content'
``` ```
### Ollama Output Review Policy ---
The coordinator (Claude) must review Ollama outputs based on impact level. Local models are useful but unreliable — they hallucinate, miss edge cases, and produce subtly wrong code. ## Dataforth Network
**Impact levels and review requirements:** | Host | IP | Role | Notes |
|------|-----|------|-------|
| AD1 | 192.168.0.27 | Primary DC | Disk at 90%, C:\Engineering = 787 GB |
| **AD2** | **192.168.0.6** | **This machine** | Secondary DC, TestDataDB, file shares |
| D2TESTNAS | 192.168.0.9 | SMB1 proxy for DOS | Debian 13, Samba, SSH root/Paper123!@#-nas |
| UDM | 192.168.0.254 | Gateway/Router | UniFi Dream Machine |
| ESXi-122 | 192.168.0.122 | Hypervisor | ESXi |
| ESXi-124 | 192.168.0.124 | Hypervisor | ESXi |
| DOS stations | TS-01 to TS-30+ | Test stations | DOS 6.22, QuickBASIC ATE software |
| Level | Review | Examples | ### Credentials
|-------|--------|----------| - AD Sysadmin: INTRANET\sysadmin / Paper123!@#
| **Critical** | ALWAYS review, verify against source | Code touching auth/security/encryption, credential handling, database migrations, production config, anything user-facing | - D2TESTNAS SSH: root@192.168.0.9 / Paper123!@#-nas
| **High** | Review for correctness, spot-check details | API endpoint logic, business rules, infrastructure scripts, client-specific work | - D2TESTNAS Samba: guest access (no password)
| **Medium** | Skim for obvious errors, trust if reasonable | Internal documentation drafts, session log summaries, data extraction from structured input, boilerplate code | - WINS/NPS: 192.168.0.27:1812/1813
| **Low** | Trust without review | Classification/tagging of items, reformatting text, generating placeholder content for later editing | - M365 Tenant: 7dfa3ce8-c496-4b51-ab8d-bd3dcd78b584
- Rsync daemon (NAS): port 873, module "test", user rsync / IQ203s32119
**Review process for Critical/High:**
1. Read Ollama's full output — don't just check if it "looks right"
2. Verify claims against actual files/data (e.g., if it says a function exists, confirm it does)
3. Check for: hallucinated function names, wrong parameter types, missing error handling, security gaps
4. If output is wrong or uncertain, redo the task yourself rather than patching Ollama's attempt
**Batch processing pattern:**
When using Ollama for bulk tasks (e.g., processing N items), review the first 2-3 results fully before trusting the rest. If any are wrong, switch to doing it yourself or fix the prompt and reprocess.
**Flag to user:** If Ollama produces output for a Critical task and you are not confident in your review, tell the user explicitly: "This was generated by a local model and I'm not fully confident in [specific concern]."
--- ---
## Memory (Shared Across Machines) ## Local Resources
Claude Code's auto-memory is stored **in-repo** at `.claude/memory/` so it syncs via Gitea to all workstations. | Resource | Path |
|----------|------|
**IMPORTANT for all machines:** Configure Claude Code to use the repo memory path, NOT the default `~/.claude/projects/` path. When the auto-memory system prompts you to write to `~/.claude/projects/-home-guru-ClaudeTools/memory/`, write to `.claude/memory/` (repo-relative) instead. The index file is `.claude/memory/MEMORY.md`. | TestDataDB app | C:\Shares\testdatadb\ |
| Test database | C:\Shares\testdatadb\database\testdata.db (SQLite, 2.2M+ records) |
This ensures memory created on one workstation (CachyOS, Mac, Windows) is available on all others after a git pull/sync. | TestDataDB API | http://localhost:3000 |
| Parsers | C:\Shares\testdatadb\parsers\ (multiline.js, csvline.js, shtfile.js, spec-reader.js) |
| Templates | C:\Shares\testdatadb\templates\datasheet-exact.js |
| Import script | C:\Shares\testdatadb\database\import.js |
| Export script | C:\Shares\testdatadb\database\export-datasheets.js |
| Stage import | C:\Shares\testdatadb\import-all-stage.js |
| NAS share | \\D2TESTNAS\test (mapped as T:) |
| Datasheets share | X:\For_Web |
| ProdSW (BAT files) | C:\Shares\test\COMMON\ProdSW\ |
| Sync script | C:\Shares\test\scripts\Sync-FromNAS.ps1 (bidirectional, 15-min schedule) |
--- ---
## Reference (read on-demand, not every session) ## DOS Update System - Batch Files
- **Project structure, endpoints, workflows, troubleshooting:** `.claude/REFERENCE.md` ### Boot Sequence on DOS Machines
- **Agent definitions:** `.claude/agents/*.md` ```
- **MCP servers:** `MCP_SERVERS.md` AUTOEXEC.BAT (v4.1)
- **Coding standards:** `.claude/CODING_GUIDELINES.md` -> STARTNET.BAT (v2.0) -- init network, map T: and X: drives
- **Shared memory:** `.claude/memory/MEMORY.md` (index) + `.claude/memory/*.md` (individual memories) -> ATESYNC.BAT
-> CTONW.BAT (v5.0) -- upload test data to network
-> CTONWTXT.BAT (v2.3) -- upload C:\STAGE\*.TXT to T:\STAGE\%MACHINE%
-> NWTOC.BAT (v5.0) -- download updates from network
```
### Current Production Versions (on AD2 & NAS)
| File | Version | Last Update | Purpose |
|------|---------|-------------|---------|
| AUTOEXEC.BAT | v4.1 | 2026-03-12 | Startup config |
| STARTNET.BAT | v2.0 | 2026-01-20 | Network init |
| NWTOC.BAT | v5.0 | 2026-03-16 | Download updates from network |
| CTONW.BAT | v5.0 | 2026-03-28 | Upload test data (5 steps with echo) |
| CTONWTXT.BAT | v2.3 | 2026-03-28 | Upload Stage TXT files (no MD, dirs pre-created) |
| CHECKUPD.BAT | v1.3 | 2026-01-20 | Check for updates |
| UPDATE.BAT | v2.3 | 2026-01-20 | Full system backup |
| STAGE.BAT | v1.0 | Original | Stage system file updates |
| DEPLOY.BAT | v1.0 | 2026-01-20 | One-time deployment installer |
### DOS 6.22 Compatibility Rules
- NO `IF NOT` -- unreliable on DOS 6.22. Use positive `IF EXIST` with GOTO
- NO `IF /I` (case-insensitive compare)
- NO `FOR /F` loops
- NO `%COMPUTERNAME%` -- use `%MACHINE%` (set during DEPLOY)
- `XCOPY /D` requires date parameter (`/D:mm-dd-yy`)
- `MD` fails with error on existing directories -- pre-create dirs server-side
- `COPY` without `/Y` hangs on overwrite prompts
- All paths UPPERCASE for Samba compatibility
- Line endings MUST be CRLF (0D 0A)
--- ---
**Last Updated:** 2026-03-22 ## Serial Number Encoding (DOS 8.3 filenames)
QuickBASIC ATE encodes long serial numbers for 8.3 filenames:
```
First 2 digits replaced with hex letter if serial too long:
178236-12 -> H8236-12.TXT (17 -> H, charCode 72 - 55 = 17)
10819-1 -> A819-1.TXT (10 -> A, charCode 65 - 55 = 10)
Decode: letter.charCodeAt(0) - 55 = numeric prefix
Only applies when filename starts with [A-Z] followed by digits.
H-prefix files have decoded SN inside the file (SN: 178236-12)
A-prefix files have encoded SN inside the file (SN: A819-1) -- must decode to 10819-1
```
---
## Test Datasheet Pipeline
### 5-Stage Architecture
1. **DOS Test Programs** -> Write DAT files to C:\ATE\*LOG\ and TXT to C:\STAGE\
2. **Boot Upload** -> CTONW.BAT copies DAT to T:\%MACHINE%\LOGS\, CTONWTXT copies TXT to T:\STAGE\%MACHINE%
3. **NAS <-> AD2 Sync** -> Rsync every 15 min (Sync-FromNAS.ps1 scheduled task)
4. **TestDataDB Import** -> import.js parses DAT into SQLite; export-datasheets.js generates TXT to X:\For_Web
5. **Web Share** -> X:\For_Web\ holds validated datasheets (501K+ files)
### import-all-stage.js (ready to run)
Located at `C:\Shares\testdatadb\import-all-stage.js`. Processes ~8,100 TXT files:
- Scans \\D2TESTNAS\test\STAGE\TS-*\*.TXT
- Decodes hex-prefix serial numbers
- Cross-references testdata.db by (serial_number, model_number)
- Inserts missing records as log_type='SHT'
- Copies to X:\For_Web\{decoded_serial}.TXT
```
cd C:\Shares\testdatadb
node import-all-stage.js
```
### Machine data volumes in STAGE
| Machine | Files |
|---------|-------|
| TS-4L | 3,082 |
| TS-4R | 2,741 |
| TS-1R | 509 |
| TS-8R | 478 |
| TS-3R | 435 |
| TS-11R | 325 |
| TS-8L | 285 |
| TS-11L | 248 |
| TS-27 | 10 (already imported) |
| TS-1L | 1 |
### Web Share Layout (X:\)
- X:\For_Web -- Validated datasheets (production)
- X:\For_Web_PDF -- PDF versions (4.7K files)
- X:\Test_Datasheets -- Incoming/staging
- X:\Bad_Datasheets -- Invalid files (18K)
- X:\Datasheets_Log -- Processing logs
---
## Known Issues & Pending Work
### HIGH PRIORITY
1. **Run import-all-stage.js** -- 8,100 TXT files need cross-referencing and ingestion
2. **Website Upload Replacement** -- Old ASP.NET endpoints (Uploader.aspx) return 404. Need new approach.
3. **7B Series Datasheets** -- ~830K records can't generate datasheets (missing 7BMAIN.DAT spec file). Check ENGR share.
4. **Service Permissions** -- testdatadb runs as SYSTEM, causing file permission issues. Change to INTRANET\sysadmin.
### MEDIUM PRIORITY
5. **C2 IP Blocking** -- iptables rules added to UDM for 80.76.49.18 and 45.88.91.99. Need permanent rules in UniFi UI.
6. **MFA Enforcement** -- 19/38 users ready. Report-only until April 4, 2026. Monitor registration.
7. **Joel Lohr Account** -- Retiring March 31. Disable account post-retirement. Auto-reply set to Dan Center.
---
## Security Incident (2026-03-27)
**DF-JOEL2 (192.168.0.143) compromised via phishing:**
- Joel Lohr clicked phishing link in personal Yahoo email
- ScreenConnect C2 installed, "Angel Raya" connected remotely
- Two C2 backdoors deployed via PowerShell
- C2 IPs: 80.76.49.18, 45.88.91.99 (AS399486, suspended by host)
- IC3 Complaint: 1c32ade367084be9acd548f23705736f
- ConnectWise Case: 03464184
- **Remediation complete:** IPs blocked, 3 rogue clients removed, password reset, sessions revoked
- **No lateral movement detected** (32 machines scanned clean)
---
## Key Contacts
| Person | Email | Role |
|--------|-------|------|
| John Lehman | jlehman@dataforth.com | Engineering, QB code, test specs |
| Dan Center | dcenter@dataforth.com | Operations (replacing Joel) |
| Peter Iliya | pIliya@dataforth.com | Applications Engineer |
| AJ | dataforthgit@... | Engineering contact |
| Ken Hoffman | (unresponsive) | TestDataSheetUploader author |
| Georg Haubner | ghaubner@dataforth.com | Has pre-crypto backup on D: drive |
---
## Quick Reference Commands
```powershell
# Check BAT files on NAS
ssh root@192.168.0.9 'ls -la /data/test/COMMON/ProdSW/'
# Trigger NAS sync
Start-ScheduledTask -TaskName 'Sync-FromNAS'
# Check sync log
Get-Content 'C:\Shares\test\scripts\sync-from-nas.log' -Tail 20
# Check TestDataDB health
curl http://localhost:3000/health
# Query test records
node -e "const db=require('better-sqlite3')('C:\\Shares\\testdatadb\\database\\testdata.db',{readonly:true});console.log(db.prepare('SELECT COUNT(*) as cnt FROM test_records').get())"
# Check Stage files on NAS
ssh root@192.168.0.9 'find /data/test/STAGE -name "*.TXT" | wc -l'
```
---
**Last Updated:** 2026-03-29

View File

@@ -0,0 +1,68 @@
# Stage TXT Import Task
# Date: 2026-03-28
# Context: CTONWTXT.BAT now uploads C:\STAGE\*.TXT from DOS machines to T:\STAGE\%MACHINE%\
## What happened
1. CTONWTXT.BAT was never being called -- fixed, now called from CTONW.BAT on every boot
2. Destination changed from broken X: (Novell serve.sys check) to T:\STAGE\%MACHINE%\
3. DOS 6.22 can't MD on existing dirs without error, so dirs are pre-created on NAS
4. All TS-* machine folders pre-created under /data/test/STAGE/ on D2TESTNAS
## What needs to run
Save the script below as C:\Shares\testdatadb\import-all-stage.js and run it:
cd C:\Shares\testdatadb
node import-all-stage.js
## What it does
- Scans \\D2TESTNAS\test\STAGE\TS-*\*.TXT (~8,100 files across 10 machines)
- Parses each TXT datasheet (Date, Model, SN)
- Decodes hex-prefix serial numbers for 8.3 filename encoding:
- Letter prefix = hex digit: A=10, B=11, C=12, ..., H=17, etc.
- Example: H8236-12.TXT has SN: 178236-12 inside the file
- Example: A819-1.TXT has SN: A819-1 inside -> decoded to 10819-1
- The SN line inside H-prefix files already has the full numeric serial
- The SN line inside A-prefix files still has the encoded serial
- Cross-references against testdata.db by (serial_number, model_number)
- Inserts MISSING records as log_type='SHT' with test_station from folder name
- Copies ALL files to X:\For_Web\{decoded_serial}.TXT (the web share)
## Machines with data
TS-4L: 3,082 files (largest)
TS-4R: 2,741 files
TS-1R: 509 files
TS-8R: 478 files
TS-3R: 435 files
TS-11R: 325 files
TS-8L: 285 files
TS-11L: 248 files
TS-27: 10 files (already imported this session)
TS-1L: 1 file
## Serial number encoding (8.3 filename scheme)
The QuickBASIC ATE software encodes long serial numbers to fit DOS 8.3 filenames.
The first two digits get replaced with a hex letter if the serial is too long:
178236-12 -> H8236-12.TXT (17 -> H, which is char code 72, 72-55=17)
10819-1 -> A819-1.TXT (10 -> A, which is char code 65, 65-55=10)
Decode: letter.charCodeAt(0) - 55 = numeric prefix
Only applies if filename starts with [A-Z] followed by digits.
## TS-27 already done
10 files from TS-27 were already imported earlier this session into the DB as SHT records.
The import script uses INSERT OR REPLACE so re-running is safe.
## Previous CTONWTXT.BAT issues (resolved)
- v1.0: Never called, checked for Novell serve.sys, used X: drive parameter
- v2.0: Called from CTONW, but used mixed-case "Stage" path -> failed on DOS
- v2.1: All uppercase STAGE, but had MD commands that fail on existing dirs
- v2.2: Same issue
- v2.3: Removed MD entirely, dirs pre-created on NAS. CURRENT VERSION.

View File

@@ -0,0 +1,80 @@
Subject: Test Datasheets - Weekend Update: All 73 Quatronix Sheets Generated, Work Order Search Live
John, Ken,
Quick update on progress since Friday's email. The pipeline is significantly further along.
## Quatronix Customer Issue - RESOLVED
All 73 requested datasheets have been generated (TXT + PDF). The last holdout was SCM5B49-05 (SN 177000-15) — the 5B49DATA.DAT spec file was empty, but John pointed us to 5B49_2.DAT which had the data. All 73 files are ready to send to Peter/Ginger.
## Model Spec Coverage Expanded
We went from 751 model specs to 1,470+ by loading additional spec databases:
| Spec File | Family | Models |
|-----------|--------|--------|
| 5BMAIN.DAT | SCM5B | 481 |
| 5B45DATA.DAT | SCM5B (freq/counter) | 56 |
| DB5B48.DAT | SCM5B (multi-bandwidth) | 3 |
| 5B49_2.DAT | SCM5B (sample & hold) | 15 |
| 8BMAIN.DAT | 8B | 148 |
| DSCOUT.DAT | DSCA (output) | 23 |
| DSCMAIN4.DAT | DSCA (input) | 391 |
| SCTMAIN.DAT | DSCT | 103 |
| 7BMAIN.DAT | SCM7B | 276 |
If there are additional spec files we're missing, let me know the paths and we'll add them.
## SCM7B Support Added
The 7B product family is now fully supported in the datasheet generator:
- 31 test parameters (vs 20 for SCM5B)
- Correct header ("SCM" prefix prepended to model name)
- 120VAC Withstand / Hi-Pot (skipped for 7BPT models)
- "Packing Check List" with blank fields (vs pre-marked checkboxes on 5B/8B)
- "Tested by" and "QC" signature lines
- Note: The 7B DAT format (single CSV line) doesn't include individual accuracy test points, so the accuracy table is omitted. Only the Final Test Results section is generated from DAT data.
## Work Order Search & Linking
Imported all 33,745 work order status reports from the test station Reports folders:
- 63,263 individual test lines parsed (serial number, model, pass/fail, date/time, station)
- 2.27 million test records linked to their work orders
In the web app (http://192.168.0.6:3000):
- New "Work Order #" search field — enter a WO number to find all associated test records
- Click the WO number in any record's detail view to see the full work order:
- All serial numbers tested under that WO
- Pass/fail status for each (including retests)
- Test program and version used
- Test station and timestamps
- New work order reports are automatically imported when synced from the NAS
## Datasheet Formatting Refined
Compared generated datasheets against originals from the DFWDS archive and fixed column alignment to match the QuickBASIC output:
- TAB positions match exactly (parameter names, measured values, spec limits, pass/fail)
- Number formatting matches QB PRINT USING (right-justified, correct decimal places)
- STR$() behavior replicated (leading space for positive numbers, dropped leading zeros)
- Spec limit formatting matches (e.g., "+/- .03 %" not "+/- 0.03 %")
## View Button Updated
The "SHEET" button in the web app now shows a styled HTML page that matches the PDF/TXT layout — white page, monospace font, same column alignment. Includes Print and Download PDF buttons.
## Infrastructure
- Created domain service account (INTRANET\svc_testdatadb) for the TestDataDB Windows service — resolves the file permission issues we were hitting
- Added STAGE folder sync to the NAS sync script — TXT datasheets from DOS machines will now be pulled to AD2 automatically
- Work order report import added to sync script — new reports are ingested automatically every 15 minutes
## Still Open
1. **Website upload** — The old Uploader.aspx endpoints are dead. Need to determine the new upload mechanism for dataforth.com.
2. **STAGE backlog** — ~8,100 TXT files on the NAS from DOS machines need to be processed (script ready, haven't run it yet).
3. **Pending ForWeb export** — ~845K records in the database don't have TXT files in For_Web yet (mostly 7B and older records). Can batch-export as needed.
Let me know if you need anything else.
Mike

View File

@@ -0,0 +1,88 @@
<#
.SYNOPSIS
Configures PowerShell transcript logging for remote sessions.
.DESCRIPTION
Enables comprehensive transcript logging via registry settings,
creates the logging directory with proper permissions, and sets up
automatic log rotation.
.NOTES
Author: ClaudeTools Automation
Version: 1.0
Run as Administrator
#>
$ErrorActionPreference = 'Stop'
$transcriptPath = "C:\ClaudeTools\Logs\Transcripts"
Write-Host "Configuring PowerShell Transcript Logging..." -ForegroundColor Cyan
# Create transcript directory
if (-not (Test-Path $transcriptPath)) {
New-Item -ItemType Directory -Path $transcriptPath -Force | Out-Null
Write-Host "Created transcript directory: $transcriptPath" -ForegroundColor Green
}
# Set permissions on transcript directory
# Administrators: Full Control, SYSTEM: Full Control, Remote Management Users: Read/Write
$acl = Get-Acl $transcriptPath
$acl.SetAccessRuleProtection($true, $false) # Disable inheritance
# Add Administrators - Full Control
$adminRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
"Administrators", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
)
$acl.AddAccessRule($adminRule)
# Add SYSTEM - Full Control
$systemRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
"SYSTEM", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
)
$acl.AddAccessRule($systemRule)
# Add Remote Management Users - Modify (so they can write transcripts)
$rmRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
"Remote Management Users", "Modify", "ContainerInherit,ObjectInherit", "None", "Allow"
)
$acl.AddAccessRule($rmRule)
Set-Acl $transcriptPath $acl
Write-Host "Set permissions on transcript directory" -ForegroundColor Green
# Configure PowerShell transcript logging via registry
$psPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription"
if (-not (Test-Path $psPath)) {
New-Item -Path $psPath -Force | Out-Null
}
# Enable transcription
Set-ItemProperty -Path $psPath -Name "EnableTranscripting" -Value 1 -Type DWord
Set-ItemProperty -Path $psPath -Name "EnableInvocationHeader" -Value 1 -Type DWord
Set-ItemProperty -Path $psPath -Name "OutputDirectory" -Value $transcriptPath -Type String
Write-Host "Enabled PowerShell transcription via registry" -ForegroundColor Green
# Also enable module logging for additional audit trail
$modulePath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging"
if (-not (Test-Path $modulePath)) {
New-Item -Path $modulePath -Force | Out-Null
}
Set-ItemProperty -Path $modulePath -Name "EnableModuleLogging" -Value 1 -Type DWord
# Enable script block logging
$scriptPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
if (-not (Test-Path $scriptPath)) {
New-Item -Path $scriptPath -Force | Out-Null
}
Set-ItemProperty -Path $scriptPath -Name "EnableScriptBlockLogging" -Value 1 -Type DWord
Write-Host "Enabled module and script block logging" -ForegroundColor Green
Write-Host "`nTranscript logging configuration complete!" -ForegroundColor Green
Write-Host "Transcripts will be saved to: $transcriptPath"
# Display current settings
Write-Host "`n--- Current Settings ---" -ForegroundColor Yellow
Get-ItemProperty -Path $psPath | Select-Object EnableTranscripting, EnableInvocationHeader, OutputDirectory

View File

@@ -0,0 +1,87 @@
<#
.SYNOPSIS
Generates a report of all Active Directory computers.
.DESCRIPTION
This script queries Active Directory for all computer accounts and exports
key properties including name, operating system, last logon, and OU location.
.PARAMETER OutputPath
Optional. Path to export CSV report. If not specified, outputs to console.
.PARAMETER OperatingSystem
Optional. Filter by operating system (e.g., "Windows Server*", "*Windows 10*").
.EXAMPLE
.\Get-ADComputerReport.ps1
Lists all computers to console.
.EXAMPLE
.\Get-ADComputerReport.ps1 -OperatingSystem "Windows Server*" -OutputPath "C:\ClaudeTools\Logs\servers.csv"
Exports all Windows Server computers to CSV.
.NOTES
Author: ClaudeTools Automation
Version: 1.0
Requires: ActiveDirectory PowerShell module
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$OutputPath,
[Parameter(Mandatory=$false)]
[string]$OperatingSystem = "*"
)
# Import AD module
Import-Module ActiveDirectory -ErrorAction Stop
Write-Host "Querying Active Directory computers..." -ForegroundColor Cyan
# Get computers with properties
$computers = Get-ADComputer -Filter "OperatingSystem -like '$OperatingSystem'" -Properties `
OperatingSystem,
OperatingSystemVersion,
LastLogonDate,
Created,
Enabled,
IPv4Address,
Description,
DistinguishedName |
Select-Object `
@{N='Name';E={$_.Name}},
@{N='OperatingSystem';E={$_.OperatingSystem}},
@{N='OSVersion';E={$_.OperatingSystemVersion}},
@{N='Enabled';E={$_.Enabled}},
@{N='IPv4Address';E={$_.IPv4Address}},
@{N='LastLogon';E={$_.LastLogonDate}},
@{N='Created';E={$_.Created}},
@{N='OU';E={($_.DistinguishedName -split ',',2)[1]}},
@{N='Description';E={$_.Description}}
$computerCount = ($computers | Measure-Object).Count
Write-Host "Found $computerCount computers." -ForegroundColor Green
if ($OutputPath) {
$computers | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "Report exported to: $OutputPath" -ForegroundColor Green
} else {
$computers | Format-Table -AutoSize
}
# Summary by OS
Write-Host "`n--- Operating System Summary ---" -ForegroundColor Yellow
$computers | Group-Object OperatingSystem | Sort-Object Count -Descending |
Format-Table @{N='Operating System';E={$_.Name}}, Count -AutoSize
# Summary by status
$enabledCount = ($computers | Where-Object { $_.Enabled -eq $true } | Measure-Object).Count
$disabledCount = ($computers | Where-Object { $_.Enabled -eq $false } | Measure-Object).Count
Write-Host "Enabled: $enabledCount | Disabled: $disabledCount"
# Stale computers (no logon in 90 days)
$staleDate = (Get-Date).AddDays(-90)
$staleCount = ($computers | Where-Object { $_.LastLogon -lt $staleDate -or $null -eq $_.LastLogon } | Measure-Object).Count
Write-Host "Stale (no logon 90+ days): $staleCount" -ForegroundColor $(if ($staleCount -gt 0) { 'Yellow' } else { 'Green' })

View File

@@ -0,0 +1,92 @@
<#
.SYNOPSIS
Generates a report of all Active Directory users with key properties.
.DESCRIPTION
This script queries Active Directory for all user accounts and exports
key properties including name, email, last logon, account status, and group memberships.
.PARAMETER OutputPath
Optional. Path to export CSV report. If not specified, outputs to console.
.PARAMETER IncludeDisabled
Switch to include disabled accounts in the report.
.EXAMPLE
.\Get-ADUserReport.ps1
Lists all enabled users to console.
.EXAMPLE
.\Get-ADUserReport.ps1 -OutputPath "C:\ClaudeTools\Logs\users.csv" -IncludeDisabled
Exports all users (including disabled) to CSV file.
.NOTES
Author: ClaudeTools Automation
Version: 1.0
Requires: ActiveDirectory PowerShell module
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$OutputPath,
[Parameter(Mandatory=$false)]
[switch]$IncludeDisabled
)
# Import AD module
Import-Module ActiveDirectory -ErrorAction Stop
Write-Host "Querying Active Directory users..." -ForegroundColor Cyan
# Build filter
$filter = if ($IncludeDisabled) { "*" } else { "Enabled -eq 'True'" }
# Get users with properties
$users = Get-ADUser -Filter $filter -Properties `
DisplayName,
EmailAddress,
Department,
Title,
Manager,
LastLogonDate,
PasswordLastSet,
PasswordNeverExpires,
Enabled,
Created,
MemberOf,
Description |
Select-Object `
@{N='SamAccountName';E={$_.SamAccountName}},
@{N='DisplayName';E={$_.DisplayName}},
@{N='Email';E={$_.EmailAddress}},
@{N='Department';E={$_.Department}},
@{N='Title';E={$_.Title}},
@{N='Enabled';E={$_.Enabled}},
@{N='LastLogon';E={$_.LastLogonDate}},
@{N='PasswordLastSet';E={$_.PasswordLastSet}},
@{N='PasswordNeverExpires';E={$_.PasswordNeverExpires}},
@{N='Created';E={$_.Created}},
@{N='GroupCount';E={($_.MemberOf | Measure-Object).Count}},
@{N='Description';E={$_.Description}}
$userCount = ($users | Measure-Object).Count
Write-Host "Found $userCount users." -ForegroundColor Green
if ($OutputPath) {
$users | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "Report exported to: $OutputPath" -ForegroundColor Green
} else {
$users | Format-Table -AutoSize
}
# Summary statistics
Write-Host "`n--- Summary ---" -ForegroundColor Yellow
Write-Host "Total Users: $userCount"
$enabledCount = ($users | Where-Object { $_.Enabled -eq $true } | Measure-Object).Count
$disabledCount = ($users | Where-Object { $_.Enabled -eq $false } | Measure-Object).Count
Write-Host "Enabled: $enabledCount"
Write-Host "Disabled: $disabledCount"
$neverExpire = ($users | Where-Object { $_.PasswordNeverExpires -eq $true } | Measure-Object).Count
Write-Host "Password Never Expires: $neverExpire"

111
scripts/Get-GPOStatus.ps1 Normal file
View File

@@ -0,0 +1,111 @@
<#
.SYNOPSIS
Reports on Group Policy Object status and replication.
.DESCRIPTION
This script checks all GPOs in the domain and reports their status,
including version information, links, and replication status between
AD and SYSVOL.
.PARAMETER OutputPath
Optional. Path to export CSV report. If not specified, outputs to console.
.PARAMETER CheckReplication
Switch to perform detailed replication check between AD and SYSVOL.
.EXAMPLE
.\Get-GPOStatus.ps1
Lists all GPOs with basic status.
.EXAMPLE
.\Get-GPOStatus.ps1 -CheckReplication -OutputPath "C:\ClaudeTools\Logs\gpo-status.csv"
Full replication check with CSV export.
.NOTES
Author: ClaudeTools Automation
Version: 1.0
Requires: GroupPolicy PowerShell module
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$OutputPath,
[Parameter(Mandatory=$false)]
[switch]$CheckReplication
)
# Import required modules
Import-Module GroupPolicy -ErrorAction Stop
Import-Module ActiveDirectory -ErrorAction Stop
Write-Host "Querying Group Policy Objects..." -ForegroundColor Cyan
# Get all GPOs
$gpos = Get-GPO -All | Select-Object `
@{N='Name';E={$_.DisplayName}},
@{N='ID';E={$_.Id}},
@{N='Status';E={$_.GpoStatus}},
@{N='CreationTime';E={$_.CreationTime}},
@{N='ModificationTime';E={$_.ModificationTime}},
@{N='UserVersion';E={$_.User.DSVersion}},
@{N='ComputerVersion';E={$_.Computer.DSVersion}},
@{N='WMIFilter';E={$_.WmiFilter.Name}}
$gpoCount = ($gpos | Measure-Object).Count
Write-Host "Found $gpoCount GPOs." -ForegroundColor Green
# Check GPO links
Write-Host "`nChecking GPO links..." -ForegroundColor Cyan
$gpoLinks = @()
foreach ($gpo in (Get-GPO -All)) {
$report = [xml](Get-GPOReport -Guid $gpo.Id -ReportType Xml)
$links = $report.GPO.LinksTo.SOMPath
$gpoLinks += [PSCustomObject]@{
Name = $gpo.DisplayName
LinkCount = if ($links) { ($links | Measure-Object).Count } else { 0 }
Links = if ($links) { $links -join "; " } else { "Not Linked" }
}
}
if ($CheckReplication) {
Write-Host "`nChecking SYSVOL replication status..." -ForegroundColor Cyan
$domain = (Get-ADDomain).DNSRoot
$dcs = Get-ADDomainController -Filter *
foreach ($dc in $dcs) {
Write-Host " Checking $($dc.HostName)..." -ForegroundColor Gray
$sysvolPath = "\\$($dc.HostName)\SYSVOL\$domain\Policies"
if (Test-Path $sysvolPath) {
$sysvolGPOs = Get-ChildItem $sysvolPath -Directory | Where-Object { $_.Name -match '^{' }
Write-Host " SYSVOL GPO count: $($sysvolGPOs.Count)" -ForegroundColor Green
} else {
Write-Host " Unable to access SYSVOL" -ForegroundColor Red
}
}
}
# Output results
if ($OutputPath) {
$gpos | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "`nReport exported to: $OutputPath" -ForegroundColor Green
} else {
Write-Host "`n--- GPO List ---" -ForegroundColor Yellow
$gpos | Format-Table Name, Status, ModificationTime, UserVersion, ComputerVersion -AutoSize
Write-Host "`n--- GPO Links ---" -ForegroundColor Yellow
$gpoLinks | Format-Table Name, LinkCount, Links -AutoSize
}
# Summary
Write-Host "`n--- Summary ---" -ForegroundColor Yellow
Write-Host "Total GPOs: $gpoCount"
$unlinked = ($gpoLinks | Where-Object { $_.LinkCount -eq 0 } | Measure-Object).Count
Write-Host "Unlinked GPOs: $unlinked" -ForegroundColor $(if ($unlinked -gt 0) { 'Yellow' } else { 'Green' })
$disabled = ($gpos | Where-Object { $_.Status -ne 'AllSettingsEnabled' } | Measure-Object).Count
Write-Host "Disabled/Partial GPOs: $disabled" -ForegroundColor $(if ($disabled -gt 0) { 'Yellow' } else { 'Green' })

View File

@@ -0,0 +1,173 @@
<#
.SYNOPSIS
Checks Active Directory replication health across domain controllers.
.DESCRIPTION
This script performs comprehensive AD replication health checks including
replication status, partner connectivity, and identifies any replication failures.
.PARAMETER OutputPath
Optional. Path to export results. If not specified, outputs to console.
.PARAMETER Detailed
Switch to show detailed replication information per DC.
.EXAMPLE
.\Get-ReplicationHealth.ps1
Basic replication health check.
.EXAMPLE
.\Get-ReplicationHealth.ps1 -Detailed -OutputPath "C:\ClaudeTools\Logs\repl-health.txt"
Detailed check with output to file.
.NOTES
Author: ClaudeTools Automation
Version: 1.0
Requires: ActiveDirectory PowerShell module, repadmin.exe
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$OutputPath,
[Parameter(Mandatory=$false)]
[switch]$Detailed
)
# Import AD module
Import-Module ActiveDirectory -ErrorAction Stop
$output = @()
$output += "=" * 60
$output += "AD REPLICATION HEALTH REPORT"
$output += "Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
$output += "=" * 60
Write-Host "Checking AD Replication Health..." -ForegroundColor Cyan
# Get all DCs
$dcs = Get-ADDomainController -Filter *
$output += "`nDomain Controllers Found: $($dcs.Count)"
foreach ($dc in $dcs) {
$output += "`n--- $($dc.HostName) ---"
Write-Host "Checking $($dc.HostName)..." -ForegroundColor Gray
}
# Check replication summary using repadmin
$output += "`n" + "=" * 60
$output += "REPLICATION SUMMARY (repadmin /replsummary)"
$output += "=" * 60
try {
$replSummary = repadmin /replsummary 2>&1
$output += $replSummary
Write-Host "Replication summary retrieved." -ForegroundColor Green
} catch {
$output += "ERROR: Unable to run repadmin /replsummary"
Write-Host "Error running repadmin" -ForegroundColor Red
}
# Check for replication failures
$output += "`n" + "=" * 60
$output += "REPLICATION FAILURES (repadmin /showrepl * /errorsonly)"
$output += "=" * 60
try {
$replErrors = repadmin /showrepl * /errorsonly 2>&1
if ($replErrors -match "error" -or $replErrors -match "fail") {
$output += $replErrors
Write-Host "Replication ERRORS detected!" -ForegroundColor Red
} else {
$output += "No replication errors detected."
Write-Host "No replication errors." -ForegroundColor Green
}
} catch {
$output += "ERROR: Unable to check replication errors"
}
# Queue length
$output += "`n" + "=" * 60
$output += "REPLICATION QUEUE (repadmin /queue)"
$output += "=" * 60
try {
$replQueue = repadmin /queue 2>&1
$output += $replQueue
} catch {
$output += "ERROR: Unable to check replication queue"
}
if ($Detailed) {
$output += "`n" + "=" * 60
$output += "DETAILED REPLICATION STATUS (repadmin /showrepl)"
$output += "=" * 60
try {
$replDetail = repadmin /showrepl 2>&1
$output += $replDetail
} catch {
$output += "ERROR: Unable to get detailed replication status"
}
# DFSR Health (if applicable)
$output += "`n" + "=" * 60
$output += "DFSR SYSVOL REPLICATION STATUS"
$output += "=" * 60
try {
$dfsrStatus = Get-DfsrMember -ErrorAction SilentlyContinue
if ($dfsrStatus) {
$output += "DFSR Members:"
foreach ($member in $dfsrStatus) {
$output += " - $($member.ComputerName): $($member.DomainName)"
}
} else {
$output += "DFSR not configured or FRS in use."
}
} catch {
$output += "Unable to query DFSR status (may be using FRS)"
}
}
# AD Database health
$output += "`n" + "=" * 60
$output += "AD DATABASE INTEGRITY"
$output += "=" * 60
$adDb = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" -ErrorAction SilentlyContinue
if ($adDb) {
$dbPath = $adDb.'DSA Database file'
$logPath = $adDb.'Database log files path'
$output += "Database Path: $dbPath"
$output += "Log Path: $logPath"
if (Test-Path $dbPath) {
$dbSize = (Get-Item $dbPath).Length / 1MB
$output += "Database Size: $([math]::Round($dbSize, 2)) MB"
}
}
# Final summary
$output += "`n" + "=" * 60
$output += "HEALTH CHECK COMPLETE"
$output += "=" * 60
# Output results
if ($OutputPath) {
$output | Out-File -FilePath $OutputPath -Encoding UTF8
Write-Host "`nReport saved to: $OutputPath" -ForegroundColor Green
} else {
$output | ForEach-Object { Write-Host $_ }
}
# Quick status summary
Write-Host "`n--- Quick Status ---" -ForegroundColor Yellow
Write-Host "Domain Controllers: $($dcs.Count)"
$errorMatch = $replErrors -match "error|fail"
if ($errorMatch) {
Write-Host "Replication Status: ERRORS DETECTED" -ForegroundColor Red
} else {
Write-Host "Replication Status: HEALTHY" -ForegroundColor Green
}

View File

@@ -0,0 +1,107 @@
<#
.SYNOPSIS
Rotates and cleans up old log files.
.DESCRIPTION
Removes transcript and log files older than the specified retention period.
Designed to run as a scheduled task daily.
.PARAMETER RetentionDays
Number of days to retain log files. Default is 30.
.PARAMETER LogPath
Path to the logs directory. Default is C:\ClaudeTools\Logs.
.PARAMETER WhatIf
Shows what would be deleted without actually deleting.
.EXAMPLE
.\Invoke-LogRotation.ps1
Removes logs older than 30 days.
.EXAMPLE
.\Invoke-LogRotation.ps1 -RetentionDays 14 -WhatIf
Shows what would be deleted with 14-day retention.
.NOTES
Author: ClaudeTools Automation
Version: 1.0
#>
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory=$false)]
[int]$RetentionDays = 30,
[Parameter(Mandatory=$false)]
[string]$LogPath = "C:\ClaudeTools\Logs"
)
$rotationLog = Join-Path $LogPath "rotation.log"
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
function Write-Log {
param([string]$Message)
$logEntry = "[$timestamp] $Message"
Add-Content -Path $rotationLog -Value $logEntry
Write-Host $logEntry
}
Write-Log "=== Log Rotation Started ==="
Write-Log "Retention Period: $RetentionDays days"
Write-Log "Log Path: $LogPath"
$cutoffDate = (Get-Date).AddDays(-$RetentionDays)
$totalDeleted = 0
$totalSizeFreed = 0
# Find and delete old files
$oldFiles = Get-ChildItem -Path $LogPath -Recurse -File |
Where-Object { $_.LastWriteTime -lt $cutoffDate -and $_.Name -ne "rotation.log" }
$fileCount = ($oldFiles | Measure-Object).Count
Write-Log "Found $fileCount files older than $RetentionDays days"
foreach ($file in $oldFiles) {
$fileSize = $file.Length
$filePath = $file.FullName
if ($PSCmdlet.ShouldProcess($filePath, "Delete")) {
try {
Remove-Item $filePath -Force
$totalDeleted++
$totalSizeFreed += $fileSize
Write-Log "Deleted: $filePath ($([math]::Round($fileSize/1KB, 2)) KB)"
} catch {
Write-Log "ERROR deleting $filePath : $_"
}
} else {
Write-Log "WhatIf: Would delete $filePath ($([math]::Round($fileSize/1KB, 2)) KB)"
}
}
# Delete empty subdirectories
$emptyDirs = Get-ChildItem -Path $LogPath -Directory -Recurse |
Where-Object { (Get-ChildItem $_.FullName -Force).Count -eq 0 }
foreach ($dir in $emptyDirs) {
if ($PSCmdlet.ShouldProcess($dir.FullName, "Remove empty directory")) {
try {
Remove-Item $dir.FullName -Force
Write-Log "Removed empty directory: $($dir.FullName)"
} catch {
Write-Log "ERROR removing directory $($dir.FullName) : $_"
}
}
}
# Summary
$sizeMB = [math]::Round($totalSizeFreed / 1MB, 2)
Write-Log "=== Rotation Complete ==="
Write-Log "Files Deleted: $totalDeleted"
Write-Log "Space Freed: $sizeMB MB"
# Show current disk usage
$currentSize = (Get-ChildItem -Path $LogPath -Recurse -File | Measure-Object -Property Length -Sum).Sum
$currentSizeMB = [math]::Round($currentSize / 1MB, 2)
Write-Log "Current Log Directory Size: $currentSizeMB MB"

View File

@@ -0,0 +1,177 @@
# Session Log - AD2 - 2026-04-03
## Session Summary
Continued test datasheet pipeline work from the 03-27/28/29 session. Major focus on:
1. Fixing formatting issues in generated TXT datasheets (column alignment matching QuickBASIC)
2. Adding 7B product family support to the exact-match formatter
3. Loading additional spec files (5B49_2.DAT for the last missing Quatronix datasheet)
4. Work order report ingestion (33K WOs, 63K lines, 2.27M records linked)
5. UI improvements (WO search, WO detail popup, View button styled HTML)
6. Generating full Dataforth audit document
7. Planning and beginning PostgreSQL migration (SQLite hitting 4.4GB, queries timing out)
8. Uninstalling SQL Server Express, installing PostgreSQL 18
## Key Decisions
- PostgreSQL over SQL Server Express (no 10GB limit, better FTS, no licensing)
- Install PG locally on AD2 (not SAGE-SQL or new VM)
- Clean cutover (no parallel run with SQLite)
- MSSQL Express uninstalled to free resources
## Credentials
### PostgreSQL (newly installed)
- Host: localhost (AD2, 192.168.0.6)
- Port: 5432
- Superuser: postgres / DfPgSQL2026!
- App role: testdatadb_app / DfTestDB2026!
- Database: testdatadb
- Service: postgresql-18 (runs as INTRANET\sysadmin)
- Install path: C:\Program Files\PostgreSQL\18\
- Data dir: C:\Program Files\PostgreSQL\18\data\
### TestDataDB (existing)
- Service: testdatadb (runs as INTRANET\svc_testdatadb / DfSvcTDB2026!)
- URL: http://192.168.0.6:3000
- SQLite DB: C:\Shares\testdatadb\database\testdata.db (4.4 GB)
### Existing (from CLAUDE.md)
- AD Sysadmin: INTRANET\sysadmin / Paper123!@#
- D2TESTNAS SSH: root@192.168.0.9 / Paper123!@#-nas
- Rsync: port 873, user rsync / IQ203s32119
- M365 Tenant: 7dfa3ce8-c496-4b51-ab8d-bd3dcd78b584
- Gitea: mike@azcomputerguru.com / Gptf*77ttb123!@#-git
- Gitea API Token: 9b1da4b79a38ef782268341d25a4b6880572063f
## Work Completed
### Formatting Fixes (datasheet-exact.js)
- Compared generated TXT against originals from X:\For_Web\2025\
- Fixed Final Test Results column alignment to match QB TAB positions:
- TAB(5) param name, TAB(31) measured value, TAB(60-speclen) spec, TAB(61) unit, TAB(71) PASS/FAIL
- Added setCol() and padToCol() helpers for exact column positioning
- Fixed STR$() emulation: leading space for positive, drops leading zero (.03 not 0.03)
- Fixed header spacing (Date, Model, SN fields)
- Fixed checklist spacing to match QB TAB(45)
- Fixed separator line length (23 chars not 24)
### 7B Product Family Support
- Added SCM7B DATA_LINES (31 parameters vs 20 for SCM5B)
- Added SCM7B TSPECS (supply current, linearity, accuracy, excitation, CJC, noise, etc.)
- Added 7B raw_data parser (single CSV line format vs multi-line for other families)
- 7B-specific footer: 120VAC (not 240), "Packing Check List" (not "Check List"), blank checkmarks, Tested by/QC lines
- Accuracy section suppressed for 7B (DAT format doesn't include individual test points)
- 7B model names prepend "SCM" in header
### Additional Spec File: 5B49_2.DAT
- 5B49DATA.DAT was 0 bytes (empty), John pointed to 5B49_2.DAT
- 15 models, 93 bytes/record, added SCM5B49_FIELDS to spec-reader.js
- Completed final missing Quatronix datasheet (177000-15, SCM5B49-05)
- All 73/73 Quatronix datasheets now generated
### View Button Enhancement
- /api/datasheet/:id now uses exact-match formatter with styled HTML
- White page on gray background, monospace font, print-optimized
- Includes Print and Download PDF buttons
- Falls back to generic template if exact-match not available
### PDF Endpoint Fallback
- /api/datasheet/:id/pdf falls back to generic template when exact-match fails
- Prevents 422 errors for unsupported families
### Work Order Reports
- Created parsers/wo-report.js (parses WO status report TXT format)
- Created database/import-work-orders.js (imports WOs, creates tables, links to test records)
- Created work_orders table (33,745 records) and work_order_lines table (63,263 records)
- Added work_order column to test_records, 2,277,183 records linked via serial number pattern
- Added /api/workorder/:wo and /api/workorder-search endpoints
- Added WO# search field and clickable WO link in UI detail view
- WO detail popup shows all test lines, pass/fail history, program version
- Added auto-import hooks to Sync-FromNAS-rsync.ps1 for Reports and STAGE folders
### Sync Script Updates (Sync-FromNAS-rsync.ps1)
- Added STAGE folder sync (NAS STAGE -> AD2)
- Added $syncedReportFiles and $syncedStageFiles tracking
- Added WO report auto-import after sync
- Added STAGE TXT auto-import after sync
- Updated status file with WO and STAGE counts
### Dataforth Audit Document
- Generated C:\Users\sysadmin\Desktop\Dataforth-Audit-2026-04-02.txt
- 22 sections: company info, network, AD computers/users/groups, GPO, DNS, shares, tasks, services, firewall, credentials, M365, security incidents, manufacturing infrastructure, pipeline, applications, backups, known issues, contacts
### PostgreSQL Migration (IN PROGRESS)
- Plan approved: PostgreSQL 18 on AD2, clean cutover
- PostgreSQL 18.3 installed via Chocolatey
- Database cluster initialized (C:\Program Files\PostgreSQL\18\data\)
- Service registered as postgresql-18 (runs as INTRANET\sysadmin)
- Database created: testdatadb owned by testdatadb_app
- SQL Server Express 2022 uninstalled
### SQLite Issues Documented
- Database grown to 4.4GB
- Single search query took 5,157 seconds (85 minutes)
- Stats query took 216 seconds
- WAL file grew to 454MB
- ANALYZE ran for 30+ minutes without completing
- SHM/WAL permission conflicts between SYSTEM and sysadmin
### Service Account (from previous session, still relevant)
- INTRANET\svc_testdatadb created in OU=ServiceAccounts
- testdatadb Windows service runs under this account
- SeServiceLogonRight granted
- Permissions on C:\Shares\testdatadb and C:\Shares\webshare
## Files Created
- C:\Shares\testdatadb\fix-sysadmin-logon.ps1
- C:\ClaudeTools\Test Datasheets\weekend-update-draft.md
- C:\Users\sysadmin\Desktop\Dataforth-Audit-2026-04-02.txt
- C:\Users\sysadmin\.claude\plans\generic-petting-lovelace.md (PG migration plan)
## Files Modified
- C:\Shares\testdatadb\templates\datasheet-exact.js — Column alignment, 7B support, STR$() emulation
- C:\Shares\testdatadb\parsers\spec-reader.js — Added 5B49 TYPE, fuzzy model matching
- C:\Shares\testdatadb\parsers\wo-report.js — Created (WO report parser)
- C:\Shares\testdatadb\database\import-work-orders.js — Created (WO importer)
- C:\Shares\testdatadb\database\schema.sql — Added work_order column
- C:\Shares\testdatadb\routes\api.js — Added WO endpoints, PDF fallback, view button exact-match
- C:\Shares\testdatadb\public\index.html — WO search, WO popup, view button styling
- C:\Shares\test\scripts\Sync-FromNAS-rsync.ps1 — STAGE sync, WO auto-import
## Database Stats (as of session end)
- Test records: 2,294,877
- Work orders: 33,745
- Work order lines: 63,263
- Records with WO linked: 2,277,183
- ForWeb exported: ~1,436,000
- Model specs loaded: 1,470+
## Pending / Next Steps
1. **PostgreSQL Migration (Step 2-8):**
- Create PG schema (schema-pg.sql) with tsvector FTS
- Create database abstraction layer (db.js)
- Migrate routes/api.js to async
- Migrate import/export scripts
- Build data migration script
- Migrate 2.28M records
- Test and cutover
2. **Tune PostgreSQL config:**
- shared_buffers=1GB, work_mem=64MB, maintenance_work_mem=256MB
3. **MSSQL cleanup:**
- May need reboot to fully remove SQL Server services
4. **Website upload:**
- Old ASP.NET endpoints still dead (404)
- Need to determine new upload mechanism
5. **Joel Lohr account:**
- Retired March 31 — account needs to be disabled
## Infrastructure
- AD2: 192.168.0.6 (Windows Server 2016)
- PostgreSQL 18: localhost:5432 (newly installed, service running)
- TestDataDB: localhost:3000 (SQLite, service running)
- NAS: 192.168.0.9 (rsync port 873)
- STAGE backlog: cleared (0 files remaining)