Compare commits
60 Commits
feature/re
...
2b05bf6130
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b05bf6130 | |||
| afd5eb2a2c | |||
| 4bf151ca7b | |||
| 74890d51ec | |||
| a173c70633 | |||
| d2e375df8a | |||
| 6a135ac111 | |||
| 975adda092 | |||
| 7660cb4a16 | |||
| 5b8813af4d | |||
| c957ef33ef | |||
| 68153cf9b6 | |||
| 273342ee9f | |||
| a80ea236ba | |||
| 3358cecdcc | |||
| fe3b5b0382 | |||
| 0a7f3368a6 | |||
| 3eb621a8b7 | |||
| 4220b8f57c | |||
| 4886c8cc2a | |||
| 5a31946083 | |||
| 71c9ddce9e | |||
| e695743149 | |||
| 5995511011 | |||
| b99f8512e4 | |||
| 68d9836245 | |||
| dd8e45de80 | |||
| 32888ea9d4 | |||
| ac4ceb65c0 | |||
| 392c42710c | |||
| 046175af3a | |||
| 6bb00601b7 | |||
| 996dd515b1 | |||
| f190f7813f | |||
| a3fe1b9a9b | |||
| d13d4e4909 | |||
| 8d975c1b44 | |||
| 6eaba02b71 | |||
| f5acf9f453 | |||
| 8a094529ab | |||
| 6f6a77f8e4 | |||
| 100a491ac6 | |||
| a18157b5fa | |||
| 43c116f0c6 | |||
| ea48061389 | |||
| 232f463325 | |||
| d033dbe8a2 | |||
| 148ac75a25 | |||
| 2937c29f07 | |||
| fdd0bb0c1f | |||
| 5abf9ba670 | |||
| f01d9d5538 | |||
| 733d87f20e | |||
| eae9d7f644 | |||
| dd5c5afd4b | |||
| 72105233a2 | |||
| d0dbfed5ec | |||
| 04bdac0448 | |||
| 7326fbb05c | |||
| c9eba69753 |
347
.claude/AUTO_CONTEXT_SYSTEM.md
Normal file
347
.claude/AUTO_CONTEXT_SYSTEM.md
Normal file
@@ -0,0 +1,347 @@
|
||||
# Automatic Context Loading System
|
||||
|
||||
## The Problem
|
||||
|
||||
Claude instances don't proactively review previous work before starting. User must say "review previous work first" which defeats the purpose of the context recovery system.
|
||||
|
||||
**Example failure:**
|
||||
```
|
||||
User: "Look at the Dataforth DFWDS folders"
|
||||
Claude: "What work have we done on this?" # WRONG - should check CONTEXT.md first
|
||||
```
|
||||
|
||||
## The Solution: Tiered Hint System
|
||||
|
||||
### Tier 1: Quick Hints (CONTEXT.md)
|
||||
- High-level overview (infrastructure, current state, anti-patterns)
|
||||
- Fast to read (~30 seconds)
|
||||
- Points to detailed resources
|
||||
- **Location:** [project-root]/CONTEXT.md
|
||||
|
||||
### Tier 2: Detailed Resources
|
||||
- Recent session logs (full commands, decisions)
|
||||
- Implementation plans, technical specs
|
||||
- Pointed to by CONTEXT.md
|
||||
|
||||
### Tier 3: Deep Archive
|
||||
- Historical session logs
|
||||
- Git history
|
||||
- Full technical documentation
|
||||
|
||||
## Automatic Loading Rules
|
||||
|
||||
### Rule 1: Project Mention Detection
|
||||
|
||||
**When user message contains project keywords, auto-load CONTEXT.md:**
|
||||
|
||||
| Keywords | Load | Read Before Responding |
|
||||
|----------|------|------------------------|
|
||||
| "GuruRMM", "tunnel", "agents", "rmm-api" | projects/msp-tools/guru-rmm/CONTEXT.md | Yes |
|
||||
| "Dataforth", "DFWDS", "testdatadb", "AD2", "VASLOG" | projects/dataforth-dos/CONTEXT.md | Yes |
|
||||
| "ClaudeTools API", "work tracking" | CONTEXT.md (root) | Yes |
|
||||
|
||||
**Implementation:**
|
||||
```python
|
||||
import re
|
||||
|
||||
PROJECT_PATTERNS = {
|
||||
'gururmm': {
|
||||
'keywords': r'\b(GuruRMM|tunnel|rmm-api|gururmm|agent.*status)\b',
|
||||
'context_file': 'projects/msp-tools/guru-rmm/CONTEXT.md',
|
||||
},
|
||||
'dataforth': {
|
||||
'keywords': r'\b(Dataforth|DFWDS|testdatadb|AD2|AD1|VASLOG|SCMVAS|SCMHVAS)\b',
|
||||
'context_file': 'projects/dataforth-dos/CONTEXT.md',
|
||||
},
|
||||
'claudetools': {
|
||||
'keywords': r'\b(ClaudeTools API|work tracking|claudetools database)\b',
|
||||
'context_file': 'CONTEXT.md',
|
||||
},
|
||||
}
|
||||
|
||||
def detect_project(user_message):
|
||||
for project, config in PROJECT_PATTERNS.items():
|
||||
if re.search(config['keywords'], user_message, re.IGNORECASE):
|
||||
return config['context_file']
|
||||
return None
|
||||
```
|
||||
|
||||
### Rule 2: Continuation Context Detection
|
||||
|
||||
**When user says "continue", "let's work on", "back to", auto-check for active project:**
|
||||
|
||||
```
|
||||
User: "Let's continue working on the tunnel"
|
||||
Claude: [Detects "tunnel" → reads GuruRMM CONTEXT.md]
|
||||
"I see tunnel Phase 1 is complete (v0.6.0). Phase 2 is channel implementation..."
|
||||
```
|
||||
|
||||
### Rule 3: Uncertainty Threshold
|
||||
|
||||
**When Claude's certainty < 95%, auto-check hints:**
|
||||
|
||||
```python
|
||||
def should_check_hints(user_message, current_knowledge):
|
||||
"""Check if we should read CONTEXT.md before responding"""
|
||||
|
||||
# Rule 1: Project keyword mentioned
|
||||
if detect_project(user_message):
|
||||
return True
|
||||
|
||||
# Rule 2: Continuation words
|
||||
if re.search(r'\b(continue|back to|work on|finish|resume)\b', user_message, re.I):
|
||||
return True
|
||||
|
||||
# Rule 3: Infrastructure questions
|
||||
if re.search(r'\b(server|database|deploy|credentials|IP|password)\b', user_message, re.I):
|
||||
return True
|
||||
|
||||
# Rule 4: Reference to past work
|
||||
if re.search(r'\b(last time|previous|recent|we did|earlier)\b', user_message, re.I):
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
## CONTEXT.md Standard Format
|
||||
|
||||
**Every project CONTEXT.md must have these sections:**
|
||||
|
||||
### Required Sections
|
||||
1. **Quick Start - Infrastructure Overview** (table format)
|
||||
2. **Current State (READ THIS FIRST)** - Recent work, versions deployed
|
||||
3. **Anti-Patterns (DON'T DO THIS)** - Common mistakes to avoid
|
||||
4. **Where to Find Things** - File structure, key paths
|
||||
5. **Common Operations** - Copy-paste commands for frequent tasks
|
||||
6. **Recent Session Logs** - Links to latest work
|
||||
|
||||
### Optional Sections
|
||||
- Key Technical Decisions (ADRs)
|
||||
- Troubleshooting (FAQ format)
|
||||
- Roadmap
|
||||
- Quick Reference (API endpoints, log formats, etc.)
|
||||
|
||||
## Implementation in .claude/CLAUDE.md
|
||||
|
||||
**Add this section to CLAUDE.md:**
|
||||
|
||||
```markdown
|
||||
## Automatic Context Loading (MANDATORY)
|
||||
|
||||
**BEFORE responding to ANY user message, check these triggers:**
|
||||
|
||||
### Trigger 1: Project Keywords
|
||||
If user mentions GuruRMM, Dataforth, tunnel, VASLOG, AD2, etc:
|
||||
1. Identify project from keyword
|
||||
2. Read [project]/CONTEXT.md ENTIRELY
|
||||
3. Note current state, infrastructure, anti-patterns
|
||||
4. THEN respond with full context
|
||||
|
||||
### Trigger 2: Continuation Words
|
||||
If user says "continue", "let's work on", "back to", "resume":
|
||||
1. Check for project in message
|
||||
2. Read CONTEXT.md if found
|
||||
3. Check recent session logs mentioned in CONTEXT.md
|
||||
4. THEN proceed with work
|
||||
|
||||
### Trigger 3: Infrastructure Questions
|
||||
If user asks about servers, databases, credentials, deployment:
|
||||
1. Check root CONTEXT.md for project list
|
||||
2. Read relevant project CONTEXT.md
|
||||
3. Answer from CONTEXT.md (don't ask user)
|
||||
|
||||
### Trigger 4: Uncertainty
|
||||
If you're <95% certain about infrastructure, recent work, or next steps:
|
||||
1. Search for CONTEXT.md in current working directory
|
||||
2. Search for CONTEXT.md in projects/*/
|
||||
3. Read any found before asking user
|
||||
|
||||
**ANTI-PATTERN EXAMPLE:**
|
||||
User: "Look at the Dataforth DFWDS folders"
|
||||
You: "I don't recall what we've done with Dataforth" # WRONG
|
||||
|
||||
**CORRECT PATTERN:**
|
||||
User: "Look at the Dataforth DFWDS folders"
|
||||
You: [Detects "Dataforth" → reads projects/dataforth-dos/CONTEXT.md]
|
||||
"I see from CONTEXT.md that recent work (2026-04-12) extended the SCMVAS/SCMHVAS
|
||||
pipeline. DFWDS folders are at C:\Shares\testdatadb\ on AD2 (192.168.0.6)..."
|
||||
```
|
||||
|
||||
## Hook Integration
|
||||
|
||||
**Create .claude/hooks/pre-response:**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Pre-response hook: Check for CONTEXT.md
|
||||
|
||||
USER_MSG="$1"
|
||||
|
||||
# Check for project keywords
|
||||
if echo "$USER_MSG" | grep -qi "GuruRMM\|tunnel\|rmm-api"; then
|
||||
echo "[HINT] Load projects/msp-tools/guru-rmm/CONTEXT.md"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if echo "$USER_MSG" | grep -qi "Dataforth\|DFWDS\|testdatadb\|AD2\|VASLOG"; then
|
||||
echo "[HINT] Load projects/dataforth-dos/CONTEXT.md"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for continuation words
|
||||
if echo "$USER_MSG" | grep -qi "continue\|back to\|work on\|resume"; then
|
||||
echo "[HINT] Check for active project CONTEXT.md"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for infrastructure questions
|
||||
if echo "$USER_MSG" | grep -qi "server\|database\|deploy\|credentials"; then
|
||||
echo "[HINT] Check CONTEXT.md in current directory or projects/*/"
|
||||
exit 0
|
||||
fi
|
||||
```
|
||||
|
||||
## Session Start Protocol
|
||||
|
||||
**At the start of EVERY new session/conversation:**
|
||||
|
||||
1. Check current working directory for CONTEXT.md
|
||||
2. If found, read it BEFORE asking user anything
|
||||
3. If not found, check for projects/*/CONTEXT.md
|
||||
4. List available projects from found CONTEXT.md files
|
||||
5. Wait for user to specify what to work on
|
||||
6. When they do, load that project's CONTEXT.md
|
||||
|
||||
**Example session start:**
|
||||
|
||||
```
|
||||
[Claude starts, reads CONTEXT.md in /Users/azcomputerguru/ClaudeTools/]
|
||||
|
||||
Claude: "I've loaded context for ClaudeTools project. Available subprojects:
|
||||
- GuruRMM (tunnel Phase 2 pending)
|
||||
- Dataforth DOS (SCMVAS/SCMHVAS pipeline deployed)
|
||||
|
||||
What would you like to work on?"
|
||||
|
||||
User: "GuruRMM tunnel"
|
||||
|
||||
[Claude reads projects/msp-tools/guru-rmm/CONTEXT.md]
|
||||
|
||||
Claude: "Loaded GuruRMM context:
|
||||
- Server: 172.16.3.30:3001
|
||||
- Phase 1 complete (v0.6.0)
|
||||
- 2/6 agents online
|
||||
- Next: Channel implementation
|
||||
|
||||
Ready to proceed with Phase 2."
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
### For User
|
||||
- ✅ Never repeat context ("What's the server IP?")
|
||||
- ✅ Claude starts work immediately with full context
|
||||
- ✅ No "let me check session logs" delays
|
||||
- ✅ Consistent infrastructure knowledge
|
||||
|
||||
### For Claude
|
||||
- ✅ Clear decision tree for when to load context
|
||||
- ✅ Structured hints (CONTEXT.md) are fast to read
|
||||
- ✅ Anti-patterns prevent repeated mistakes
|
||||
- ✅ Recent session log pointers for deep-dive
|
||||
|
||||
### For System
|
||||
- ✅ Scales to N projects (just add CONTEXT.md)
|
||||
- ✅ Works across machines (Git-synced)
|
||||
- ✅ Low overhead (only read when triggered)
|
||||
- ✅ Degrades gracefully (if CONTEXT.md missing, ask user)
|
||||
|
||||
## Migration Path
|
||||
|
||||
### Phase 1: Create CONTEXT.md files (DONE ✅)
|
||||
- [x] Root: CONTEXT.md
|
||||
- [x] GuruRMM: projects/msp-tools/guru-rmm/CONTEXT.md
|
||||
- [x] Dataforth: projects/dataforth-dos/CONTEXT.md
|
||||
|
||||
### Phase 2: Update CLAUDE.md with auto-load rules
|
||||
```bash
|
||||
# Add "Automatic Context Loading" section to .claude/CLAUDE.md
|
||||
# Include triggers, anti-patterns, examples
|
||||
```
|
||||
|
||||
### Phase 3: Train via /refresh-directives
|
||||
```bash
|
||||
# Every time Claude starts session:
|
||||
# 1. Read CLAUDE.md (includes auto-load rules)
|
||||
# 2. Apply triggers to user's first message
|
||||
# 3. Load relevant CONTEXT.md before responding
|
||||
```
|
||||
|
||||
### Phase 4: Create hook (optional)
|
||||
```bash
|
||||
# .claude/hooks/pre-response
|
||||
# Automated hint detection, prints to stderr
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
**Test cases to verify system works:**
|
||||
|
||||
| User Message | Expected Behavior | Pass/Fail |
|
||||
|--------------|-------------------|-----------|
|
||||
| "Look at Dataforth DFWDS" | Reads dataforth-dos/CONTEXT.md, knows AD2 IP | ✅ |
|
||||
| "Continue GuruRMM tunnel" | Reads guru-rmm/CONTEXT.md, knows Phase 1 done | ✅ |
|
||||
| "What's the database password?" | Checks CONTEXT.md, finds vault command | ✅ |
|
||||
| "Deploy to AD2" | Reads dataforth/CONTEXT.md, knows deploy script | ✅ |
|
||||
| "Check agent status" | Reads guru-rmm/CONTEXT.md, knows API endpoint | ✅ |
|
||||
|
||||
## Example: Before and After
|
||||
|
||||
### BEFORE (Current Problem)
|
||||
```
|
||||
User: "Look at the Dataforth DFWDS folders"
|
||||
|
||||
Claude: "I'm not sure what work we've done on Dataforth. Let me search session logs..."
|
||||
[Searches for 5 minutes]
|
||||
[Finds multiple sessions]
|
||||
"Can you tell me which server has the DFWDS folders?"
|
||||
|
||||
User: [Frustrated] "It's AD2 at 192.168.0.6, we just worked on this!"
|
||||
```
|
||||
|
||||
### AFTER (With Auto-Context)
|
||||
```
|
||||
User: "Look at the Dataforth DFWDS folders"
|
||||
|
||||
Claude: [Detects "Dataforth" → reads projects/dataforth-dos/CONTEXT.md]
|
||||
"I see from CONTEXT.md that DFWDS folders are at C:\Shares\testdatadb\
|
||||
on AD2 (192.168.0.6). Recent work (2026-04-12) extended the SCMVAS/SCMHVAS
|
||||
pipeline. The testdatadb service is running on port 3000.
|
||||
|
||||
What would you like me to check in those folders?"
|
||||
|
||||
User: [Happy] "Perfect, let's verify the Engineering-Tested files imported correctly"
|
||||
```
|
||||
|
||||
## Rollout Plan
|
||||
|
||||
**Immediate (2026-04-14):**
|
||||
- [x] Create CONTEXT.md for 3 main projects
|
||||
- [ ] Update CLAUDE.md with auto-load rules
|
||||
- [ ] Test with /refresh-directives
|
||||
|
||||
**Short-term (1 week):**
|
||||
- [ ] Add CONTEXT.md for remaining projects
|
||||
- [ ] Create pre-response hook
|
||||
- [ ] Document in README
|
||||
|
||||
**Long-term (ongoing):**
|
||||
- [ ] Update CONTEXT.md after major sessions
|
||||
- [ ] Add new projects' CONTEXT.md as they start
|
||||
- [ ] Refine triggers based on user feedback
|
||||
|
||||
---
|
||||
|
||||
**Implementation Status:** Phase 1 Complete (CONTEXT.md files created)
|
||||
**Next Step:** Update .claude/CLAUDE.md with automatic loading rules
|
||||
**Goal:** Claude is >95% certain before responding, never asks for context that's in CONTEXT.md
|
||||
@@ -1,5 +1,84 @@
|
||||
# ClaudeTools Project Context
|
||||
|
||||
## Multi-User Environment (CHECK FIRST)
|
||||
|
||||
This repo is shared across multiple team members. **At every session start, BEFORE doing anything else:**
|
||||
|
||||
1. **Read `.claude/identity.json`** (local, gitignored). If it exists, greet the user by name and proceed.
|
||||
2. **If identity.json does NOT exist** (first sync on a new machine):
|
||||
- Read `.claude/users.json` for the known user list
|
||||
- Ask: "This looks like a new machine. Are you **Mike Swanson** or **Howard Enos**? (Or someone new?)"
|
||||
- Based on their answer, create `.claude/identity.json`:
|
||||
```json
|
||||
{
|
||||
"user": "mike",
|
||||
"full_name": "Mike Swanson",
|
||||
"email": "mike@azcomputerguru.com",
|
||||
"role": "admin",
|
||||
"machine": "<HOSTNAME>"
|
||||
}
|
||||
```
|
||||
- Also set local git config for this repo:
|
||||
```bash
|
||||
git config user.name "<full_name>"
|
||||
git config user.email "<email>"
|
||||
```
|
||||
- Set git remote to use the user's own Gitea account (read `gitea_username` from users.json):
|
||||
```bash
|
||||
git remote set-url origin https://<gitea_username>@git.azcomputerguru.com/azcomputerguru/claudetools.git
|
||||
```
|
||||
- Add the machine hostname to the user's `known_machines` list in `.claude/users.json` and commit.
|
||||
- **IMPORTANT: Show the user `.claude/ONBOARDING.md`** — present it section by section, explain what each part does and WHY, answer any questions. This is their orientation to the system.
|
||||
3. **If the hostname doesn't match any known machine** for the identified user, update their `known_machines` in users.json.
|
||||
|
||||
### Session log attribution
|
||||
|
||||
Every session log MUST include a `## User` section at the top:
|
||||
```markdown
|
||||
## User
|
||||
- **User:** Mike Swanson (mike)
|
||||
- **Machine:** DESKTOP-0O8A1RL
|
||||
- **Role:** admin
|
||||
```
|
||||
|
||||
### Git commit attribution
|
||||
|
||||
Commits use the local git config (user.name / user.email), which is set per-user during identity setup. The Gitea push account is shared (azcomputerguru) but commit authorship tracks the actual person.
|
||||
|
||||
### Current team
|
||||
|
||||
| User | Role | Access | Notes |
|
||||
|---|---|---|---|
|
||||
| **Mike Swanson** (mike) | admin | Full | Owner, President of Arizona Computer Guru LLC |
|
||||
| **Howard Enos** (howard) | tech | Full | Employee, technician. Full trust — same access as admin for all MSP tracking and daily work. |
|
||||
|
||||
Both users have identical access. No permission gating between them. If a new team member is added later, their role and access scope should be defined in `.claude/users.json` before they sync.
|
||||
|
||||
## Work Mode (auto-detect + color)
|
||||
|
||||
Claude operates in one of five modes. Mode determines terminal color and operational posture. **Auto-detect on every user message** using these priority rules (first match wins):
|
||||
|
||||
1. **remediation** (purple) — "remediation tool", "365", "breach", "tenant sweep", M365 keywords
|
||||
2. **client** (orange) — client name mentioned (check `clients/` dirs), work under `clients/`, "for \<client\>"
|
||||
3. **infra** (red) — server names/IPs (AD2, Jupiter, 172.16.x.x), SSH, firewall, DNS, deploy, service restart
|
||||
4. **dev** (cyan) — code, build, compile, Rust/cargo, npm, GuruRMM dev, testing, work under `projects/`
|
||||
5. **general** (blue) — default
|
||||
|
||||
**On mode change:** update `identity.json` "mode" field, change terminal color, announce briefly: `[MODE -> infra]`. Don't interrupt workflow.
|
||||
|
||||
**Manual override:** user can run `/mode <name>` to force a mode. `/mode auto` re-runs detection. `/mode` shows current.
|
||||
|
||||
**Posture by mode:**
|
||||
- **client (orange):** careful with data, session logs go to `clients/`, always name the client
|
||||
- **dev (cyan):** delegate freely to Coding/Testing agents, less confirmation friction
|
||||
- **infra (red):** confirm before destructive ops, backup-first, double-check IPs
|
||||
- **general (blue):** lightweight, default
|
||||
- **remediation (purple):** Graph API focus, compliance language, full audit trail
|
||||
|
||||
Full details: `.claude/commands/mode.md`
|
||||
|
||||
---
|
||||
|
||||
## Identity: You Are a Coordinator
|
||||
|
||||
You are NOT an executor. You coordinate specialized agents and preserve your context window.
|
||||
@@ -23,6 +102,20 @@ You are NOT an executor. You coordinate specialized agents and preserve your con
|
||||
|
||||
**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.
|
||||
|
||||
### Model Routing (Complexity-Based)
|
||||
|
||||
Before spawning an agent, pick a tier from `.claude/COMPLEXITY_ROUTING.md`:
|
||||
|
||||
| Tier | Model | When |
|
||||
|------|-------|------|
|
||||
| 1 | `haiku` | Lookup, format, summarize, doc — no code changes |
|
||||
| 2 | (inherit) | Standard code, DB, tests, git — most work |
|
||||
| 3 | `opus` | Architecture, security, ambiguous failures, production risk |
|
||||
|
||||
**Bump rule:** if the request involves `security`, `auth`, `credential`, `migration`, `production`, or `data loss` — bump one tier up.
|
||||
|
||||
Pass `model: "haiku"` or `model: "opus"` explicitly. Omit for Tier 2 (inherits session model).
|
||||
|
||||
### Coordination Flow
|
||||
|
||||
```
|
||||
@@ -34,6 +127,91 @@ User request -> Main Claude (coordinator) -> Launches agent(s) -> Agent returns
|
||||
|
||||
---
|
||||
|
||||
## Automatic Context Loading (CRITICAL)
|
||||
|
||||
**BEFORE responding to user's first message or when switching projects, AUTOMATICALLY load context:**
|
||||
|
||||
### Trigger 1: Project Keywords Detected
|
||||
If user mentions **GuruRMM**, **Dataforth**, **tunnel**, **VASLOG**, **AD2**, **testdatadb**, etc:
|
||||
1. **Immediately read** the matching project CONTEXT.md:
|
||||
- GuruRMM keywords → `projects/msp-tools/guru-rmm/CONTEXT.md`
|
||||
- Dataforth keywords → `projects/dataforth-dos/CONTEXT.md`
|
||||
- General → `CONTEXT.md` (root)
|
||||
2. Read ENTIRE file (infrastructure, current state, anti-patterns)
|
||||
3. Note recent session logs mentioned in CONTEXT.md
|
||||
4. THEN respond with full context
|
||||
|
||||
### Trigger 2: Continuation/Resume Words
|
||||
If user says "continue", "let's work on", "back to", "resume", "finish":
|
||||
1. Detect project from message
|
||||
2. Read project CONTEXT.md if found
|
||||
3. Check "Current State" and "Recent Session Logs" sections
|
||||
4. Proceed without asking for context
|
||||
|
||||
### Trigger 3: Infrastructure/Deployment Questions
|
||||
If user asks about **servers**, **databases**, **credentials**, **deploy**, **IP**, **password**:
|
||||
1. Check current directory for CONTEXT.md
|
||||
2. If not found, check projects/*/CONTEXT.md
|
||||
3. Answer from CONTEXT.md (never ask user for info that's in CONTEXT.md)
|
||||
|
||||
### Trigger 4: Uncertainty >5%
|
||||
If you're <95% certain about infrastructure, recent work, or next steps:
|
||||
1. Search for CONTEXT.md in working directory
|
||||
2. Search for CONTEXT.md in projects/*/
|
||||
3. Read before asking user
|
||||
|
||||
### ANTI-PATTERN Examples (NEVER DO THIS):
|
||||
|
||||
❌ **Wrong:**
|
||||
```
|
||||
User: "Look at the Dataforth DFWDS folders"
|
||||
You: "I don't recall what we've done with Dataforth. Let me search session logs..."
|
||||
```
|
||||
|
||||
✅ **Correct:**
|
||||
```
|
||||
User: "Look at the Dataforth DFWDS folders"
|
||||
You: [Detects "Dataforth" → reads projects/dataforth-dos/CONTEXT.md in <3 seconds]
|
||||
"I see from CONTEXT.md that DFWDS is at C:\Shares\testdatadb\ on AD2 (192.168.0.6).
|
||||
Recent work (2026-04-12) extended SCMVAS/SCMHVAS pipeline. Service is testdatadb on port 3000.
|
||||
What would you like me to check?"
|
||||
```
|
||||
|
||||
❌ **Wrong:**
|
||||
```
|
||||
User: "Continue working on GuruRMM tunnel"
|
||||
You: "What phase are we on? Which server is this deployed to?"
|
||||
```
|
||||
|
||||
✅ **Correct:**
|
||||
```
|
||||
User: "Continue working on GuruRMM tunnel"
|
||||
You: [Reads projects/msp-tools/guru-rmm/CONTEXT.md]
|
||||
"Tunnel Phase 1 is complete (v0.6.0, deployed to 172.16.3.30:3001).
|
||||
Phase 2 is channel implementation (Terminal, File, Registry, Service).
|
||||
2/6 agents online. Ready to proceed."
|
||||
```
|
||||
|
||||
### Session Start Protocol
|
||||
|
||||
At session start:
|
||||
1. Check for CONTEXT.md in current working directory
|
||||
2. If found, read it silently (don't announce to user)
|
||||
3. Be ready to answer questions about any project listed
|
||||
4. When user specifies project, load that project's CONTEXT.md automatically
|
||||
|
||||
### Benefits
|
||||
|
||||
- ✅ Never ask "What's the server IP?" (it's in CONTEXT.md)
|
||||
- ✅ Never ask "What did we do last time?" (recent logs in CONTEXT.md)
|
||||
- ✅ Never ask "Where's the database?" (infrastructure table in CONTEXT.md)
|
||||
- ✅ Start work immediately with full context
|
||||
- ✅ Follow anti-patterns automatically (CONTEXT.md lists common mistakes)
|
||||
|
||||
**See:** `.claude/AUTO_CONTEXT_SYSTEM.md` for full implementation details
|
||||
|
||||
---
|
||||
|
||||
## Projects
|
||||
|
||||
**ClaudeTools** -- MSP Work Tracking System (Production-Ready)
|
||||
@@ -109,6 +287,7 @@ Service account token in vault: `infrastructure/1password-service-account.sops.y
|
||||
| `/sync` | Sync config from Gitea repository |
|
||||
| `/create-spec` | Create app specification for AutoCoder |
|
||||
| `/frontend-design` | Modern frontend design patterns (auto-invoke after UI changes) |
|
||||
| `/remediation-tool` | M365 breach checks, tenant sweeps, gated remediation via Claude-MSP-Access Graph API app |
|
||||
|
||||
---
|
||||
|
||||
@@ -125,7 +304,7 @@ Service account token in vault: `infrastructure/1password-service-account.sops.y
|
||||
|
||||
## Local AI (Ollama)
|
||||
|
||||
Ollama runs locally with GPU acceleration for tasks that don't need Claude-level reasoning.
|
||||
Ollama runs on Mike's workstation (DESKTOP-0O8A1RL) with GPU acceleration. Available to all team members via Tailscale.
|
||||
|
||||
| Model | Size | Use For |
|
||||
|-------|------|---------|
|
||||
@@ -133,11 +312,37 @@ Ollama runs locally with GPU acceleration for tasks that don't need Claude-level
|
||||
| `codestral:22b` | 12 GB | Code generation, refactoring suggestions, docstrings |
|
||||
| `nomic-embed-text` | 274 MB | Embeddings only (used by GrepAI) |
|
||||
|
||||
### How to connect
|
||||
|
||||
**On Mike's workstation (local):**
|
||||
```bash
|
||||
# Simple prompt
|
||||
curl -s http://localhost:11434/api/generate -d '{"model":"qwen3:14b","prompt":"...","stream":false}' | jq -r '.response'
|
||||
```
|
||||
|
||||
**On any other machine via Tailscale:**
|
||||
```bash
|
||||
curl -s http://100.92.127.64:11434/api/generate -d '{"model":"qwen3:14b","prompt":"...","stream":false}' | jq -r '.response'
|
||||
```
|
||||
|
||||
### Per-machine setup
|
||||
|
||||
Read `.claude/identity.json` to determine which machine you're on:
|
||||
- **DESKTOP-0O8A1RL** (Mike's workstation): Ollama runs locally. Use `localhost:11434`.
|
||||
- **Any other machine** (Howard's laptop, other workstations): Ollama is remote via Tailscale. Use `100.92.127.64:11434`. Requires Tailscale to be connected.
|
||||
|
||||
**To check if Ollama is reachable:**
|
||||
```bash
|
||||
curl -s http://100.92.127.64:11434/api/tags | python -c "import sys,json; [print(m['name']) for m in json.load(sys.stdin).get('models',[])]"
|
||||
```
|
||||
|
||||
If it fails: verify Tailscale is connected (`tailscale status`), and that Mike's workstation is online.
|
||||
|
||||
### Access control
|
||||
|
||||
- Firewall rule on Mike's workstation allows port 11434 ONLY from Tailscale subnet (100.0.0.0/8)
|
||||
- NOT exposed to LAN, VPN, or internet
|
||||
- Binding: `OLLAMA_HOST=0.0.0.0:11434` (all interfaces, firewall restricts)
|
||||
|
||||
**Review policy:** Always review Critical/High impact Ollama outputs (auth, security, migrations, production). Trust Low impact (classification, formatting). Flag uncertainty to user.
|
||||
|
||||
### GrepAI (Semantic Code Search)
|
||||
|
||||
74
.claude/COMPLEXITY_ROUTING.md
Normal file
74
.claude/COMPLEXITY_ROUTING.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Complexity-Based Model Routing
|
||||
|
||||
When spawning an agent, pick a tier based on the request signals below, then pass `model` accordingly.
|
||||
|
||||
---
|
||||
|
||||
## Tier 1 — Haiku (fast/cheap)
|
||||
|
||||
**Signals:** single lookup, no code changes, classification, formatting, summarization, status check, documentation
|
||||
|
||||
**Examples:**
|
||||
- "What's the status of X?"
|
||||
- Summarize or format a session log
|
||||
- Search/grep for a value
|
||||
- Convert or extract data
|
||||
- Write/update a markdown doc
|
||||
|
||||
**Agents that default here:** documentation-squire, explore (quick searches), photo
|
||||
|
||||
**Agent call:** `model: "haiku"`
|
||||
|
||||
---
|
||||
|
||||
## Tier 2 — Sonnet (default, inherit)
|
||||
|
||||
**Signals:** standard code generation, routine DB queries, test execution, API work, multi-file reads, git operations
|
||||
|
||||
**Examples:**
|
||||
- Add or modify an endpoint
|
||||
- Run tests and report results
|
||||
- Write a DB migration
|
||||
- Fetch credentials, configure a service
|
||||
- Commit and push changes
|
||||
|
||||
**Agents that default here:** coding, database, testing, gitea, general-purpose, deep-explore (standard search)
|
||||
|
||||
**Agent call:** omit `model` (inherits session model)
|
||||
|
||||
---
|
||||
|
||||
## Tier 3 — Opus (high-stakes reasoning)
|
||||
|
||||
**Signals:** architectural decision, security/auth, 3+ interacting systems, ambiguous root cause, production data risk, anything that fails badly if wrong
|
||||
|
||||
**Examples:**
|
||||
- Redesign an auth or data flow
|
||||
- Security or code review of a critical PR
|
||||
- Debug a multi-service race condition
|
||||
- Schema migration on production data
|
||||
- Evaluate competing architectural approaches
|
||||
|
||||
**Agents that default here:** code-review (when Sequential Thinking triggers), deep-explore (architecture questions)
|
||||
|
||||
**Agent call:** `model: "opus"`
|
||||
|
||||
---
|
||||
|
||||
## Bump Rule
|
||||
|
||||
If the request contains ANY of these keywords, bump one tier up regardless of other signals:
|
||||
|
||||
`security`, `auth`, `token`, `credential`, `migration`, `production`, `race condition`, `data loss`, `breach`, `encrypt`
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Tier | Model | Typical cost | Use when |
|
||||
|------|-------|-------------|----------|
|
||||
| 1 | `haiku` | ~10x cheaper | Lookup, format, summarize, doc |
|
||||
| 2 | (inherit) | baseline | Standard code, DB, tests |
|
||||
| 3 | `opus` | ~5x more expensive | Architecture, security, ambiguous failures |
|
||||
|
||||
Err toward Tier 2 when uncertain. Only use Opus when the reasoning stakes justify the cost.
|
||||
109
.claude/MCP_SERVERS.md
Normal file
109
.claude/MCP_SERVERS.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# MCP Servers — Configuration Reference
|
||||
|
||||
MCP (Model Context Protocol) servers extend Claude Code with external tool
|
||||
capabilities. Each server runs as a child process and exposes tools that
|
||||
Claude can call.
|
||||
|
||||
**Config file:** `.mcp.json` in repo root (shared across machines via git).
|
||||
|
||||
---
|
||||
|
||||
## Active Servers
|
||||
|
||||
### TickTick
|
||||
|
||||
Task management integration for TickTick (todo/project tracking app).
|
||||
|
||||
**Tools provided:**
|
||||
- `ticktick_create_task`, `ticktick_update_task`, `ticktick_complete_task`, `ticktick_delete_task`
|
||||
- `ticktick_create_project`, `ticktick_update_project`, `ticktick_delete_project`
|
||||
- `ticktick_list_projects`, `ticktick_get_project`
|
||||
|
||||
**Auth:** OAuth token stored in vault at `services/ticktick.sops.yaml`. Token file
|
||||
auto-generated by `mcp-servers/ticktick/ticktick_auth.py` on first use.
|
||||
|
||||
**Config in `.mcp.json`:**
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ticktick": {
|
||||
"command": "python",
|
||||
"args": ["D:\\claudetools\\mcp-servers\\ticktick\\ticktick_mcp.py"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Claude-in-Chrome (browser automation)
|
||||
|
||||
Installed as a Chrome browser extension. Provides browser automation tools
|
||||
for web interaction, form filling, page reading, screenshots, GIF recording.
|
||||
|
||||
**Not configured in `.mcp.json`** — runs as a Chrome extension that connects
|
||||
automatically when the Claude Code extension is active and Chrome is open.
|
||||
|
||||
**Tools provided:** `tabs_context_mcp`, `tabs_create_mcp`, `navigate`, `computer`
|
||||
(click/type/screenshot), `read_page`, `find`, `form_input`, `javascript_tool`,
|
||||
`get_page_text`, `read_console_messages`, `gif_creator`, etc.
|
||||
|
||||
**Requires:** Chrome browser with the Claude-in-Chrome extension installed.
|
||||
|
||||
---
|
||||
|
||||
## Available but Not Wired
|
||||
|
||||
These server directories exist but aren't in `.mcp.json`. Add them when needed.
|
||||
|
||||
### GrepAI MCP Server
|
||||
|
||||
Semantic code search over the indexed codebase. Alternative to using the
|
||||
`grepai search` CLI directly.
|
||||
|
||||
**To activate:** Add to `.mcp.json`:
|
||||
```json
|
||||
{
|
||||
"grepai": {
|
||||
"command": "D:\\claudetools\\grepai.exe",
|
||||
"args": ["mcp-serve"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Requires:** GrepAI initialized (`grepai init`) + Ollama running with
|
||||
`nomic-embed-text` model. Index builds automatically via `grepai watch`.
|
||||
|
||||
### Ollama Assistant
|
||||
|
||||
Local LLM integration for delegating simple tasks (summarization,
|
||||
classification, drafting) to locally-running models.
|
||||
|
||||
**Location:** `mcp-servers/ollama-assistant/`
|
||||
|
||||
**To activate:** Check the server's README for the exact `.mcp.json` entry.
|
||||
Requires Ollama running at `http://localhost:11434` with models pulled.
|
||||
|
||||
### Feature Management
|
||||
|
||||
Feature flag management server.
|
||||
|
||||
**Location:** `mcp-servers/feature-management/`
|
||||
|
||||
**Status:** Exists but purpose unclear. Check directory for README.
|
||||
|
||||
---
|
||||
|
||||
## Adding a New MCP Server
|
||||
|
||||
1. Create directory: `mcp-servers/<name>/`
|
||||
2. Write the server script (Python or Node recommended)
|
||||
3. Add entry to `.mcp.json` with `command` and `args`
|
||||
4. Restart Claude Code to pick up the new server
|
||||
5. Document in this file
|
||||
|
||||
**Important:** `.mcp.json` is tracked in git. Changes sync to all machines.
|
||||
Machine-specific server paths should use absolute paths that work on all
|
||||
team workstations (or use relative paths from repo root).
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-04-16*
|
||||
246
.claude/ONBOARDING.md
Normal file
246
.claude/ONBOARDING.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# Welcome to ClaudeTools — Onboarding Guide
|
||||
|
||||
Hey! This guide explains how our Claude Code setup works, WHY it's built the way it is, and how to use it effectively for daily MSP work. Read this once, then use it as reference when something feels unfamiliar.
|
||||
|
||||
---
|
||||
|
||||
## What is this?
|
||||
|
||||
ClaudeTools is our shared workspace for **Claude Code** — the AI coding + automation assistant. It's a git repo that syncs across our workstations via Gitea (our self-hosted Git server). Everything Claude learns, every session log, every automation script, every project we build — it all lives here and stays in sync.
|
||||
|
||||
**Why a repo instead of just using Claude directly?**
|
||||
- Claude Code loses context between sessions. This repo IS the memory.
|
||||
- Session logs preserve what we did, what creds we used, what decisions we made.
|
||||
- CLAUDE.md tells Claude HOW to behave specifically for our org (not generic defaults).
|
||||
- Skills and commands give us reusable shortcuts for common MSP tasks.
|
||||
- The vault (separate repo) stores all credentials encrypted so Claude can access them without us typing passwords every session.
|
||||
|
||||
---
|
||||
|
||||
## First time setup
|
||||
|
||||
When you open Claude Code for the first time on a new machine, Claude will ask who you are. Just answer with your name. Claude then:
|
||||
|
||||
1. Creates a local identity file (so it knows who's at the keyboard)
|
||||
2. Sets your git name/email for commits
|
||||
3. Registers your machine in the shared users list
|
||||
|
||||
After that, every session log and git commit is attributed to you.
|
||||
|
||||
---
|
||||
|
||||
## The slash commands (most important daily tools)
|
||||
|
||||
Type these in Claude Code's prompt. They're shortcuts for common operations.
|
||||
|
||||
| Command | What it does | When to use |
|
||||
|---------|-------------|-------------|
|
||||
| `/save` | Saves a comprehensive session log (what you did, creds used, decisions made) | **End of every significant work session.** This is how future-you (or future-me) recovers context. |
|
||||
| `/sync` | Pull + push changes to/from Gitea | Start of session (get latest), end of session (push yours) |
|
||||
| `/context` | Searches session logs and credentials for previous work | "What did we do for Dataforth last week?" or "What's the password for AD2?" |
|
||||
| `/checkpoint` | Git commit + database context save | After completing a feature or fix |
|
||||
| `/scc` | Save + Commit + Push (all three in one shot) | Quick end-of-session wrap-up |
|
||||
| `/1password` | Access secrets from 1Password | When vault doesn't have a credential |
|
||||
|
||||
### Why these exist
|
||||
|
||||
Without `/save`, you'd lose everything when a session ends. Without `/sync`, your work stays on one machine. Without `/context`, you'd re-discover the same information every session. These three commands are 90% of daily usage.
|
||||
|
||||
---
|
||||
|
||||
## The SOPS vault (how credentials work)
|
||||
|
||||
We store ALL credentials in an encrypted vault at `D:\vault\` (separate git repo). Files are YAML encrypted with age/SOPS. Claude can decrypt them on the fly.
|
||||
|
||||
**How Claude accesses a credential:**
|
||||
```bash
|
||||
bash D:/vault/scripts/vault.sh get-field clients/dataforth/ad2.sops.yaml credentials.password
|
||||
```
|
||||
|
||||
**Why this matters:**
|
||||
- We never hardcode passwords in scripts or session logs (they're vault references)
|
||||
- The vault syncs across machines via Gitea (same as claudetools)
|
||||
- Encryption uses an age key at `%APPDATA%\sops\age\keys.txt` — this key needs to be on each machine that decrypts
|
||||
|
||||
**Your machine needs the age key.** Mike will give you the key file. Drop it at:
|
||||
```
|
||||
C:\Users\<you>\AppData\Roaming\sops\age\keys.txt
|
||||
```
|
||||
|
||||
Without this file, vault commands fail. Everything else works fine.
|
||||
|
||||
---
|
||||
|
||||
## How Claude knows about our infrastructure
|
||||
|
||||
### CLAUDE.md (the brain)
|
||||
|
||||
`.claude/CLAUDE.md` is the master instructions file. Claude reads it at the start of every session. It tells Claude:
|
||||
|
||||
- **Who we are** (AZ Computer Guru, MSP)
|
||||
- **How to behave** (delegate to agents, no emojis, use vault for creds)
|
||||
- **What projects exist** (GuruRMM, Dataforth, ClaudeTools API)
|
||||
- **How to load context** automatically when you mention a project keyword
|
||||
|
||||
**Key behavior:** If you say "work on Dataforth", Claude automatically reads `projects/dataforth-dos/CONTEXT.md` before responding. Same for "GuruRMM" → reads `projects/msp-tools/guru-rmm/CONTEXT.md`. This means Claude starts every project conversation with full context — server IPs, current state, recent work, anti-patterns to avoid.
|
||||
|
||||
### CONTEXT.md files (per-project state)
|
||||
|
||||
Each major project has a `CONTEXT.md` that captures:
|
||||
- Server IPs, ports, credentials references
|
||||
- Current deployment state
|
||||
- Recent session logs (what was done last)
|
||||
- Anti-patterns (things NOT to do, learned from past mistakes)
|
||||
- What to work on next
|
||||
|
||||
These files are the **single source of truth** for "where are we on this project."
|
||||
|
||||
### Session logs (the history)
|
||||
|
||||
Every significant work session gets a log saved to `session-logs/` (root for general, or `projects/*/session-logs/` for project-specific). These include:
|
||||
- What was accomplished
|
||||
- Full credentials used (unredacted — needed for future sessions)
|
||||
- Infrastructure changes made
|
||||
- Commands that worked and errors that didn't
|
||||
- What's still pending
|
||||
|
||||
**This is why `/save` matters.** Without it, the next person (or the next Claude session) starts from scratch.
|
||||
|
||||
---
|
||||
|
||||
## Skills (auto-invoked behaviors)
|
||||
|
||||
Skills are more powerful than commands — some trigger automatically.
|
||||
|
||||
| Skill | Auto-invokes? | What it does |
|
||||
|-------|--------------|-------------|
|
||||
| `frontend-design` | YES — after any UI change | Validates visual correctness, accessibility, design quality |
|
||||
| `stop-slop` | YES — always active | Prevents generic/lazy AI output. Enforces quality. |
|
||||
| `remediation-tool` | When you say "remediation tool" or "365" | M365 tenant investigation via our Graph API app |
|
||||
| `skill-creator` | On request | Helps build new custom skills |
|
||||
| `theme-factory` | On request | Apply visual themes to HTML artifacts |
|
||||
|
||||
### Why "stop-slop" exists
|
||||
|
||||
Without it, Claude defaults to generic patterns (purple gradients, Inter font, emoji-heavy prose). Our `stop-slop` skill enforces our standards: ASCII markers instead of emojis, specific rather than vague, no filler phrases.
|
||||
|
||||
---
|
||||
|
||||
## Agents (specialized workers)
|
||||
|
||||
Claude Code can spawn sub-agents for specific tasks. These are defined in `.claude/agents/`. The main ones you'll encounter:
|
||||
|
||||
| Agent | What it does | When Claude uses it |
|
||||
|-------|-------------|-------------------|
|
||||
| **Database Agent** | Runs SQL queries on our databases | Any database operation — Claude should NEVER query directly |
|
||||
| **Code Review Agent** | Reviews code changes for quality/security | After any code modification |
|
||||
| **Coding Agent** | Writes production code | When Claude needs to generate code (not just edit) |
|
||||
| **Explore Agent** | Searches codebases quickly | When looking for files, patterns, or understanding code |
|
||||
| **Gitea Agent** | Git commits, pushes, branch operations | Commit workflow |
|
||||
| **Backup Agent** | Backup operations | Before destructive changes |
|
||||
|
||||
**Why agents?** Claude has a limited context window. If it does everything itself, it runs out of memory mid-conversation. Agents handle heavy work in isolation and return just the summary. Also: separation of concerns — the Code Review Agent can independently evaluate code the Coding Agent wrote.
|
||||
|
||||
---
|
||||
|
||||
## Local AI tools (when available)
|
||||
|
||||
### Ollama (local LLM)
|
||||
|
||||
Ollama runs AI models locally on your GPU. Used for tasks that don't need Claude's full reasoning power — summarization, classification, data extraction.
|
||||
|
||||
**Models we use:**
|
||||
- `qwen3:14b` — general purpose (summarization, drafting)
|
||||
- `codestral:22b` — code generation assistance
|
||||
- `nomic-embed-text` — embeddings for semantic search
|
||||
|
||||
**Ollama runs on Mike's workstation** and is shared via Tailscale. You don't need to install it locally.
|
||||
|
||||
**To use from your machine (Tailscale must be connected):**
|
||||
```bash
|
||||
curl -s http://100.92.127.64:11434/api/tags
|
||||
```
|
||||
|
||||
If that returns models, you're connected. Claude automatically uses the right URL based on which machine you're on (reads from `identity.json`).
|
||||
|
||||
If it fails: check that Tailscale is connected (`tailscale status`) and Mike's workstation is online.
|
||||
|
||||
### GrepAI (semantic code search)
|
||||
|
||||
Searches code by MEANING rather than exact text. "How does auth work?" finds authentication code even if the word "auth" doesn't appear.
|
||||
|
||||
**Status:** Requires setup per-machine (index build). The `deep-explore` agent uses it. If it's not installed, Claude uses regular grep (still works, just less smart).
|
||||
|
||||
---
|
||||
|
||||
## Project structure
|
||||
|
||||
```
|
||||
D:\claudetools\
|
||||
.claude/ — Claude's brain (CLAUDE.md, agents, skills, memory, commands)
|
||||
session-logs/ — General work logs
|
||||
projects/
|
||||
dataforth-dos/ — Dataforth test datasheet pipeline (AD2, testdatadb)
|
||||
msp-tools/
|
||||
guru-rmm/ — GuruRMM agent + server (Rust, our product)
|
||||
newsletter/ — Marketing newsletters
|
||||
clients/
|
||||
dataforth/ — Dataforth-specific client docs
|
||||
pavon/ — Pavon/client docs
|
||||
... — Other clients
|
||||
credentials.md — Quick-reference credentials (vault is source of truth)
|
||||
CONTEXT.md — Root-level project context
|
||||
|
||||
D:\vault\ — SOPS-encrypted credentials (separate repo)
|
||||
infrastructure/ — Our servers (Jupiter, Uranus, pfSense, etc.)
|
||||
clients/ — Client credentials
|
||||
services/ — Service credentials (Cloudflare, Azure, Gitea, etc.)
|
||||
projects/ — Project-specific secrets
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Daily workflow
|
||||
|
||||
### Starting a work session
|
||||
1. Open Claude Code in the project directory
|
||||
2. Claude greets you by name (reads identity.json)
|
||||
3. Tell Claude what you're working on — it auto-loads the right context
|
||||
4. Work normally — ask questions, make changes, run commands
|
||||
|
||||
### Ending a work session
|
||||
1. `/save` — creates the session log (DO THIS EVERY TIME)
|
||||
2. `/sync` — pushes everything to Gitea
|
||||
3. Close Claude Code
|
||||
|
||||
### When switching projects mid-session
|
||||
Just say "let's work on GuruRMM" or "switch to Dataforth" — Claude reads the relevant CONTEXT.md and picks up where the last session left off.
|
||||
|
||||
---
|
||||
|
||||
## Things to know
|
||||
|
||||
**Claude remembers across sessions** — via session logs and memory files, not magic. If you don't `/save`, the next session starts cold.
|
||||
|
||||
**Credentials are in the vault** — don't ask Mike for passwords; ask Claude. It decrypts from the vault.
|
||||
|
||||
**Git commits are attributed to YOU** — your name and email appear on every commit from your machine.
|
||||
|
||||
**Production deployments need care** — Claude will warn before destructive operations (git push --force, database drops, service restarts). Read the warnings.
|
||||
|
||||
**If Claude seems confused about a project** — say `/context` and ask it to search for recent work. Or read the project's CONTEXT.md yourself.
|
||||
|
||||
**If something breaks** — session logs have the full history. `git log` shows what changed and who changed it. Gitea keeps everything.
|
||||
|
||||
---
|
||||
|
||||
## Getting help
|
||||
|
||||
- Ask Claude: "What commands do I have?" or "How do I access credentials?"
|
||||
- Read `.claude/CLAUDE.md` for the full rulebook
|
||||
- Check `session-logs/` for recent work examples
|
||||
- Ask Mike
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-04-16*
|
||||
132
.claude/commands/import.md
Normal file
132
.claude/commands/import.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# /import — Ingest a folder into ClaudeTools
|
||||
|
||||
Import any folder of data into the ClaudeTools structure. Claude analyzes each file's content, classifies it, proposes placement, sanitizes credentials, and organizes everything into the correct locations.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/import <path> Import a folder
|
||||
/import <path> --dry-run Show plan without executing
|
||||
/import <path> --client <name> Hint: this data belongs to a specific client
|
||||
/import <path> --project <name> Hint: this data belongs to a specific project
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
The first argument is a folder path to ingest. Everything inside (recursive) is scanned and classified.
|
||||
|
||||
## Process
|
||||
|
||||
Follow these steps IN ORDER. Do not skip any step.
|
||||
|
||||
### Step 1: Scan
|
||||
|
||||
Read the source folder recursively. For each file, note:
|
||||
- Filename + extension
|
||||
- Size
|
||||
- First ~200 lines of content (for text files)
|
||||
- Binary vs text detection
|
||||
|
||||
Skip files >50 MB (flag them for manual review).
|
||||
|
||||
### Step 2: Classify
|
||||
|
||||
For each file, determine its category based on content analysis:
|
||||
|
||||
| Category | Signals | Destination |
|
||||
|---|---|---|
|
||||
| **Session log** | Conversation transcript, dated entries, "accomplished", "session" | `session-logs/` or `projects/*/session-logs/` or `clients/*/session-logs/` |
|
||||
| **Client work** | Client name mentioned, ticket/case references, client-specific infra | `clients/<client>/` |
|
||||
| **Project code** | Source code, configs, build files, READMEs | `projects/<project>/` |
|
||||
| **Credentials** | Passwords, API keys, tokens, connection strings, SSH keys | `D:\vault\` (SOPS encrypted) |
|
||||
| **Infrastructure docs** | Server configs, network diagrams, IP lists, runbooks | `credentials.md` update or memory entry |
|
||||
| **Tool/script** | Standalone utility, automation script, helper | `tools/` or `projects/msp-tools/` |
|
||||
| **Documentation** | Guides, how-tos, notes, procedures | Project-specific docs or root docs |
|
||||
| **Unknown** | Can't classify | Flag for user decision |
|
||||
|
||||
If `--client` or `--project` was specified, weight classification toward that target.
|
||||
|
||||
### Step 3: Credential extraction
|
||||
|
||||
Before placing ANY file, scan for sensitive data:
|
||||
- Passwords (inline, in configs, in notes)
|
||||
- API keys / tokens (any string matching `[A-Za-z0-9_\-]{20,}` near words like key/token/secret)
|
||||
- Connection strings (jdbc:, postgres://, mysql://, mongodb://)
|
||||
- SSH private keys (`-----BEGIN`)
|
||||
- Certificate private keys
|
||||
|
||||
For each credential found:
|
||||
1. Show the user: "Found credential in `<file>`: `<context>` — move to vault?"
|
||||
2. If approved: create a vault SOPS entry, replace inline value with a vault reference
|
||||
3. If declined: leave as-is but warn
|
||||
|
||||
### Step 4: Present plan
|
||||
|
||||
Show a table:
|
||||
|
||||
```
|
||||
SOURCE → DESTINATION ACTION
|
||||
────────────────────────────────────────────────────────────────────────────────────
|
||||
notes/client-acme.md → clients/acme/notes.md copy
|
||||
scripts/backup-check.ps1 → tools/backup-check.ps1 copy
|
||||
creds.txt → D:\vault\clients\acme.sops.yaml vault + delete source
|
||||
session-2026-04-10.md → clients/acme/session-logs/2026-04-10.md copy
|
||||
my-tool/src/main.rs → projects/msp-tools/howard-tools/src/ copy (new project)
|
||||
random-binary.exe → (SKIP - 85 MB, too large) flag
|
||||
unknown-doc.pdf → (UNKNOWN - needs your input) ask
|
||||
```
|
||||
|
||||
Ask: "Does this plan look right? I can adjust any placement before executing."
|
||||
|
||||
### Step 5: Execute
|
||||
|
||||
After approval:
|
||||
1. Copy files to destinations (never move from source — source is the user's data)
|
||||
2. Create destination directories as needed
|
||||
3. Encrypt credential files via SOPS
|
||||
4. Update `MEMORY.md` if new knowledge was gained
|
||||
5. Update project `CONTEXT.md` files if project state changed
|
||||
6. Update `credentials.md` if infrastructure details were discovered
|
||||
|
||||
### Step 6: Report
|
||||
|
||||
Write a summary showing:
|
||||
- Files imported: N
|
||||
- Credentials vaulted: N
|
||||
- New directories created: list
|
||||
- Skipped files: list with reasons
|
||||
- Suggested follow-ups (e.g., "review clients/acme/ for completeness")
|
||||
|
||||
Commit the imported files with message: `import: ingested <N> files from <source_path>`
|
||||
|
||||
## Special cases
|
||||
|
||||
### Claude Code session data (~/.claude/projects/)
|
||||
|
||||
If the source folder IS a Claude Code projects directory (contains `.jsonl` files):
|
||||
- Use `tools/import-sessions.py` to extract summaries first
|
||||
- Then apply the standard classification to the summaries
|
||||
- Don't import raw JSONL (too large, mostly noise)
|
||||
|
||||
### Existing project detection
|
||||
|
||||
If imported code has a `Cargo.toml`, `package.json`, `pyproject.toml`, or similar:
|
||||
- Detect the project name from the manifest
|
||||
- Check if it already exists under `projects/`
|
||||
- If new: propose creating a new project directory
|
||||
- If existing: propose merging into the existing project
|
||||
|
||||
### Duplicate detection
|
||||
|
||||
Before copying, check if a file with the same name already exists at the destination:
|
||||
- If content is identical: skip (report as "already present")
|
||||
- If content differs: ask user which version to keep, or keep both with suffix
|
||||
|
||||
## File placement rules
|
||||
|
||||
Follow the conventions in `.claude/FILE_PLACEMENT_GUIDE.md`. Key rules:
|
||||
- Dataforth work → `projects/dataforth-dos/`
|
||||
- GuruRMM work → `projects/msp-tools/guru-rmm/`
|
||||
- Client work → `clients/<client-name>/`
|
||||
- General session logs → `session-logs/`
|
||||
- Credentials → SOPS vault at `D:\vault\`, NEVER in plaintext in the repo
|
||||
68
.claude/commands/mode.md
Normal file
68
.claude/commands/mode.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# /mode — Set or view the current work mode
|
||||
|
||||
Manually set the work mode, or let it auto-detect. Mode controls the terminal color and adjusts Claude's operational posture.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/mode Show current mode
|
||||
/mode client Switch to client mode (orange)
|
||||
/mode dev Switch to development mode (cyan)
|
||||
/mode infra Switch to infrastructure mode (red)
|
||||
/mode general Switch to general mode (blue)
|
||||
/mode remediation Switch to remediation/365 mode (purple)
|
||||
/mode auto Re-run auto-detection from current context
|
||||
```
|
||||
|
||||
## Modes
|
||||
|
||||
| Mode | Color | Posture |
|
||||
|---|---|---|
|
||||
| **client** | orange | Working on/for a specific client. Extra care with data handling. Session logs go to `clients/<name>/session-logs/`. Credential access audited. Always identify the client in session logs. |
|
||||
| **dev** | cyan | Building features, writing code, testing. Delegate freely to Coding/Testing agents. Use Ollama for drafts when available. Less confirmation friction on non-destructive operations. |
|
||||
| **infra** | red | Infrastructure work — servers, firewalls, DNS, deployments, backups. Confirm before any destructive or hard-to-reverse operation. Backup-first mentality. Double-check IPs and hostnames. |
|
||||
| **general** | blue | Research, planning, documentation, email drafts, general questions. Default mode. Lightweight posture. |
|
||||
| **remediation** | purple | M365 tenant work, breach investigation, security remediation. Graph API focus. Compliance-grade language. Full audit trail. |
|
||||
|
||||
## When invoked
|
||||
|
||||
1. Set the mode in `.claude/identity.json` under a `"mode"` key
|
||||
2. Run the color change: invoke `/color <mode_color>`
|
||||
3. Confirm to user: "Mode: **<mode>** (<color>)"
|
||||
|
||||
## Auto-detection rules
|
||||
|
||||
When `/mode auto` is called, OR at session start, OR when the user shifts topics, determine mode from context:
|
||||
|
||||
**Priority order (first match wins):**
|
||||
|
||||
1. **remediation** — user said "remediation tool", "365", "breach", "tenant sweep", or `/remediation-tool` was invoked
|
||||
2. **client** — user mentions a client name (check `clients/` subdirectories for name matches), or current work is under `clients/`, or user said "for <client>"
|
||||
3. **infra** — user mentions servers by name/IP (AD2, Jupiter, Uranus, pfSense, 172.16.x.x), SSH commands, firewall rules, DNS changes, service restarts, or "deploy to production"
|
||||
4. **dev** — user mentions code, building, compiling, Rust/Python/Node, cargo, npm, GuruRMM development, writing features, testing, or current work is under `projects/`
|
||||
5. **general** — default if nothing else matches
|
||||
|
||||
**On mode change (auto or manual):**
|
||||
- Update `.claude/identity.json` with `"mode": "<mode>"`
|
||||
- **Tell the user to run `/color <color>`** — Claude cannot invoke `/color` programmatically (it's a built-in CLI command). Include the command inline so the user can copy-paste.
|
||||
- Log the transition: `[MODE] general -> infra (detected: SSH to 172.16.3.30) — run /color red`
|
||||
|
||||
**Silent auto-switching:** When auto-detection triggers a mode change mid-session, announce it as: `[MODE -> infra] /color red` — short, actionable, the user can run the color command or ignore it. Don't interrupt flow with a long explanation. If the detection seems wrong, the user can override with `/mode <correct_mode>`.
|
||||
|
||||
## Session log integration
|
||||
|
||||
Session logs should include the mode in the User section:
|
||||
|
||||
```markdown
|
||||
## User
|
||||
- **User:** Mike Swanson (mike)
|
||||
- **Machine:** DESKTOP-0O8A1RL
|
||||
- **Role:** admin
|
||||
- **Mode:** infra (red)
|
||||
```
|
||||
|
||||
If mode changed during the session, note the transitions:
|
||||
|
||||
```markdown
|
||||
- **Mode:** general → infra → dev (transitioned during session)
|
||||
```
|
||||
118
.claude/commands/remediation-tool.md
Normal file
118
.claude/commands/remediation-tool.md
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
description: M365 tenant investigation + remediation via the Claude-MSP-Access Graph API app. Breach checks, tenant sweeps, consent URLs, and gated remediation actions.
|
||||
---
|
||||
|
||||
# /remediation-tool
|
||||
|
||||
M365 investigation and remediation using the **Claude-MSP-Access Graph API** multi-tenant app (App ID `fabb3421-8b34-484b-bc17-e46de9703418`, display name in customer tenants: **"ComputerGuru - AI Remediation"**).
|
||||
|
||||
**Default posture: READ-ONLY.** Remediation actions require explicit `YES` confirmation in chat.
|
||||
|
||||
---
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Form | What it does |
|
||||
|---|---|
|
||||
| `/remediation-tool check <upn>` | 10-point breach check on a single user |
|
||||
| `/remediation-tool sweep <domain>` | Tenant-wide signals (sign-ins, audits, risky users, guests) |
|
||||
| `/remediation-tool signins <domain> [--user upn] [--failed-only] [--days N]` | Ad-hoc sign-in query |
|
||||
| `/remediation-tool consent-url <domain>` | Emit admin consent URL for a tenant |
|
||||
| `/remediation-tool remediate <upn> <action>` | **GATED:** password-reset, revoke-sessions, disable-forwarding, remove-inbox-rules, disable-account |
|
||||
|
||||
`<domain>` accepts a tenant domain (`cascadestucson.com`), a UPN (`user@domain.com`), or a tenant GUID.
|
||||
|
||||
---
|
||||
|
||||
## Workflow Claude should follow
|
||||
|
||||
### 0. Parse invocation
|
||||
|
||||
- Extract subcommand, target, and any flags from `$ARGUMENTS`.
|
||||
- Normalize: UPN -> domain (split on `@`), domain -> look up tenant-id.
|
||||
- If the target is ambiguous or missing, ask the user once and proceed.
|
||||
|
||||
### 1. Resolve tenant ID
|
||||
|
||||
Run `bash .claude/skills/remediation-tool/scripts/resolve-tenant.sh <domain>` — returns tenant GUID via OpenID discovery. If it fails, the domain is not in Entra ID; surface the error and stop.
|
||||
|
||||
### 2. Acquire tokens (cached)
|
||||
|
||||
Run `bash .claude/skills/remediation-tool/scripts/get-token.sh <tenant-id> graph` and `... exchange` as needed. Tokens cache at `/tmp/remediation-tool/{tenant}/{scope}.jwt` with 55-minute TTL. The script pulls the app secret from the SOPS vault (`msp-tools/claude-msp-access-graph-api.sops.yaml`, field `credentials.credential`).
|
||||
|
||||
If either token returns 403/401 on first use, check `.claude/skills/remediation-tool/references/gotchas.md` for the per-tenant prerequisites (directory roles, admin consent) and emit the remediation link to the user.
|
||||
|
||||
### 3. Run the requested checks
|
||||
|
||||
- **`check <upn>`** -> `bash scripts/user-breach-check.sh <tenant> <upn>`. Script runs all 10 checks in parallel where possible and dumps raw JSON to `/tmp/remediation-tool/{tenant}/user-breach/<slug>/`. Claude then interprets findings against the rubric in `references/checklist.md` and writes a report.
|
||||
|
||||
- **`sweep <domain>`** -> `bash scripts/tenant-sweep.sh <tenant>`. Script pulls tenant-wide failed sign-ins (30d), successful non-US sign-ins, directory audits filtered for consent/auth-method/service-principal changes, risky users (if permission granted), B2B guest invites, user location profile. Claude summarizes priority findings.
|
||||
|
||||
- **`signins`** — build ad-hoc `curl` against Graph `/auditLogs/signIns` with the requested filter.
|
||||
|
||||
- **`consent-url <domain>`** — emit `https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id=fabb3421-8b34-484b-bc17-e46de9703418&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient` plus the note that the nativeclient landing page "looks like an error, that's normal."
|
||||
|
||||
- **`remediate`** — see Remediation section below.
|
||||
|
||||
### 4. Write the report
|
||||
|
||||
Location: `clients/{client-slug}/reports/YYYY-MM-DD-{action}.md` (UTC date). Derive the client slug from the domain:
|
||||
- `cascadestucson.com` -> `cascades-tucson`
|
||||
- `foobarwidgets.com` -> `foobar-widgets`
|
||||
- Use existing `clients/<slug>/` directory if present; if no matching client dir exists, ask the user for the slug before creating one.
|
||||
|
||||
Use `templates/breach-report.md` as the skeleton. For single-user checks, fill in per-check findings using raw JSON in `/tmp/remediation-tool/{tenant}/user-breach/<slug>/`.
|
||||
|
||||
### 5. Summarize to the user
|
||||
|
||||
Short chat summary: top findings, blocked checks (with remediation links), next actions. Save raw JSON artifacts paths in the report for later re-analysis.
|
||||
|
||||
### 6. Auto-commit
|
||||
|
||||
After writing the report, delegate to the **Gitea Agent** to commit with a message like `Remediation report: <action> for <target>`. Do not push unless the user asks.
|
||||
|
||||
---
|
||||
|
||||
## Remediation (gated)
|
||||
|
||||
When the user runs `/remediation-tool remediate <upn> <action>`:
|
||||
|
||||
1. **Confirm read-only context first**: the skill must have recently run a `check <upn>` in this session (check `/tmp/remediation-tool/{tenant}/user-breach/<slug>/` exists). If not, tell the user to run the check first.
|
||||
2. **Display the exact action** that will run (curl command, cmdlet name, parameters).
|
||||
3. **Require explicit `YES` in chat** — not approval via permission prompt. If the user types anything else, abort.
|
||||
4. Execute via Graph/Exchange REST. Capture response to a remediation log at `/tmp/remediation-tool/{tenant}/remediation/<slug>-YYYY-MM-DDTHHMMSS.json`.
|
||||
5. Update the user's report with a `## Remediation Actions` section appending what was done and the result.
|
||||
|
||||
Allowed `<action>` values:
|
||||
|
||||
| Action | API | Result |
|
||||
|---|---|---|
|
||||
| `password-reset` | Graph `PATCH /users/{upn}` with new `passwordProfile` | Forces sign-in; revokes refresh tokens |
|
||||
| `revoke-sessions` | Graph `POST /users/{upn}/revokeSignInSessions` | Kills all active sessions |
|
||||
| `disable-forwarding` | Exchange REST `Set-Mailbox -ForwardingAddress $null -ForwardingSmtpAddress $null -DeliverToMailboxAndForward $false` | Clears all forwarding |
|
||||
| `remove-inbox-rules` | Exchange REST `Remove-InboxRule` for each non-default rule | Asks which to keep first |
|
||||
| `disable-account` | Graph `PATCH /users/{upn}` with `accountEnabled: false` | Hard disable |
|
||||
|
||||
---
|
||||
|
||||
## Arguments
|
||||
|
||||
`$ARGUMENTS` — the full invocation text. Parse freely; common forms:
|
||||
|
||||
- `check john.trozzi@cascadestucson.com`
|
||||
- `sweep cascadestucson.com`
|
||||
- `signins cascadestucson.com --user megan.hiatt@cascadestucson.com --failed-only --days 30`
|
||||
- `consent-url cascadestucson.com`
|
||||
- `remediate megan.hiatt@cascadestucson.com password-reset`
|
||||
|
||||
If the user's phrasing is loose ("check john's box at cascades", "who's being attacked"), infer intent from CONTEXT.md and session logs. Prefer asking one clarifying question to guessing.
|
||||
|
||||
---
|
||||
|
||||
## Scope and references
|
||||
|
||||
- Detailed check rubric: `.claude/skills/remediation-tool/references/checklist.md`
|
||||
- Permission/role gotchas + consent URLs: `.claude/skills/remediation-tool/references/gotchas.md`
|
||||
- Endpoint cheatsheet: `.claude/skills/remediation-tool/references/graph-endpoints.md`
|
||||
- Report template: `.claude/skills/remediation-tool/templates/breach-report.md`
|
||||
- Memory note on what the tool IS: `.claude/memory/feedback_365_remediation_tool.md`
|
||||
@@ -72,9 +72,32 @@ Format credentials as:
|
||||
|
||||
## After Saving
|
||||
|
||||
Before committing, emit a **Change Summary** block for the user to review:
|
||||
|
||||
```
|
||||
## Change Summary (this session)
|
||||
User: <full_name> (from .claude/identity.json)
|
||||
Machine: <HOSTNAME>
|
||||
|
||||
Files changed:
|
||||
<output of: git status --short>
|
||||
|
||||
Stats:
|
||||
<output of: git diff --stat HEAD>
|
||||
```
|
||||
|
||||
Then:
|
||||
1. Commit with message: "Session log: [brief description of work done]"
|
||||
2. Push to gitea remote (if configured)
|
||||
3. Confirm push was successful
|
||||
3. After push, emit a **Post-commit Summary**:
|
||||
- New commit SHA + message
|
||||
- Author (from `git log -1 --format='%an <%ae>'`)
|
||||
- Files in the commit (from `git show --stat HEAD`)
|
||||
4. Confirm push was successful
|
||||
|
||||
### Why the summary
|
||||
|
||||
In the multi-user setup, commits can land in `main` from either team member. Always attributing author + files makes it obvious who made what change when someone else pulls the repo. Saves re-reading diffs to figure out "wait, when did that happen?"
|
||||
|
||||
## Purpose
|
||||
|
||||
|
||||
@@ -7,23 +7,33 @@ bash .claude/scripts/sync.sh
|
||||
```
|
||||
|
||||
The script automatically:
|
||||
1. Stages and commits local changes (if any)
|
||||
2. Fetches and pulls remote changes
|
||||
3. Pushes local changes
|
||||
4. Reports sync status
|
||||
1. Stages and commits local changes (attributed to the current user from `.claude/identity.json`)
|
||||
2. Fetches remote and shows **incoming commits with authors** before pulling
|
||||
3. Shows **outgoing commits with authors** before pushing
|
||||
4. Pulls (rebase), then pushes
|
||||
5. Prints a final change summary (who committed what, on which side)
|
||||
|
||||
After the script completes, report the 3 most recent session logs:
|
||||
## After the script completes
|
||||
|
||||
The script emits a "Sync Summary" block. Relay the key bits to the user:
|
||||
|
||||
- **Incoming from remote:** N commits. If N > 0, list commits as `<short-sha> <author> — <message>` so the user immediately sees what Howard / Mike / other teammates pushed since their last sync.
|
||||
- **Outgoing to remote:** M commits by the current user (this is what they're publishing).
|
||||
- **Net file changes in this sync:** output of `git diff --stat <prev-HEAD>..HEAD -- . ':(exclude)session-logs'` (or similar scoping) so the user sees the meaningful edits, not noise.
|
||||
|
||||
Then report the 3 most recent session logs:
|
||||
```bash
|
||||
ls -t session-logs/*.md projects/*/session-logs/*.md clients/*/session-logs/*.md 2>/dev/null | head -3
|
||||
```
|
||||
|
||||
## Conflict Resolution
|
||||
## Conflict resolution
|
||||
|
||||
- **Session logs:** Keep both, rename with machine suffix
|
||||
- **credentials.md:** Do NOT auto-merge, report to user
|
||||
- **Other files:** Standard git conflict resolution
|
||||
- **Session logs:** Keep both, rename with machine suffix. Note which user authored each conflicting side.
|
||||
- **credentials.md:** Do NOT auto-merge, report to user.
|
||||
- **Other files:** Standard git conflict resolution. When presenting a conflict, include the author of the conflicting commits on each side so the user can coordinate (e.g., "Howard changed this in commit abc123 on 2026-04-15").
|
||||
|
||||
## Error Handling
|
||||
## Error handling
|
||||
|
||||
If push fails with auth error, retry once (transient Gitea auth issue).
|
||||
If pull fails with conflicts, report affected files and ask for guidance.
|
||||
- **Auth failure on push:** retry once (transient Gitea auth issue).
|
||||
- **Pull conflicts:** report affected files + author of each conflicting side, then ask for guidance.
|
||||
- **No identity.json yet:** follow the onboarding flow in CLAUDE.md before syncing.
|
||||
|
||||
169
.claude/commands/syncro.md
Normal file
169
.claude/commands/syncro.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# /syncro — Syncro PSA ticket management
|
||||
|
||||
Create, update, close, comment on, and bill tickets in Syncro PSA.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/syncro Show open tickets summary
|
||||
/syncro ticket <number> View ticket details + comments
|
||||
/syncro create <customer> <subject> Create new ticket
|
||||
/syncro update <number> <status> Update ticket status
|
||||
/syncro close <number> Close/resolve a ticket
|
||||
/syncro comment <number> <text> Add a comment to a ticket
|
||||
/syncro bill <number> Create invoice from ticket time entries
|
||||
/syncro search <query> Search tickets by subject/customer
|
||||
/syncro customers <query> Search customers
|
||||
```
|
||||
|
||||
## API Configuration
|
||||
|
||||
**Base URL:** `https://computerguru.syncromsp.com/api/v1`
|
||||
**API Key:** SOPS vault `msp-tools/syncro.sops.yaml` → `credentials.credential`
|
||||
**Rate limit:** 180 requests/minute per IP
|
||||
**Docs:** https://api-docs.syncromsp.com/
|
||||
|
||||
## Implementation
|
||||
|
||||
When invoked, use the Syncro REST API via `curl`. All requests include `?api_key=<key>` as query parameter (NOT in header — Syncro uses query param auth).
|
||||
|
||||
### Get API key
|
||||
|
||||
```bash
|
||||
API_KEY=$(bash D:/vault/scripts/vault.sh get-field msp-tools/syncro.sops.yaml credentials.credential)
|
||||
BASE="https://computerguru.syncromsp.com/api/v1"
|
||||
```
|
||||
|
||||
If `vault.sh get-field` fails (yq not installed), fall back to:
|
||||
```bash
|
||||
API_KEY=$(sops -d D:/vault/msp-tools/syncro.sops.yaml | python -c "import sys,yaml; print(yaml.safe_load(sys.stdin)['credentials']['credential'])")
|
||||
```
|
||||
|
||||
### Endpoints reference
|
||||
|
||||
#### Tickets
|
||||
|
||||
| Operation | Method | Endpoint | Body |
|
||||
|---|---|---|---|
|
||||
| List tickets | GET | `/tickets?status=<status>&per_page=25` | — |
|
||||
| Get ticket | GET | `/tickets/<id>` | — |
|
||||
| Create ticket | POST | `/tickets` | `{"customer_id": N, "subject": "...", "problem_type": "...", "status": "New"}` |
|
||||
| Update ticket | PUT | `/tickets/<id>` | `{"status": "In Progress", "priority": "..."}` |
|
||||
| Delete ticket | DELETE | `/tickets/<id>` | — |
|
||||
|
||||
**Ticket statuses:** `New`, `In Progress`, `Waiting on Customer`, `Waiting on Vendor`, `Scheduled`, `Resolved`, `Invoiced`, `Closed`
|
||||
|
||||
**Ticket fields (create/update):**
|
||||
- `customer_id` (required for create)
|
||||
- `subject` (required for create)
|
||||
- `problem_type` (string, free-form)
|
||||
- `status` (string, one of the statuses above)
|
||||
- `priority` (string)
|
||||
- `due_date` (ISO date)
|
||||
- `user_id` (assign to tech)
|
||||
- `contact_id` (customer contact)
|
||||
- `ticket_type_id` (ticket category)
|
||||
|
||||
#### Comments (with optional time entry)
|
||||
|
||||
| Operation | Method | Endpoint | Body |
|
||||
|---|---|---|---|
|
||||
| Add comment | POST | `/tickets/<id>/comment` | `{"subject": "Update", "body": "...", "hidden": false, "do_not_email": false}` |
|
||||
| Add comment + time | POST | `/tickets/<id>/comment` | Same as above, PLUS: `"product_id": N, "minutes_spent": 60, "bill_time_now": false` |
|
||||
|
||||
**Comment fields:**
|
||||
- `subject` — comment header (e.g., "Update", "Resolution", "Internal Note")
|
||||
- `body` — comment text (HTML supported)
|
||||
- `hidden` — if true, internal-only (customer can't see)
|
||||
- `do_not_email` — if true, don't email customer about this comment
|
||||
- `product_id` — labor product ID (see labor products table below). Adds billable time to the ticket.
|
||||
- `minutes_spent` — integer, minutes of work (60 = 1hr minimum in most cases)
|
||||
- `bill_time_now` — if true, immediately creates a charge (equivalent to "Charge now" checkbox in GUI)
|
||||
|
||||
**This is the primary way to log time.** Comment + time in one call mirrors the GUI workflow exactly. Timer entries (`/tickets/{id}/timer_entry`) exist but are rarely used.
|
||||
|
||||
#### Customers
|
||||
|
||||
| Operation | Method | Endpoint |
|
||||
|---|---|---|
|
||||
| List/search | GET | `/customers?query=<search>&per_page=25` |
|
||||
| Get customer | GET | `/customers/<id>` |
|
||||
| Create customer | POST | `/customers` |
|
||||
|
||||
#### Timer Entries (add time to ticket)
|
||||
|
||||
| Operation | Method | Endpoint | Body |
|
||||
|---|---|---|---|
|
||||
| Add time | POST | `/tickets/<id>/timer_entry` | `{"start_at": "ISO8601", "end_at": "ISO8601", "notes": "...", "billable": true, "product_id": N}` |
|
||||
| List timers | GET | `/ticket_timers?ticket_id=<id>` |
|
||||
|
||||
**IMPORTANT:** `product_id` must be a **labor product**, not an invoice product. Common labor products:
|
||||
- `1190473` — Labor - Remote Business (standard remote work)
|
||||
- `26118` — Labor - Onsite Business
|
||||
- `26184` — Labor - Emergency or After Hours Business
|
||||
- `9269129` — Labor - Prepaid Project Labor
|
||||
- `9269124` — Labor - Internal Labor
|
||||
- `26117` — Fee - Travel Time
|
||||
- `68055` — Labor - Website Labor
|
||||
|
||||
#### Invoices
|
||||
|
||||
| Operation | Method | Endpoint | Body |
|
||||
|---|---|---|---|
|
||||
| List invoices | GET | `/invoices?per_page=25` |
|
||||
| Get invoice | GET | `/invoices/<id>` |
|
||||
| Create from ticket | POST | `/invoices` | `{"ticket_id": N, "customer_id": N, "category": "Standard"}` |
|
||||
| Delete invoice | DELETE | `/invoices/<id>` | — |
|
||||
|
||||
**"Make Invoice" flow:** Timer entries on the ticket become invoice line items when you POST `/invoices` with the ticket_id. This is the equivalent of clicking "Make Invoice" in the GUI.
|
||||
|
||||
#### Invoice Line Items
|
||||
|
||||
| Operation | Method | Endpoint | Body |
|
||||
|---|---|---|---|
|
||||
| Add line item | POST | `/invoices/<id>/line_items` | `{"item": "...", "quantity": 1, "price": 125.00, "product_id": N}` |
|
||||
|
||||
### Display formatting
|
||||
|
||||
When showing ticket lists, format as:
|
||||
|
||||
```
|
||||
#32164 New Jerry Burger Own cloud thing again
|
||||
#32163 New LeeAnn Parkinson Remote - Jim cant access his email
|
||||
#32162 Invoiced Len's Auto Brokerage Server upgrade
|
||||
```
|
||||
|
||||
When showing ticket detail, include:
|
||||
- Ticket number, subject, status, priority
|
||||
- Customer name + contact
|
||||
- Created date, due date, last updated
|
||||
- Assigned tech
|
||||
- Comments (most recent first, truncated to last 5)
|
||||
- Time entries if any
|
||||
- Billing status
|
||||
|
||||
### Billing workflow
|
||||
|
||||
When `/syncro bill <number>` is called:
|
||||
1. Get ticket details
|
||||
2. Ask: "How many minutes + labor type?" (default: 60 min, Labor - Remote Business)
|
||||
3. Add comment with time: `POST /tickets/{id}/comment` with `product_id`, `minutes_spent`, `bill_time_now: false`, and work notes as body
|
||||
4. Then create invoice: `POST /invoices` with `{"ticket_id": N, "customer_id": N, "category": "Standard"}`
|
||||
5. Update ticket status to "Invoiced"
|
||||
|
||||
**The flow mirrors the GUI: add comment with time attached → Make Invoice.**
|
||||
|
||||
When `/syncro comment <number> <text> --time 60 --labor remote` is called:
|
||||
- Post the comment with time in one API call
|
||||
- `--labor` maps to product IDs: `remote` → 1190473, `onsite` → 26118, `emergency` → 26184, `project` → 9269129, `internal` → 9269124, `travel` → 26117, `website` → 68055
|
||||
|
||||
### Error handling
|
||||
|
||||
- 401: API key invalid or expired
|
||||
- 404: ticket/customer/invoice not found
|
||||
- 422: validation error (show the error message from response body)
|
||||
- 429: rate limited (wait 60s and retry)
|
||||
|
||||
### Integration with session logs
|
||||
|
||||
When closing a ticket (`/syncro close`), offer to create a session log entry in `clients/<customer>/session-logs/` documenting what was resolved. Pull the ticket subject, comments, and resolution into a structured log.
|
||||
@@ -10,6 +10,11 @@
|
||||
- [Matomo Analytics](reference_matomo_analytics.md) - Self-hosted analytics at analytics.azcomputerguru.com, site IDs, tracking for all 3 sites
|
||||
- [Dataforth Contact - AJ](reference_dataforth_contact.md) - AJ at Dataforth, dataforthgit@ email forwarding to him
|
||||
- [TickTick Integration](reference_ticktick_integration.md) - OAuth API integration, MCP server, SOPS vault creds, project/task CRUD
|
||||
- [Client Docs Structure](reference_client_docs_structure.md) - clients/<name>/docs/ layout (overview, network, servers, cloud, security, rmm, issues). Template at clients/_client_template/.
|
||||
- [MSP Audit Scripts](reference_msp_audit_scripts.md) - server_audit.ps1 / workstation_audit.ps1 at projects/msp-tools/msp-audit-scripts/. ScreenConnect 80-char rule.
|
||||
|
||||
## Users
|
||||
- [Howard Enos](user_howard.md) — Mike's brother, technician, full trust/access. Known machine: ACG-TECH03L.
|
||||
|
||||
## Feedback
|
||||
- [D2TESTNAS SSH Access](feedback_d2testnas_ssh.md) - Use root@192.168.0.9 with Paper123!@#, not sysadmin
|
||||
@@ -20,6 +25,8 @@
|
||||
- [ACG-5070 Workstation Setup](reference_workstation_setup.md) - Windows 11 Pro clean install 2026-03-30, replaced CachyOS. All tools installed.
|
||||
|
||||
## Project
|
||||
- [Sync script bug — untracked files](project_sync_script_bug.md) — Flagged for Mike. `.claude/scripts/sync.sh` line 53 misses untracked-only changes; one-line fix included.
|
||||
- [MasterBooter Side Project](project_masterbooter.md) — Howard's Rust+Slint Windows deployment toolkit at C:\MasterBooter, separate from client work. Do not log to clients/.
|
||||
- [Audio Processor Architecture](project_audio_processor_architecture.md) - Segment-first pipeline: detect breaks before transcription for complete content capture
|
||||
- [Neptune Email Routing Issues](project_email_routing_neptune.md) - Multiple clients (devcon, Sorensen/rieussetcorp) have email not routing properly from Neptune
|
||||
- [Neptune SBR Email Routing Setup](project_neptune_sbr_email_routing.md) - Full SBR routing chain, config file locations, MailProtector integration, access methods
|
||||
|
||||
@@ -10,6 +10,8 @@ When user says "365 remediation tool" or "remediation tool", they ALWAYS mean th
|
||||
|
||||
**How to apply:** Authenticate directly via Graph API using the app's client secret from SOPS vault (`msp-tools/claude-msp-access-graph-api.sops.yaml`), get tenant ID from OpenID discovery for the target domain, and query Graph API endpoints directly. No browser/UI needed.
|
||||
|
||||
**Preferred invocation: use the `/remediation-tool` skill** (`.claude/skills/remediation-tool/`, also surfaces as a `/remediation-tool` command). It wraps tenant resolution, token caching, the 10-point user breach check, and tenant-wide sweep. Remediation actions are gated behind explicit `YES` confirmation. Reference docs at `references/gotchas.md`, `references/graph-endpoints.md`, `references/checklist.md`.
|
||||
|
||||
### Directory Role Requirements (discovered 2026-04-01)
|
||||
|
||||
Graph API permissions alone are NOT sufficient for privileged operations. The service principal also needs Entra directory roles assigned per-tenant:
|
||||
|
||||
31
.claude/memory/project_masterbooter.md
Normal file
31
.claude/memory/project_masterbooter.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: MasterBooter Side Project
|
||||
description: Howard's personal side project at C:\MasterBooter — Windows deployment toolkit, separate from client/MSP work. Do not mix with clients/ content.
|
||||
type: project
|
||||
---
|
||||
|
||||
MasterBooter is Howard's personal Rust + Slint Windows deployment toolkit at `C:\MasterBooter`. Single-portable-EXE targeting IT/MSP/repair-shop techs. Four modes: Backup/Restore, Windows Deploy, WinPE Builder (WinRE-based), System Prep. Public GitHub repo: `Howweird/Masterbooter`.
|
||||
|
||||
**Why:** Side project separate from Arizona Computer Guru client work. Howard is learning Rust through it — code is heavily commented by design. Not a commercial product yet, no paying customers.
|
||||
|
||||
**How to apply:**
|
||||
- When Howard mentions MasterBooter, WinPE builder, winpe.rs, deploy.rs, etc., context is `C:\MasterBooter`, NOT the `clients/` folder in ClaudeTools.
|
||||
- Don't log MasterBooter sessions to `clients/` — they are personal project work, not customer engagements.
|
||||
- Project has its own `C:\MasterBooter\CLAUDE.md` with its own rules. Follow those when in that directory.
|
||||
- Heavy comments are intentional (learning), not tech debt.
|
||||
|
||||
**Key docs in C:\MasterBooter:**
|
||||
- `VISION.md` — goals, 4 modes
|
||||
- `REQUIREMENTS.md` — feature tracking (sections 1-10 complete, Section 11 added 2026-04-17 with F1-F25 planned)
|
||||
- `DECISIONS.md` — ADRs (ADR-001 through ADR-014, Rust/Slint switch is ADR-005)
|
||||
- `EXPANSION_PLAN.md` — full roadmap added 2026-04-17, phased execution plan
|
||||
- `TODO_CLEANUP.md` — refactor backlog from March 2026 code review
|
||||
- `CHANGELOG.md` — actively maintained
|
||||
|
||||
**Current status (2026-04-17):** v0.2.1 released. Phase 1 reliability work starting — logging, tempfile, DISM /English, quick-xml, tests, CLI, GHA. Then 26 new features (F1-F25) across 4 tiers + tool swaps.
|
||||
|
||||
**Reference programs Howard studies for ideas** (all in `C:\Users\howar\ClaudeSourceFiles\` or `C:\`):
|
||||
- AMPIPIT (C:\AMPIPIT) — primary Rust+Slint reference
|
||||
- GhostWin — Rust WIM/deploy reference
|
||||
- d7x (C:\Users\howar\ClaudeSourceFiles\d7x) — MSP tool catalog inspiration (55+ bundled tools)
|
||||
- Windows Setup Helper, Unattend Generator, SysprepPreparator, PhoenixPE
|
||||
23
.claude/memory/project_sync_script_bug.md
Normal file
23
.claude/memory/project_sync_script_bug.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Sync script bug — untracked files
|
||||
description: Flagged for Mike — .claude/scripts/sync.sh misses untracked-only changes
|
||||
type: project
|
||||
---
|
||||
|
||||
`.claude/scripts/sync.sh` line 53 uses `git diff-index --quiet HEAD --` to detect local changes. This only flags **tracked** files with modifications. Brand-new untracked files (a new report, new session log, new memory) will NOT be detected on their own — they only get swept up when a tracked file is also dirty (because `git add -A` then runs).
|
||||
|
||||
Symptom seen 2026-04-17 by Howard: added a single new report file, ran /sync, script said "No local changes to commit" and did nothing. Workaround was `git add <file>` first, then re-run.
|
||||
|
||||
**Why:** `git diff-index` ignores untracked files by design. Needs `git status --porcelain` (any output = changes) or equivalent.
|
||||
|
||||
**How to apply:** Mike — small one-line fix in `.claude/scripts/sync.sh`. Suggested replacement:
|
||||
|
||||
```bash
|
||||
# Before (line 53):
|
||||
if ! git diff-index --quiet HEAD -- 2>/dev/null; then
|
||||
|
||||
# After:
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
```
|
||||
|
||||
Also applies to the Sync Summary's `git diff --stat $LOCAL_BEFORE..HEAD` — may need review to make sure the summary range still makes sense after the detection fix.
|
||||
33
.claude/memory/reference_client_docs_structure.md
Normal file
33
.claude/memory/reference_client_docs_structure.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: Client Documentation Structure
|
||||
description: Howard's MSP client docs live under clients/<name>/docs/ with a standard subfolder layout (overview, network, servers, cloud, security, rmm, issues). Template at clients/_client_template/.
|
||||
type: reference
|
||||
---
|
||||
|
||||
Each active client has structured Markdown documentation under `clients/<client-name>/docs/`:
|
||||
|
||||
| File / Folder | Purpose |
|
||||
|---|---|
|
||||
| `overview.md` | Company info, contacts, environment summary, device counts |
|
||||
| `network/topology.md` | Switches, APs, cabling, interconnects |
|
||||
| `network/vlans.md` | VLAN table, subnets, inter-VLAN routing |
|
||||
| `network/dns.md` | DNS servers, zones, records, forwarders |
|
||||
| `network/dhcp.md` | Scopes, reservations, relay config |
|
||||
| `network/firewall.md` | Rules, NAT, VPN, interfaces |
|
||||
| `network/wifi.md` | SSIDs, security, AP assignments |
|
||||
| `servers/<name>.md` | Per-server docs (use `server_template.md`) |
|
||||
| `cloud/m365.md` | Tenant, licensing, Exchange, Entra ID |
|
||||
| `cloud/azure.md` | Subscriptions, VMs, networking |
|
||||
| `security/antivirus.md` | EDR/AV product, deployment status |
|
||||
| `security/backup.md` | Backup jobs, targets, DR plan |
|
||||
| `rmm/rmm.md` | RMM product, agent counts, patch policy |
|
||||
| `issues/log.md` | Historical incident log with root causes |
|
||||
| `billing-log.md` | Per-client billing / work log |
|
||||
|
||||
Clients currently documented (imported 2026-04-16 from Howard's `C:\Users\howar\Clients`):
|
||||
anaise, cascades-tucson, dataforth, instrumental-music-center, khalsa, kittle, lens-auto-brokerage.
|
||||
|
||||
Credentials NEVER go inline in these docs — reference SOPS vault instead:
|
||||
`clients/<name>/<system>.sops.yaml` field path.
|
||||
|
||||
The template at `clients/_client_template/` is the scaffold for new clients.
|
||||
29
.claude/memory/reference_msp_audit_scripts.md
Normal file
29
.claude/memory/reference_msp_audit_scripts.md
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: MSP Audit Scripts
|
||||
description: server_audit.ps1 and workstation_audit.ps1 for on-demand auditing via ScreenConnect Toolbox. Also hosted on GitHub (Howweird/msp-audit-scripts) for remote fetch.
|
||||
type: reference
|
||||
---
|
||||
|
||||
Location in claudetools: `projects/msp-tools/msp-audit-scripts/`.
|
||||
|
||||
Scripts:
|
||||
- `server_audit.ps1` — Full server + AD + security audit, outputs JSON to `C:\Temp\`.
|
||||
- `workstation_audit.ps1` — Full workstation audit, outputs JSON to `C:\Temp\`.
|
||||
- `README.md` — Usage notes.
|
||||
|
||||
Remote fetch URL pattern (for ScreenConnect Toolbox):
|
||||
```
|
||||
https://raw.githubusercontent.com/Howweird/msp-audit-scripts/master/server_audit.ps1
|
||||
https://raw.githubusercontent.com/Howweird/msp-audit-scripts/master/workstation_audit.ps1
|
||||
```
|
||||
|
||||
ScreenConnect Toolbox PowerShell rules (IMPORTANT):
|
||||
- No line may exceed 80 chars — Toolbox silently truncates long lines
|
||||
- Store long URLs/paths in variables first
|
||||
- Use multi-line try/catch blocks, never single-line
|
||||
- Paste whole scripts as one command — no inline comments between blocks
|
||||
|
||||
Utility scripts also at `projects/msp-tools/utilities/`:
|
||||
- `clean_printer_ports.ps1`
|
||||
- `win11_upgrade.ps1`
|
||||
- `screenconnect-toolbox-commands.txt` (saved Toolbox one-liners)
|
||||
13
.claude/memory/user_howard.md
Normal file
13
.claude/memory/user_howard.md
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
name: Howard Enos — team member
|
||||
description: Howard is Mike's brother and employee at AZ Computer Guru. Technician role with full trust and full access. Uses claudetools for MSP tracking and daily client work.
|
||||
type: user
|
||||
---
|
||||
|
||||
Howard Enos is a technician at Arizona Computer Guru LLC and Mike Swanson's brother. He has full access to all systems, credentials, and client data — same level as Mike. No permission gating.
|
||||
|
||||
Known machine: ACG-TECH03L (laptop). Desktop hostname TBD (will be registered on first sync).
|
||||
|
||||
When working with Howard, treat him exactly as you would Mike — same context loading, same credential access, same capabilities. He uses claudetools for MSP work tracking, client management, and daily IT operations.
|
||||
|
||||
His git commits should show `Howard Enos <howard@azcomputerguru.com>`.
|
||||
7
.claude/messages/for-howard.md
Normal file
7
.claude/messages/for-howard.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Messages for Howard
|
||||
|
||||
Check this file at sync. Delete items after you've addressed them.
|
||||
|
||||
---
|
||||
|
||||
_No pending messages._
|
||||
@@ -1,118 +1,158 @@
|
||||
#!/bin/bash
|
||||
# ClaudeTools Bidirectional Sync Script
|
||||
# Ensures proper pull BEFORE push on all machines
|
||||
# Prints incoming/outgoing change summary with author attribution
|
||||
|
||||
set -e # Exit on error
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Detect machine name
|
||||
# Machine + timestamp
|
||||
if [ -n "$COMPUTERNAME" ]; then
|
||||
MACHINE="$COMPUTERNAME"
|
||||
else
|
||||
MACHINE=$(hostname)
|
||||
fi
|
||||
|
||||
# Timestamp
|
||||
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
echo -e "${GREEN}[OK]${NC} Starting ClaudeTools sync from $MACHINE at $TIMESTAMP"
|
||||
|
||||
# Navigate to ClaudeTools directory
|
||||
if [ -d "$HOME/ClaudeTools" ]; then
|
||||
cd "$HOME/ClaudeTools"
|
||||
elif [ -d "/d/ClaudeTools" ]; then
|
||||
cd "/d/ClaudeTools"
|
||||
elif [ -d "D:/ClaudeTools" ]; then
|
||||
cd "D:/ClaudeTools"
|
||||
else
|
||||
echo -e "${RED}[ERROR]${NC} ClaudeTools directory not found"
|
||||
# Navigate to ClaudeTools directory (check common locations)
|
||||
for candidate in "$HOME/ClaudeTools" "/d/ClaudeTools" "D:/ClaudeTools" "/d/claudetools" "D:/claudetools"; do
|
||||
if [ -d "$candidate" ]; then
|
||||
cd "$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d ".git" ]; then
|
||||
echo -e "${RED}[ERROR]${NC} Not in a git working tree"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}[OK]${NC} Working directory: $(pwd)"
|
||||
|
||||
# Phase 1: Check and commit local changes
|
||||
# Load user identity
|
||||
USER_DISPLAY="unknown"
|
||||
USER_GITEA=""
|
||||
if [ -f ".claude/identity.json" ]; then
|
||||
USER_DISPLAY=$(python -c "import json,sys; d=json.load(open('.claude/identity.json')); print(d.get('full_name', d.get('user','unknown')))" 2>/dev/null || echo "unknown")
|
||||
USER_GITEA=$(python -c "import json,sys; d=json.load(open('.claude/identity.json')); print(d.get('user',''))" 2>/dev/null || echo "")
|
||||
fi
|
||||
echo -e "${GREEN}[OK]${NC} Syncing as: $USER_DISPLAY (machine: $MACHINE)"
|
||||
|
||||
# Phase 1: Local changes
|
||||
echo ""
|
||||
echo "=== Phase 1: Local Changes ==="
|
||||
echo "=== Phase 1: Local changes ==="
|
||||
|
||||
if ! git diff-index --quiet HEAD -- 2>/dev/null; then
|
||||
echo -e "${YELLOW}[INFO]${NC} Local changes detected"
|
||||
|
||||
# Show status
|
||||
echo -e "${YELLOW}[INFO]${NC} Local changes detected:"
|
||||
git status --short
|
||||
echo ""
|
||||
|
||||
# Stage all changes
|
||||
echo -e "${GREEN}[OK]${NC} Staging all changes..."
|
||||
git add -A
|
||||
|
||||
# Commit with timestamp
|
||||
COMMIT_MSG="sync: Auto-sync from $MACHINE at $TIMESTAMP
|
||||
|
||||
Synced files:
|
||||
- Session logs updated
|
||||
- Latest context and credentials
|
||||
- Command/directive updates
|
||||
# Commit message (Co-Authored-By uses local git user if configured)
|
||||
COMMIT_MSG="sync: auto-sync from $MACHINE at $TIMESTAMP
|
||||
|
||||
Author: $USER_DISPLAY
|
||||
Machine: $MACHINE
|
||||
Timestamp: $TIMESTAMP
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
Timestamp: $TIMESTAMP"
|
||||
|
||||
git commit -m "$COMMIT_MSG"
|
||||
echo -e "${GREEN}[OK]${NC} Changes committed"
|
||||
echo -e "${GREEN}[OK]${NC} Committed."
|
||||
else
|
||||
echo -e "${GREEN}[OK]${NC} No local changes to commit"
|
||||
echo -e "${GREEN}[OK]${NC} No local changes to commit."
|
||||
fi
|
||||
|
||||
# Phase 2: Sync with remote (CRITICAL: Pull BEFORE Push)
|
||||
# Phase 2: Remote sync
|
||||
echo ""
|
||||
echo "=== Phase 2: Remote Sync (Pull + Push) ==="
|
||||
echo "=== Phase 2: Fetch + inspect ==="
|
||||
|
||||
# Fetch to see what's available
|
||||
echo -e "${GREEN}[OK]${NC} Fetching from remote..."
|
||||
git fetch origin
|
||||
LOCAL_BEFORE=$(git rev-parse HEAD)
|
||||
|
||||
# Check if remote has updates
|
||||
LOCAL=$(git rev-parse main)
|
||||
REMOTE=$(git rev-parse origin/main)
|
||||
echo -e "${GREEN}[OK]${NC} Fetching from origin..."
|
||||
git fetch origin --quiet
|
||||
|
||||
if [ "$LOCAL" != "$REMOTE" ]; then
|
||||
echo -e "${YELLOW}[INFO]${NC} Remote has updates, pulling..."
|
||||
LOCAL=$(git rev-parse HEAD)
|
||||
REMOTE=$(git rev-parse origin/main 2>/dev/null || git rev-parse origin/master 2>/dev/null || echo "$LOCAL")
|
||||
REMOTE_BRANCH="origin/main"
|
||||
if ! git rev-parse origin/main >/dev/null 2>&1; then
|
||||
REMOTE_BRANCH="origin/master"
|
||||
fi
|
||||
|
||||
# Pull with rebase
|
||||
# Count and show incoming
|
||||
INCOMING_COUNT=$(git rev-list --count HEAD..$REMOTE_BRANCH 2>/dev/null || echo 0)
|
||||
OUTGOING_COUNT=$(git rev-list --count $REMOTE_BRANCH..HEAD 2>/dev/null || echo 0)
|
||||
|
||||
if [ "$INCOMING_COUNT" -gt 0 ]; then
|
||||
echo ""
|
||||
echo -e "${CYAN}--- Incoming: $INCOMING_COUNT commits from remote ---${NC}"
|
||||
git log --oneline --format=' %C(yellow)%h%Creset %C(cyan)%an%Creset %s %C(dim)(%ar)%Creset' HEAD..$REMOTE_BRANCH | head -30
|
||||
echo ""
|
||||
echo -e "${CYAN}--- Files touched by incoming commits ---${NC}"
|
||||
git diff --stat HEAD..$REMOTE_BRANCH | tail -20
|
||||
else
|
||||
echo -e "${GREEN}[OK]${NC} No incoming changes."
|
||||
fi
|
||||
|
||||
if [ "$OUTGOING_COUNT" -gt 0 ]; then
|
||||
echo ""
|
||||
echo -e "${CYAN}--- Outgoing: $OUTGOING_COUNT commits to remote ---${NC}"
|
||||
git log --oneline --format=' %C(yellow)%h%Creset %C(cyan)%an%Creset %s %C(dim)(%ar)%Creset' $REMOTE_BRANCH..HEAD | head -30
|
||||
fi
|
||||
|
||||
# Phase 3: Pull (if needed)
|
||||
if [ "$INCOMING_COUNT" -gt 0 ]; then
|
||||
echo ""
|
||||
echo "=== Phase 3: Pull (rebase) ==="
|
||||
if git pull origin main --rebase; then
|
||||
echo -e "${GREEN}[OK]${NC} Successfully pulled remote changes"
|
||||
git log --oneline "$LOCAL..origin/main"
|
||||
echo -e "${GREEN}[OK]${NC} Pulled successfully."
|
||||
else
|
||||
echo -e "${RED}[ERROR]${NC} Pull failed - may have conflicts"
|
||||
echo -e "${YELLOW}[INFO]${NC} Resolve conflicts and run sync again"
|
||||
echo -e "${RED}[ERROR]${NC} Pull failed (likely conflicts). Resolve and re-run sync."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Phase 4: Push (if needed)
|
||||
OUTGOING_AFTER_PULL=$(git rev-list --count $REMOTE_BRANCH..HEAD 2>/dev/null || echo 0)
|
||||
if [ "$OUTGOING_AFTER_PULL" -gt 0 ]; then
|
||||
echo ""
|
||||
echo "=== Phase 4: Push ==="
|
||||
if git push origin main; then
|
||||
echo -e "${GREEN}[OK]${NC} Pushed successfully."
|
||||
else
|
||||
echo -e "${RED}[ERROR]${NC} Push failed. Check auth / network."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo -e "${GREEN}[OK]${NC} Already up to date with remote"
|
||||
echo -e "${GREEN}[OK]${NC} Nothing to push."
|
||||
fi
|
||||
|
||||
# Push local changes
|
||||
# Phase 5: Summary
|
||||
echo ""
|
||||
echo -e "${GREEN}[OK]${NC} Pushing local changes to remote..."
|
||||
if git push origin main; then
|
||||
echo -e "${GREEN}[OK]${NC} Successfully pushed to remote"
|
||||
else
|
||||
echo -e "${RED}[ERROR]${NC} Push failed"
|
||||
exit 1
|
||||
echo "=== Sync Summary ==="
|
||||
|
||||
if [ "$INCOMING_COUNT" -gt 0 ]; then
|
||||
# Count commits by author
|
||||
INCOMING_AUTHORS=$(git log --format='%an' $LOCAL_BEFORE..HEAD 2>/dev/null | sort | uniq -c | sort -rn | awk '{printf "%s (%s), ", substr($0, index($0,$2)), $1}' | sed 's/, $//')
|
||||
echo -e "${CYAN}Pulled in:${NC} $INCOMING_COUNT commit(s) — authors: ${INCOMING_AUTHORS:-unknown}"
|
||||
fi
|
||||
if [ "$OUTGOING_AFTER_PULL" -gt 0 ]; then
|
||||
echo -e "${CYAN}Pushed out:${NC} $OUTGOING_AFTER_PULL commit(s) by $USER_DISPLAY"
|
||||
fi
|
||||
if [ "$INCOMING_COUNT" -eq 0 ] && [ "$OUTGOING_AFTER_PULL" -eq 0 ]; then
|
||||
echo -e "${GREEN}Already in sync — no commits moved in either direction.${NC}"
|
||||
fi
|
||||
|
||||
# Phase 3: Report final status
|
||||
echo ""
|
||||
echo "=== Sync Complete ==="
|
||||
echo -e "${GREEN}[OK]${NC} Local branch: $(git rev-parse --abbrev-ref HEAD)"
|
||||
echo -e "${GREEN}[OK]${NC} Current commit: $(git log -1 --oneline)"
|
||||
echo -e "${GREEN}[OK]${NC} Remote status: $(git status -sb | head -1)"
|
||||
echo -e "${GREEN}[OK]${NC} HEAD: $(git log -1 --oneline)"
|
||||
echo -e "${GREEN}[OK]${NC} Status: $(git status -sb | head -1)"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}[SUCCESS]${NC} All machines in sync. Ready to continue work."
|
||||
echo -e "${GREEN}[SUCCESS]${NC} Sync complete."
|
||||
|
||||
9
.claude/settings.json
Normal file
9
.claude/settings.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"permissions": {
|
||||
"defaultMode": "bypassPermissions"
|
||||
},
|
||||
"preferences": {
|
||||
"autoCompact": true,
|
||||
"verbose": false
|
||||
}
|
||||
}
|
||||
46
.claude/skills/remediation-tool/SKILL.md
Normal file
46
.claude/skills/remediation-tool/SKILL.md
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
name: remediation-tool
|
||||
description: |
|
||||
M365 tenant investigation and remediation using the Claude-MSP-Access Graph API app (App ID fabb3421-8b34-484b-bc17-e46de9703418, known as "ComputerGuru - AI Remediation" in customer tenants). Auto-invoke when the user says "remediation tool", "365 remediation", "check <user>'s mailbox/box", "credential stuffing" against an M365 user, "breach check" on an M365 tenant, or needs M365 admin API work that client-credentials Graph + Exchange REST can perform. NOT for CIPP — this is the direct Graph API app.
|
||||
|
||||
Also invoke when the user needs any of: inbox rule enumeration, mailbox forwarding check, delegate/SendAs audit, OAuth consent audit, sign-in log queries, risky user lookup, directory audit queries, B2B guest invite audit against M365.
|
||||
|
||||
Triggers: "365 remediation", "remediation tool", "check <user> box/mailbox/account for breach", "credential stuff*", "who's getting attacked", "foreign sign-in", "inbox rule", "mailbox forward*", "oauth consent" (in MSP context), "tenant sweep", "risky user", "hidden rule", Exchange Online admin API, "adminapi/beta/{tenant}/InvokeCommand".
|
||||
---
|
||||
|
||||
# 365 Remediation Tool
|
||||
|
||||
Read-only by default. All remediation actions require explicit `YES` confirmation in chat (not a permission prompt).
|
||||
|
||||
## Auto-Invocation Behavior
|
||||
|
||||
When triggered automatically (vs. via `/remediation-tool`), follow the same workflow described in `.claude/commands/remediation-tool.md`:
|
||||
|
||||
1. Parse the user's intent into a subcommand (check/sweep/signins/consent-url/remediate).
|
||||
2. Resolve tenant ID from domain.
|
||||
3. Acquire tokens (cached).
|
||||
4. Run checks via scripts in `scripts/`.
|
||||
5. Interpret findings using `references/checklist.md`.
|
||||
6. Write report to `clients/{slug}/reports/YYYY-MM-DD-{action}.md` using `templates/breach-report.md`.
|
||||
7. Chat summary + delegate commit to Gitea agent.
|
||||
|
||||
## Before calling any script, verify
|
||||
|
||||
- The SOPS vault is accessible: `test -f D:/vault/scripts/vault.sh` (Windows) or `test -f ~/vault/scripts/vault.sh` (other).
|
||||
- `jq`, `curl`, `bash` are available.
|
||||
- For Exchange REST checks: confirm the target tenant has **Exchange Administrator** role assigned to the app's service principal (display name "ComputerGuru - AI Remediation"). If any Exchange REST call returns 403, emit the tenant-scoped Entra Roles link from `references/gotchas.md`.
|
||||
- For Identity Protection checks: app manifest must include `IdentityRiskyUser.Read.All` or `.ReadWrite.All`, AND the tenant must have admin-consented after that permission was added. If 403, emit the consent URL.
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Target identifiers**: accept UPN, domain, or tenant GUID. Normalize to tenant GUID internally.
|
||||
- **Token cache**: `/tmp/remediation-tool/{tenant-id}/{scope}.jwt`. TTL 55 minutes. Check `-mmin -55` before reuse.
|
||||
- **Raw JSON artifacts**: `/tmp/remediation-tool/{tenant-id}/{check}/` — keep so the user can re-analyze.
|
||||
- **Reports**: `clients/{slug}/reports/YYYY-MM-DD-{action}.md`. Derive slug from domain (strip TLD, hyphenate).
|
||||
- **UTC dates everywhere**.
|
||||
|
||||
## Scope boundaries
|
||||
|
||||
- **Not a replacement for CIPP.** Use CIPP for bulk baseline configuration, templates, standards alerting. Use this tool for focused investigation and point-in-time remediation.
|
||||
- **Not for creating/modifying Entra apps or Conditional Access policies.** Those are sensitive enough to stay manual in the portal.
|
||||
- **Not for Graph permissions the app doesn't have.** If a call 403s and the scope isn't in the app manifest, stop and tell the user — don't try to work around it.
|
||||
48
.claude/skills/remediation-tool/references/checklist.md
Normal file
48
.claude/skills/remediation-tool/references/checklist.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Breach-Check Rubric
|
||||
|
||||
How to interpret the outputs from `user-breach-check.sh` and `tenant-sweep.sh`.
|
||||
|
||||
## Single-user check — the 10 points
|
||||
|
||||
| # | Check | What "clean" looks like | Red flags |
|
||||
|---|---|---|---|
|
||||
| 1 | Inbox rules (Graph) | Empty, or only benign filters | ForwardTo / RedirectTo / ForwardAsAttachmentTo set; DeleteMessage+MarkAsRead combos; rules filtered on "password", "bank", "invoice", "CEO name", "security"; rules with name like "." or " " (attacker hiding) |
|
||||
| 2 | Mailbox settings / auto-reply | Auto-reply disabled or legitimate | Auto-reply active with external audience + unfamiliar message body |
|
||||
| 3 | Exchange REST (hidden rules, delegates, SendAs, Get-Mailbox forwarding fields) | Only SELF in permissions; no forwarding | **Hidden** inbox rule moving to RSS/Notes/Conversation History; non-SELF FullAccess/SendAs; ForwardingAddress or ForwardingSmtpAddress set to external |
|
||||
| 4 | OAuth consents + app role assignments | Legitimate apps only (Teams, Outlook mobile, BlueMail, etc.); dates match user history | New consent in attack window; unknown app with `Mail.ReadWrite`, `Files.ReadWrite`, `offline_access`; publisher not verified |
|
||||
| 5 | Auth methods | All methods predate the attack window | New phone/Authenticator registered within hours of first suspicious sign-in; duplicate entries with the same device name but different createdDateTime |
|
||||
| 6 | Sign-ins 30d | Consistent US IPs, user's known geography | Any successful sign-in from a country the user never visits; IMAP/POP/Authenticated SMTP client apps (legacy auth); sign-ins from TOR exit nodes or known residential-proxy ranges |
|
||||
| 7 | Directory audits | Only legit admin/system actions | `Update user` by non-admin principal; password reset the user didn't initiate; auth method change from `Microsoft Substrate Management` is normal but repeated changes are not |
|
||||
| 8 | Risky users / risk detections | `riskLevel: none` | Any `medium` or `high`; `riskDetail: userPerformedSecuredPasswordChange` just means resolved — check the original detection |
|
||||
| 9 | Sent items (recent 25) | Normal business correspondence | Blast emails to random external recipients; forwards of internal financial/HR info externally; anything after-hours from an unusual client app |
|
||||
| 10 | Deleted items (recent 25) | Marketing/spam, routine notifications | Deleted security alerts, password-reset emails, MFA notifications, bounce notices the user wouldn't delete — all signs of attacker cleanup |
|
||||
|
||||
### Cross-check rule
|
||||
|
||||
If inbox rules and forwarding are clean **but** sign-ins show successful foreign access — attacker may have used OAuth-based access (check OAuth grants) or already extracted data and cleaned up. Pull sent items + deleted items aggressively and check `/auditLogs/signIns/beta` for non-interactive sign-ins.
|
||||
|
||||
## Tenant-wide sweep — priorities
|
||||
|
||||
| Priority | Signal | Action |
|
||||
|---|---|---|
|
||||
| P1 | User with ≥20 failed sign-ins from ≥2 foreign countries | Likely active credential-stuffing target. Reset password, disable SMTP AUTH, monitor. |
|
||||
| P1 | Successful sign-in from non-US | Verify with user immediately. If not them: force password reset + revoke sessions + full breach check. |
|
||||
| P2 | New OAuth consent to unfamiliar app in attack window | Review app publisher, scopes, and requesting user. Revoke if unknown. |
|
||||
| P2 | B2B guest invite to personal email domain (gmail.com, outlook.com, yahoo.com) | Confirm with inviter it's intentional. Guest invites are a known persistence mechanism. |
|
||||
| P3 | Transport rule created/modified by a non-admin | Transport rules can redirect mail tenant-wide. Review body/actions carefully. |
|
||||
| P3 | Service principal added by non-admin or by "PowerApps Service" unexpectedly | Usually benign, but worth noting. |
|
||||
| P4 | Isolated wrong-password attempt from foreign IP | Record and move on. Single attempts are noise unless repeated. |
|
||||
|
||||
## False positives to filter out
|
||||
|
||||
- `sysadmin@<tenant>` failures during onboarding of the remediation tool itself (error 65001 against app **ComputerGuru - AI Remediation**).
|
||||
- `Microsoft Substrate Management` and `Azure MFA StrongAuthenticationService` routinely update user records — those are not attacker activity.
|
||||
- Our own consent attempts show up as `Consent to application` in directory audits. Filter `sysadmin` + target = ComputerGuru-AI-Remediation during the onboarding window.
|
||||
- `error 50140` "Keep me signed in interrupt" is a browser prompt, not a failed auth.
|
||||
|
||||
## When to escalate beyond this tool
|
||||
|
||||
- Data exfiltration suspected -> pull Unified Audit Log via Purview (this tool does not access UAL).
|
||||
- Tenant-wide phishing campaign -> enable Purview Content Search, quarantine messages.
|
||||
- Domain-joined workstation compromise -> GuruRMM + Bitdefender workflow (see `clients/ace-portables/reports/` for past example).
|
||||
- Attacker still active and exfiltrating -> consider disabling the user via the `remediate` subcommand and rotating the mailbox password at the same time.
|
||||
77
.claude/skills/remediation-tool/references/gotchas.md
Normal file
77
.claude/skills/remediation-tool/references/gotchas.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Gotchas — Permissions, Roles, Consent
|
||||
|
||||
## App identity
|
||||
|
||||
- **App ID (client_id):** `fabb3421-8b34-484b-bc17-e46de9703418`
|
||||
- **Internal name (home tenant / registration):** Claude-MSP-Access
|
||||
- **Display name in customer tenants:** **ComputerGuru - AI Remediation**
|
||||
- **Client secret:** SOPS vault `msp-tools/claude-msp-access-graph-api.sops.yaml` -> field `credentials.credential`
|
||||
|
||||
When searching customer admin portals for the service principal (role assignments, app role assignments, conditional access exclusions), **search for "ComputerGuru - AI Remediation"** — not "Claude-MSP-Access".
|
||||
|
||||
## Per-tenant prerequisites
|
||||
|
||||
Graph API permissions alone are not enough. Most privileged operations require directory roles on the service principal *in that tenant*:
|
||||
|
||||
| Operation | Required directory role |
|
||||
|---|---|
|
||||
| Password reset, user property updates | User Administrator |
|
||||
| Exchange REST (hidden inbox rules, mailbox permissions, SendAs, transport rules, Get-Mailbox) | Exchange Administrator |
|
||||
| Conditional Access policy reads/writes | Conditional Access Administrator OR Security Administrator |
|
||||
| Teams policies | Teams Administrator |
|
||||
|
||||
### How to assign a role to the SP in a customer tenant
|
||||
|
||||
1. Sign into the customer's Entra admin center as Global Admin:
|
||||
`https://entra.microsoft.com/#@{customer-domain}`
|
||||
2. Identity -> Roles & admins -> All roles -> select the role (e.g., Exchange Administrator).
|
||||
3. Add assignments -> search **"ComputerGuru - AI Remediation"** -> Assign (Active, permanent — service principals cannot activate eligible assignments).
|
||||
|
||||
## Admin consent
|
||||
|
||||
When you add new Graph scopes to the app manifest in the home tenant, each customer tenant must re-consent for those scopes to flow into tokens.
|
||||
|
||||
**Admin consent URL (per tenant):**
|
||||
|
||||
```
|
||||
https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id=fabb3421-8b34-484b-bc17-e46de9703418&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient
|
||||
```
|
||||
|
||||
- Customer admin must sign in as Global Admin of that tenant.
|
||||
- The consent page lists all permissions in the current manifest; admin clicks Accept.
|
||||
- Redirect lands on a blank Microsoft "native client" page that looks like an error — **that is normal**. Consent is recorded on Accept, not on redirect success.
|
||||
- Verify consent took effect by checking `/servicePrincipals/{sp-id}/appRoleAssignments` — the timestamps on new grants should be `today`.
|
||||
|
||||
## Diagnosing "required scopes are missing"
|
||||
|
||||
Token returned 403 with `"required scopes are missing in the token"`:
|
||||
|
||||
1. Decode the JWT payload (2nd segment, base64url) and check the `roles` claim.
|
||||
2. If the scope you expected is not in `roles`:
|
||||
- Confirm the scope is in the app's API permissions in the home tenant (not just selected in the picker — must be saved).
|
||||
- Grant admin consent in the home tenant.
|
||||
- Re-run the customer admin consent URL above.
|
||||
3. If the scope IS in `roles` but you still get 403: check for a missing directory role (see table above).
|
||||
|
||||
## Diagnosing Exchange REST 403
|
||||
|
||||
- Invalid token scope: make sure you requested `https://outlook.office365.com/.default` (not the Graph scope).
|
||||
- Missing Exchange Administrator role on the SP in that tenant.
|
||||
- Propagation delay: newly assigned role can take up to 15 minutes to reach Exchange Online. If you just assigned it, wait and retry.
|
||||
|
||||
## Common, benign "failures" in sign-in logs
|
||||
|
||||
- `error 50140` "Keep me signed in interrupt" — KMSI prompt, not a real failure.
|
||||
- `error 65001` "has not consented to use the application" — this fires during onboarding consent and when a user (or admin) signs in before granting consent. If the `appDisplayName` is **ComputerGuru - AI Remediation**, those are our own consent attempts, not attacker activity.
|
||||
- `error 50126` from the sysadmin account during our onboarding is typo/retry noise — check `ipAddress` matches Mike's known IPs before flagging.
|
||||
|
||||
## Tenants where the app is already set up (as of 2026-04-16)
|
||||
|
||||
| Tenant | Tenant ID | Directory roles assigned | Notes |
|
||||
|---|---|---|---|
|
||||
| Valleywide Plastering | 5c53ae9f... | User Administrator | |
|
||||
| Dataforth | 7dfa3ce8... | User Administrator, Exchange Administrator | |
|
||||
| Cascades Tucson | 207fa277-e9d8-4eb7-ada1-1064d2221498 | User Administrator, Exchange Administrator | IdentityRiskyUser scope still not consented as of 2026-04-16 |
|
||||
| Grabblaw | 032b383e-96e4-491b-880d-3fd3295672c3 | none | Consent broken (2026-03-31); Reyna needs full access to Jsosa mailbox |
|
||||
|
||||
Keep this table updated when you roll out to a new tenant.
|
||||
144
.claude/skills/remediation-tool/references/graph-endpoints.md
Normal file
144
.claude/skills/remediation-tool/references/graph-endpoints.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# Graph + Exchange REST Cheatsheet
|
||||
|
||||
All examples assume `$GT` = Graph token, `$EXO` = Exchange token, `$TID` = tenant ID, `$UPN`/`$UID` = user identifiers.
|
||||
|
||||
## Graph API (`https://graph.microsoft.com/v1.0`)
|
||||
|
||||
### User lookup / status
|
||||
|
||||
```bash
|
||||
# By UPN
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users/$UPN?\$select=id,displayName,userPrincipalName,mail,accountEnabled,createdDateTime,lastPasswordChangeDateTime"
|
||||
|
||||
# All users (filter, paged)
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users?\$top=999&\$filter=accountEnabled%20eq%20true"
|
||||
```
|
||||
|
||||
### Mailbox
|
||||
|
||||
```bash
|
||||
# Visible inbox rules (Graph v1.0 — does NOT return hidden rules)
|
||||
/users/$UPN/mailFolders/inbox/messageRules
|
||||
|
||||
# Mailbox settings (auto-reply, delegates meeting option, NOT forwarding flags)
|
||||
/users/$UPN/mailboxSettings
|
||||
|
||||
# Recent sent / deleted
|
||||
/users/$UPN/mailFolders/sentitems/messages?$top=25&$orderby=sentDateTime%20desc
|
||||
/users/$UPN/mailFolders/deleteditems/messages?$top=25&$orderby=receivedDateTime%20desc
|
||||
```
|
||||
|
||||
### Authentication methods
|
||||
|
||||
```bash
|
||||
/users/$UPN/authentication/methods
|
||||
# Watch for new methods added within the attack window
|
||||
```
|
||||
|
||||
### OAuth + app role assignments
|
||||
|
||||
```bash
|
||||
/users/$UPN/oauth2PermissionGrants # user-level consents
|
||||
/users/$UPN/appRoleAssignments # apps assigned to this user
|
||||
/servicePrincipals/$SP_ID/appRoleAssignments # what scopes a SP has
|
||||
```
|
||||
|
||||
### Sign-ins (needs Entra ID P1 or higher)
|
||||
|
||||
```bash
|
||||
# Interactive sign-ins v1.0 (does NOT include non-interactive/service-principal)
|
||||
/auditLogs/signIns?$filter=userId eq '$UID' and createdDateTime ge $FROM&$top=200
|
||||
|
||||
# All sign-in event types (beta endpoint)
|
||||
/beta/auditLogs/signIns?$filter=userId eq '$UID' and (signInEventTypes/any(t:t eq 'nonInteractiveUser'))
|
||||
|
||||
# Foreign successful sign-ins tenant-wide
|
||||
/auditLogs/signIns?$filter=(status/errorCode eq 0) and (location/countryOrRegion ne 'US')
|
||||
```
|
||||
|
||||
### Directory audits
|
||||
|
||||
```bash
|
||||
# Changes targeting a specific user
|
||||
/auditLogs/directoryAudits?$filter=targetResources/any(t:t/id eq '$UID')
|
||||
|
||||
# Tenant-wide consent / auth-method / role events
|
||||
/auditLogs/directoryAudits?$filter=activityDateTime ge $FROM
|
||||
# Then client-side filter by activityDisplayName ~ Consent|Authentication Method|Add service principal|Add member to role
|
||||
```
|
||||
|
||||
### Identity Protection (needs IdentityRiskyUser.Read.All)
|
||||
|
||||
```bash
|
||||
/identityProtection/riskyUsers
|
||||
/identityProtection/riskyUsers/$UID
|
||||
/identityProtection/riskDetections?$filter=userId eq '$UID'
|
||||
```
|
||||
|
||||
### B2B guests
|
||||
|
||||
```bash
|
||||
# Get guest by gmail/external address
|
||||
/users?$filter=startswith(userPrincipalName,'dunedolly21')
|
||||
|
||||
# Invite audits
|
||||
/auditLogs/directoryAudits?$filter=activityDisplayName eq 'Invite external user'
|
||||
```
|
||||
|
||||
## Exchange Online REST (`https://outlook.office365.com/adminapi/beta/{tenant-id}/InvokeCommand`)
|
||||
|
||||
POST with JSON body `{"CmdletInput":{"CmdletName":"<cmdlet>","Parameters":{...}}}`. Token scope: `https://outlook.office365.com/.default`.
|
||||
|
||||
### Inbox rules (INCLUDING hidden)
|
||||
|
||||
```json
|
||||
{"CmdletInput":{"CmdletName":"Get-InboxRule","Parameters":{"Mailbox":"user@domain.com","IncludeHidden":true}}}
|
||||
```
|
||||
|
||||
Why this matters: attackers commonly create hidden rules that Graph v1.0 cannot see.
|
||||
|
||||
### Mailbox forwarding / properties
|
||||
|
||||
```json
|
||||
{"CmdletInput":{"CmdletName":"Get-Mailbox","Parameters":{"Identity":"user@domain.com"}}}
|
||||
```
|
||||
|
||||
Check: `ForwardingAddress`, `ForwardingSmtpAddress`, `DeliverToMailboxAndForward`, `GrantSendOnBehalfTo`, `HiddenFromAddressListsEnabled`.
|
||||
|
||||
### Mailbox permissions (delegates / FullAccess)
|
||||
|
||||
```json
|
||||
{"CmdletInput":{"CmdletName":"Get-MailboxPermission","Parameters":{"Identity":"user@domain.com"}}}
|
||||
```
|
||||
|
||||
Filter out `NT AUTHORITY\\SELF` — anything else is a delegate.
|
||||
|
||||
### SendAs permissions
|
||||
|
||||
```json
|
||||
{"CmdletInput":{"CmdletName":"Get-RecipientPermission","Parameters":{"Identity":"user@domain.com"}}}
|
||||
```
|
||||
|
||||
### Transport rules (tenant-wide mail flow)
|
||||
|
||||
```json
|
||||
{"CmdletInput":{"CmdletName":"Get-TransportRule","Parameters":{}}}
|
||||
```
|
||||
|
||||
Check for rules that reroute, delete, or exfiltrate mail.
|
||||
|
||||
### SMTP AUTH
|
||||
|
||||
```json
|
||||
{"CmdletInput":{"CmdletName":"Get-CASMailbox","Parameters":{"Identity":"user@domain.com"}}}
|
||||
```
|
||||
|
||||
Check `SmtpClientAuthenticationDisabled`. To disable SMTP AUTH on a single mailbox (remediation): `Set-CASMailbox -SmtpClientAuthenticationDisabled $true`.
|
||||
|
||||
## Rate limits / pagination
|
||||
|
||||
- Graph signIns endpoints cap `$top` at 999. For >999 results, follow `@odata.nextLink`.
|
||||
- Exchange REST has undocumented throttling — if you hit 429, back off 30–60s.
|
||||
- Token is valid ~60 minutes. Script caches for 55 min.
|
||||
98
.claude/skills/remediation-tool/scripts/get-token.sh
Normal file
98
.claude/skills/remediation-tool/scripts/get-token.sh
Normal file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env bash
|
||||
# Acquire a client-credentials token for the Claude-MSP-Access (ComputerGuru - AI Remediation) app.
|
||||
# Usage: get-token.sh <tenant-id-or-domain> <scope>
|
||||
# <scope>: graph | exchange | defender | sharepoint
|
||||
# Output (stdout): token. Exit 0 on success.
|
||||
# Cache: /tmp/remediation-tool/{tenant-id}/{scope}.jwt (55-min TTL).
|
||||
set -euo pipefail
|
||||
|
||||
CLIENT_ID="fabb3421-8b34-484b-bc17-e46de9703418"
|
||||
|
||||
TARGET="${1:?usage: get-token.sh <tenant-id|domain> <scope>}"
|
||||
SCOPE_NAME="${2:?usage: get-token.sh <tenant-id|domain> <scope>}"
|
||||
|
||||
# Resolve to tenant-id
|
||||
if [[ "$TARGET" =~ ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$ ]]; then
|
||||
TENANT_ID="$TARGET"
|
||||
else
|
||||
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
||||
TENANT_ID=$("$SCRIPT_DIR/resolve-tenant.sh" "$TARGET")
|
||||
fi
|
||||
|
||||
case "$SCOPE_NAME" in
|
||||
graph) SCOPE_URL="https://graph.microsoft.com/.default" ;;
|
||||
exchange) SCOPE_URL="https://outlook.office365.com/.default" ;;
|
||||
defender) SCOPE_URL="https://api.securitycenter.microsoft.com/.default" ;;
|
||||
sharepoint)
|
||||
# SharePoint token scope depends on tenant hostname. Caller must set SHAREPOINT_HOST=contoso.sharepoint.com.
|
||||
SCOPE_URL="https://${SHAREPOINT_HOST:?set SHAREPOINT_HOST for sharepoint scope}/.default" ;;
|
||||
*) echo "ERROR: unknown scope '$SCOPE_NAME'. Expected: graph|exchange|defender|sharepoint" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
CACHE_DIR="/tmp/remediation-tool/$TENANT_ID"
|
||||
mkdir -p "$CACHE_DIR"
|
||||
CACHE_FILE="$CACHE_DIR/${SCOPE_NAME}.jwt"
|
||||
|
||||
# Reuse cache if less than 55 minutes old.
|
||||
if [[ -f "$CACHE_FILE" ]] && [[ $(find "$CACHE_FILE" -mmin -55 2>/dev/null) ]]; then
|
||||
cat "$CACHE_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Locate the vault repo.
|
||||
VAULT_ROOT=""
|
||||
for candidate in "D:/vault" "$HOME/vault" "/d/vault"; do
|
||||
[[ -d "$candidate" ]] && VAULT_ROOT="$candidate" && break
|
||||
done
|
||||
[[ -z "$VAULT_ROOT" ]] && { echo "ERROR: SOPS vault repo not found at D:/vault or ~/vault" >&2; exit 3; }
|
||||
|
||||
SOPS_FILE="$VAULT_ROOT/msp-tools/claude-msp-access-graph-api.sops.yaml"
|
||||
[[ ! -f "$SOPS_FILE" ]] && { echo "ERROR: SOPS file not found: $SOPS_FILE" >&2; exit 3; }
|
||||
|
||||
# Try vault.sh first; fall back to direct sops+python if vault.sh is broken (e.g. yq shim permission issues on Windows).
|
||||
CLIENT_SECRET=""
|
||||
if [[ -f "$VAULT_ROOT/scripts/vault.sh" ]]; then
|
||||
CLIENT_SECRET=$(bash "$VAULT_ROOT/scripts/vault.sh" get-field msp-tools/claude-msp-access-graph-api.sops.yaml credentials.credential 2>/dev/null | tr -d '\r\n' || true)
|
||||
fi
|
||||
|
||||
if [[ -z "$CLIENT_SECRET" ]]; then
|
||||
# Direct fallback: sops decrypt + python YAML parse. Works without vault.sh / yq.
|
||||
PYTHON_BIN=""
|
||||
for p in python python3 py; do command -v "$p" >/dev/null 2>&1 && PYTHON_BIN="$p" && break; done
|
||||
[[ -z "$PYTHON_BIN" ]] && { echo "ERROR: neither vault.sh worked nor python is available for fallback parse" >&2; exit 3; }
|
||||
command -v sops >/dev/null 2>&1 || { echo "ERROR: sops not on PATH (needed for fallback)" >&2; exit 3; }
|
||||
|
||||
CLIENT_SECRET=$(sops -d "$SOPS_FILE" 2>/dev/null | "$PYTHON_BIN" -c "
|
||||
import sys, re
|
||||
t = sys.stdin.read()
|
||||
# minimal YAML: find 'credentials:' block then 'credential:' key
|
||||
m = re.search(r'^credentials:\s*\n((?:[ \t]+.*\n)+)', t, re.MULTILINE)
|
||||
if not m: sys.exit(1)
|
||||
for line in m.group(1).splitlines():
|
||||
line = line.strip()
|
||||
if line.startswith('credential:'):
|
||||
print(line.split(':', 1)[1].strip().strip('\"').strip(\"'\"))
|
||||
break
|
||||
" | tr -d '\r\n')
|
||||
fi
|
||||
|
||||
[[ -z "$CLIENT_SECRET" ]] && { echo "ERROR: could not read client secret from vault (vault.sh and sops+python fallback both failed)" >&2; exit 4; }
|
||||
|
||||
# Request token.
|
||||
RESP=$(curl -s --max-time 15 -X POST "https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token" \
|
||||
--data-urlencode "client_id=${CLIENT_ID}" \
|
||||
--data-urlencode "client_secret=${CLIENT_SECRET}" \
|
||||
--data-urlencode "scope=${SCOPE_URL}" \
|
||||
--data-urlencode "grant_type=client_credentials")
|
||||
|
||||
TOKEN=$(echo "$RESP" | jq -r '.access_token // empty')
|
||||
|
||||
if [[ -z "$TOKEN" ]]; then
|
||||
echo "ERROR: token request failed for tenant=$TENANT_ID scope=$SCOPE_NAME" >&2
|
||||
echo "$RESP" >&2
|
||||
exit 5
|
||||
fi
|
||||
|
||||
echo "$TOKEN" > "$CACHE_FILE"
|
||||
chmod 600 "$CACHE_FILE" 2>/dev/null || true
|
||||
echo "$TOKEN"
|
||||
37
.claude/skills/remediation-tool/scripts/resolve-tenant.sh
Normal file
37
.claude/skills/remediation-tool/scripts/resolve-tenant.sh
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# Resolve an M365 domain (or UPN) to a tenant GUID via OpenID discovery.
|
||||
# Usage: resolve-tenant.sh <domain-or-upn-or-tenantid>
|
||||
# Output (stdout): tenant GUID. Exit 0 on success, 1 on failure.
|
||||
set -euo pipefail
|
||||
|
||||
INPUT="${1:?usage: resolve-tenant.sh <domain|upn|tenant-id>}"
|
||||
|
||||
# If it looks like a GUID already, pass through.
|
||||
if [[ "$INPUT" =~ ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$ ]]; then
|
||||
echo "$INPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If it's a UPN, strip to domain.
|
||||
DOMAIN="${INPUT#*@}"
|
||||
|
||||
# Lightweight cache keyed by domain.
|
||||
CACHE_DIR="/tmp/remediation-tool/_tenant-cache"
|
||||
mkdir -p "$CACHE_DIR"
|
||||
CACHE_FILE="$CACHE_DIR/${DOMAIN}.txt"
|
||||
if [[ -f "$CACHE_FILE" ]] && [[ $(find "$CACHE_FILE" -mmin -1440 2>/dev/null) ]]; then
|
||||
cat "$CACHE_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# OpenID discovery — parse issuer URL for tenant GUID.
|
||||
RESP=$(curl -s --max-time 10 "https://login.microsoftonline.com/${DOMAIN}/v2.0/.well-known/openid-configuration")
|
||||
TENANT_ID=$(echo "$RESP" | jq -r '.issuer // empty' | sed -E 's|^https://login\.microsoftonline\.com/||;s|/v2\.0/?$||' || true)
|
||||
|
||||
if [[ -z "$TENANT_ID" ]] || [[ ! "$TENANT_ID" =~ ^[0-9a-fA-F]{8}- ]]; then
|
||||
echo "ERROR: could not resolve tenant for domain: $DOMAIN" >&2
|
||||
echo "Response: $RESP" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$TENANT_ID" | tee "$CACHE_FILE"
|
||||
82
.claude/skills/remediation-tool/scripts/tenant-sweep.sh
Normal file
82
.claude/skills/remediation-tool/scripts/tenant-sweep.sh
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env bash
|
||||
# Tenant-wide signals sweep: failed sign-ins, foreign successful sign-ins, directory audits,
|
||||
# risky users, B2B guest invites, per-user location profile.
|
||||
# Usage: tenant-sweep.sh <tenant-id-or-domain>
|
||||
# Writes raw JSON to /tmp/remediation-tool/{tenant-id}/sweep/
|
||||
# Prints a priority summary to stdout.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
||||
TENANT_INPUT="${1:?usage: tenant-sweep.sh <tenant-id|domain>}"
|
||||
TENANT_ID=$("$SCRIPT_DIR/resolve-tenant.sh" "$TENANT_INPUT")
|
||||
GT=$("$SCRIPT_DIR/get-token.sh" "$TENANT_ID" graph)
|
||||
|
||||
OUT="/tmp/remediation-tool/$TENANT_ID/sweep"
|
||||
mkdir -p "$OUT"
|
||||
FROM=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)
|
||||
echo "[info] tenant=$TENANT_ID window=30d from=$FROM"
|
||||
|
||||
# Enabled users list
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users?\$top=999&\$filter=accountEnabled%20eq%20true&\$select=id,displayName,userPrincipalName,accountEnabled,userType,externalUserState,lastPasswordChangeDateTime,createdDateTime" \
|
||||
> "$OUT/users.json" &
|
||||
|
||||
# Failed sign-ins tenant-wide
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=(createdDateTime%20ge%20${FROM})%20and%20(status/errorCode%20ne%200)&\$top=999" \
|
||||
> "$OUT/failed_signins.json" &
|
||||
|
||||
# Successful sign-ins tenant-wide (to find non-US)
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=(createdDateTime%20ge%20${FROM})%20and%20(status/errorCode%20eq%200)&\$top=999" \
|
||||
> "$OUT/success_signins.json" &
|
||||
|
||||
# Directory audits, filtered by risky activity names
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$filter=activityDateTime%20ge%20${FROM}&\$top=999" \
|
||||
> "$OUT/dir_audits.json" &
|
||||
|
||||
# Risky users (may 403 if IdentityRiskyUser scope absent)
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/identityProtection/riskyUsers?\$top=100" \
|
||||
> "$OUT/risky_users.json" &
|
||||
|
||||
# B2B guest invites
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$filter=activityDateTime%20ge%20${FROM}%20and%20activityDisplayName%20eq%20'Invite%20external%20user'&\$top=100" \
|
||||
> "$OUT/guest_invites.json" &
|
||||
|
||||
wait
|
||||
|
||||
echo ""
|
||||
echo "=== Priority 1: accounts with foreign failed sign-ins (credential stuffing candidates) ==="
|
||||
jq '[.value[] | select(.location.countryOrRegion != "US" and .location.countryOrRegion != null) | {user: .userPrincipalName, ip: .ipAddress, country: .location.countryOrRegion, city: .location.city, t: .createdDateTime, err: .status.errorCode, fail: .status.failureReason}] | group_by(.user) | map({user: .[0].user, attempts: length, unique_ips: ([.[]|.ip]|unique|length), countries: ([.[]|.country]|unique), first: ([.[]|.t]|min), last: ([.[]|.t]|max)}) | sort_by(-.attempts)' "$OUT/failed_signins.json"
|
||||
|
||||
echo ""
|
||||
echo "=== Priority 2: successful sign-ins from non-US (suspicious) ==="
|
||||
jq '[.value[] | select(.location.countryOrRegion != "US" and .location.countryOrRegion != null) | {user: .userPrincipalName, ip: .ipAddress, country: .location.countryOrRegion, city: .location.city, t: .createdDateTime, app: .appDisplayName, clientApp: .clientAppUsed}] | sort_by(.t) | reverse | .[:30]' "$OUT/success_signins.json"
|
||||
|
||||
echo ""
|
||||
echo "=== Priority 3: B2B guest invites (30d) ==="
|
||||
jq '[.value[] | {t: .activityDateTime, by: (.initiatedBy.user.userPrincipalName // .initiatedBy.app.displayName), target: [.targetResources[]?|{name: .displayName, upn: .userPrincipalName}], result: .result}] | sort_by(.t) | reverse' "$OUT/guest_invites.json"
|
||||
|
||||
echo ""
|
||||
echo "=== Priority 4: directory audit - consent/role/auth-method changes ==="
|
||||
jq '[.value[] | select(.activityDisplayName | test("[Cc]onsent|[Aa]uthentication [Mm]ethod|Add service principal|Add delegated permission grant|Add app role|Add member to role"; "")) | {t: .activityDateTime, act: .activityDisplayName, by: (.initiatedBy.user.userPrincipalName // .initiatedBy.app.displayName // "system"), target: [.targetResources[]?|{type: .type, name: .displayName, upn: .userPrincipalName}], result: .result}] | sort_by(.t) | reverse | .[:50]' "$OUT/dir_audits.json"
|
||||
|
||||
echo ""
|
||||
echo "=== Risky users (if Identity Protection accessible) ==="
|
||||
if jq -e '.error' "$OUT/risky_users.json" >/dev/null 2>&1; then
|
||||
echo "BLOCKED: $(jq -r '.error.code // "?"' "$OUT/risky_users.json") — $(jq -r '.error.message // ""' "$OUT/risky_users.json")"
|
||||
echo "(Check references/gotchas.md for how to unblock IdentityRiskyUser scope)"
|
||||
else
|
||||
jq '[.value[] | {upn: .userPrincipalName, level: .riskLevel, state: .riskState, detail: .riskDetail, lastUpdated: .riskLastUpdatedDateTime}]' "$OUT/risky_users.json"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== User locations profile (successful sign-ins) ==="
|
||||
jq '[.value[] | {user: .userPrincipalName, country: .location.countryOrRegion, city: .location.city}] | unique | group_by(.user) | map({user: .[0].user, locations: [.[]|{country, city}]|unique})' "$OUT/success_signins.json"
|
||||
|
||||
echo ""
|
||||
echo "[info] Enabled users in tenant: $(jq '.value | length' "$OUT/users.json")"
|
||||
echo "[info] raw artifacts: $OUT"
|
||||
141
.claude/skills/remediation-tool/scripts/user-breach-check.sh
Normal file
141
.claude/skills/remediation-tool/scripts/user-breach-check.sh
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run the 10-point breach check on a single user.
|
||||
# Usage: user-breach-check.sh <tenant-id-or-domain> <upn>
|
||||
# Writes raw JSON to /tmp/remediation-tool/{tenant-id}/user-breach/{user-slug}/
|
||||
# Prints a summary table to stdout.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
TENANT_INPUT="${1:?usage: user-breach-check.sh <tenant-id|domain> <upn>}"
|
||||
UPN="${2:?usage: user-breach-check.sh <tenant-id|domain> <upn>}"
|
||||
|
||||
TENANT_ID=$("$SCRIPT_DIR/resolve-tenant.sh" "$TENANT_INPUT")
|
||||
GT=$("$SCRIPT_DIR/get-token.sh" "$TENANT_ID" graph)
|
||||
EXO=$("$SCRIPT_DIR/get-token.sh" "$TENANT_ID" exchange) || EXO=""
|
||||
|
||||
USER_SLUG=$(echo "$UPN" | tr '@.' '__')
|
||||
OUT="/tmp/remediation-tool/$TENANT_ID/user-breach/$USER_SLUG"
|
||||
mkdir -p "$OUT"
|
||||
|
||||
echo "[info] tenant=$TENANT_ID user=$UPN out=$OUT"
|
||||
|
||||
# --- 0. Resolve user object ID ---
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users/${UPN}?\$select=id,displayName,userPrincipalName,mail,accountEnabled,createdDateTime,lastPasswordChangeDateTime" \
|
||||
> "$OUT/00_user.json"
|
||||
UID_=$(jq -r '.id // empty' "$OUT/00_user.json")
|
||||
if [[ -z "$UID_" ]]; then
|
||||
echo "ERROR: user not found or Graph returned error" >&2
|
||||
cat "$OUT/00_user.json" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[info] object id: $UID_"
|
||||
|
||||
# --- 1. Inbox rules (Graph v1.0 — visible only) ---
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users/${UPN}/mailFolders/inbox/messageRules" \
|
||||
> "$OUT/01_inbox_rules_graph.json" &
|
||||
|
||||
# --- 2. Mailbox settings (forwarding flags) ---
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users/${UPN}/mailboxSettings" \
|
||||
> "$OUT/02_mailbox_settings.json" &
|
||||
|
||||
# --- 4. OAuth consents + app role assignments ---
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users/${UPN}/oauth2PermissionGrants" \
|
||||
> "$OUT/04a_oauth_grants.json" &
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users/${UPN}/appRoleAssignments" \
|
||||
> "$OUT/04b_app_role_assignments.json" &
|
||||
|
||||
# --- 5. Authentication methods ---
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users/${UPN}/authentication/methods" \
|
||||
> "$OUT/05_auth_methods.json" &
|
||||
|
||||
wait
|
||||
|
||||
# --- 6. Sign-ins 30d (v1.0 — interactive only) ---
|
||||
FROM=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=userId%20eq%20'${UID_}'%20and%20createdDateTime%20ge%20${FROM}&\$top=200" \
|
||||
> "$OUT/06_signins.json" &
|
||||
|
||||
# --- 7. Directory audits (targetResources = user) 30d ---
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$filter=activityDateTime%20ge%20${FROM}%20and%20targetResources/any(t:t/id%20eq%20'${UID_}')&\$top=200" \
|
||||
> "$OUT/07_dir_audits.json" &
|
||||
|
||||
# --- 8. Risky user + risk detections (403 if app lacks IdentityRiskyUser scope) ---
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/identityProtection/riskyUsers/${UID_}" \
|
||||
> "$OUT/08a_risky_user.json" &
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/identityProtection/riskDetections?\$filter=userId%20eq%20'${UID_}'&\$top=100" \
|
||||
> "$OUT/08b_risk_detections.json" &
|
||||
|
||||
# --- 9. Sent items (last 25) ---
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users/${UPN}/mailFolders/sentitems/messages?\$top=25&\$orderby=sentDateTime%20desc&\$select=subject,toRecipients,sentDateTime,from" \
|
||||
> "$OUT/09_sent.json" &
|
||||
|
||||
# --- 10. Deleted items (last 25) ---
|
||||
curl -s -H "Authorization: Bearer $GT" \
|
||||
"https://graph.microsoft.com/v1.0/users/${UPN}/mailFolders/deleteditems/messages?\$top=25&\$orderby=receivedDateTime%20desc&\$select=subject,from,receivedDateTime" \
|
||||
> "$OUT/10_deleted.json" &
|
||||
|
||||
wait
|
||||
|
||||
# --- 3. Exchange REST (hidden rules + delegates + SendAs + Get-Mailbox) ---
|
||||
if [[ -n "$EXO" ]]; then
|
||||
EX_URL="https://outlook.office365.com/adminapi/beta/${TENANT_ID}/InvokeCommand"
|
||||
|
||||
curl -s -X POST -H "Authorization: Bearer $EXO" -H "Content-Type: application/json" "$EX_URL" \
|
||||
-d "{\"CmdletInput\":{\"CmdletName\":\"Get-InboxRule\",\"Parameters\":{\"Mailbox\":\"${UPN}\",\"IncludeHidden\":true}}}" \
|
||||
> "$OUT/03a_InboxRule_hidden.json" &
|
||||
|
||||
curl -s -X POST -H "Authorization: Bearer $EXO" -H "Content-Type: application/json" "$EX_URL" \
|
||||
-d "{\"CmdletInput\":{\"CmdletName\":\"Get-MailboxPermission\",\"Parameters\":{\"Identity\":\"${UPN}\"}}}" \
|
||||
> "$OUT/03b_MailboxPermission.json" &
|
||||
|
||||
curl -s -X POST -H "Authorization: Bearer $EXO" -H "Content-Type: application/json" "$EX_URL" \
|
||||
-d "{\"CmdletInput\":{\"CmdletName\":\"Get-RecipientPermission\",\"Parameters\":{\"Identity\":\"${UPN}\"}}}" \
|
||||
> "$OUT/03c_RecipientPermission.json" &
|
||||
|
||||
curl -s -X POST -H "Authorization: Bearer $EXO" -H "Content-Type: application/json" "$EX_URL" \
|
||||
-d "{\"CmdletInput\":{\"CmdletName\":\"Get-Mailbox\",\"Parameters\":{\"Identity\":\"${UPN}\"}}}" \
|
||||
> "$OUT/03d_Mailbox.json" &
|
||||
|
||||
wait
|
||||
else
|
||||
echo "[warn] no Exchange token; skipping check 3 (hidden rules/delegates/SendAs/mailbox forwarding flags)"
|
||||
fi
|
||||
|
||||
# --- Summary table ---
|
||||
echo ""
|
||||
echo "=== Summary: $UPN ==="
|
||||
jq -r '"account_enabled: \(.accountEnabled) lastPwChange: \(.lastPasswordChangeDateTime) created: \(.createdDateTime)"' "$OUT/00_user.json"
|
||||
echo "01 inbox_rules (Graph): $(jq '.value | length // "error"' "$OUT/01_inbox_rules_graph.json")"
|
||||
echo "02 forwarding: fwdSmtp=$(jq -r '.automaticRepliesSetting.status // "n/a"' "$OUT/02_mailbox_settings.json" 2>/dev/null) (see mailbox Get-Mailbox for forwarding fields)"
|
||||
echo "04a oauth_grants: $(jq '.value | length // "error"' "$OUT/04a_oauth_grants.json")"
|
||||
echo "04b app_role_assignments: $(jq '.value | length // "error"' "$OUT/04b_app_role_assignments.json")"
|
||||
echo "05 auth_methods: $(jq '.value | length // "error"' "$OUT/05_auth_methods.json")"
|
||||
echo "06 signins (30d, interactive): $(jq '.value | length // "error"' "$OUT/06_signins.json") non-US: $(jq '[.value[]?|select(.location.countryOrRegion != "US" and .location.countryOrRegion != null)] | length' "$OUT/06_signins.json" 2>/dev/null)"
|
||||
echo "07 dir_audits (30d): $(jq '.value | length // "error"' "$OUT/07_dir_audits.json")"
|
||||
echo "08 risky_user: $(jq -r '.riskLevel // .error.code // "none"' "$OUT/08a_risky_user.json" 2>/dev/null)"
|
||||
echo "08 risk_detections: $(jq '.value | length // (.error.code // "error")' "$OUT/08b_risk_detections.json")"
|
||||
echo "09 sent (recent 25): $(jq '.value | length // "error"' "$OUT/09_sent.json")"
|
||||
echo "10 deleted (recent 25): $(jq '.value | length // "error"' "$OUT/10_deleted.json")"
|
||||
if [[ -f "$OUT/03a_InboxRule_hidden.json" ]]; then
|
||||
HIDDEN=$(jq '.value | length // (.error.code // "?")' "$OUT/03a_InboxRule_hidden.json" 2>/dev/null || echo "?")
|
||||
echo "03a hidden_inbox_rules: $HIDDEN"
|
||||
echo "03b mailbox_permissions: $(jq '[.value[]? | select(.User != "NT AUTHORITY\\SELF")] | length // "?"' "$OUT/03b_MailboxPermission.json" 2>/dev/null) non-SELF"
|
||||
echo "03c send_as: $(jq '[.value[]? | select(.Trustee != "NT AUTHORITY\\SELF")] | length // "?"' "$OUT/03c_RecipientPermission.json" 2>/dev/null) non-SELF"
|
||||
echo "03d mailbox_forwarding: fwdAddr=$(jq -r '.value[0].ForwardingAddress // "null"' "$OUT/03d_Mailbox.json" 2>/dev/null) fwdSmtp=$(jq -r '.value[0].ForwardingSmtpAddress // "null"' "$OUT/03d_Mailbox.json" 2>/dev/null)"
|
||||
else
|
||||
echo "03 exchange_rest: SKIPPED (no exchange token — tenant likely needs Exchange Admin role assigned)"
|
||||
fi
|
||||
echo ""
|
||||
echo "[info] raw artifacts: $OUT"
|
||||
75
.claude/skills/remediation-tool/templates/breach-report.md
Normal file
75
.claude/skills/remediation-tool/templates/breach-report.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# {{TITLE}}
|
||||
|
||||
**Date:** {{YYYY-MM-DD}}
|
||||
**Tenant:** {{tenant-display-name}} ({{domain}}, {{tenant-id}})
|
||||
**Subject:** {{user-or-tenant}}
|
||||
**Tool:** Claude-MSP-Access / ComputerGuru - AI Remediation (App ID `fabb3421-8b34-484b-bc17-e46de9703418`)
|
||||
**Scope:** {{read-only | included remediation}}
|
||||
|
||||
## Summary
|
||||
|
||||
- {{3-5 bullets: breach indicators found? which categories? priority actions?}}
|
||||
|
||||
## Target details
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| UPN | |
|
||||
| Object ID | |
|
||||
| Account Enabled | |
|
||||
| Created | |
|
||||
| Last Password Change | |
|
||||
|
||||
## Per-check findings
|
||||
|
||||
### 1. Inbox rules (Graph)
|
||||
{{count, flagged items verbatim}}
|
||||
|
||||
### 2. Mailbox forwarding / settings
|
||||
{{forwarding flags, auto-reply status}}
|
||||
|
||||
### 3. Exchange REST (hidden rules, delegates, SendAs, Get-Mailbox)
|
||||
{{hidden rule count, non-SELF permissions, ForwardingAddress/ForwardingSmtpAddress}}
|
||||
|
||||
### 4. OAuth consents + app role assignments
|
||||
{{apps consented, when, scopes}}
|
||||
|
||||
### 5. Authentication methods
|
||||
{{methods, creation dates — flag any inside attack window}}
|
||||
|
||||
### 6. Sign-ins (30d)
|
||||
{{count, unique IPs, countries, failures — flag non-US and legacy client apps}}
|
||||
|
||||
### 7. Directory audits
|
||||
{{30d changes targeting user, by-whom analysis}}
|
||||
|
||||
### 8. Risky users / risk detections
|
||||
{{risk level, recent detections — or note if blocked by missing permission}}
|
||||
|
||||
### 9. Sent items (recent 25)
|
||||
{{sample of recipients/subjects — flag blast patterns or unusual externals}}
|
||||
|
||||
### 10. Deleted items (recent 25)
|
||||
{{sample — flag deleted security alerts or MFA notifications}}
|
||||
|
||||
## Suspicious items (pulled out of per-check findings)
|
||||
|
||||
{{bullets for anything abnormal — external forwards, hidden rules, unfamiliar consents, foreign-geo sign-ins, new auth methods within attack window}}
|
||||
|
||||
## Gaps — checks not completed
|
||||
|
||||
{{list any 403s or missing permissions with exact remediation link (see gotchas.md)}}
|
||||
|
||||
## Next actions
|
||||
|
||||
1. {{specific action + owner + deadline}}
|
||||
2. {{...}}
|
||||
|
||||
## Remediation actions (if any)
|
||||
|
||||
{{populated only when `/remediation-tool remediate` was executed — include cmdlet, parameters, response, timestamp}}
|
||||
|
||||
## Data artifacts
|
||||
|
||||
Raw JSON saved at `/tmp/remediation-tool/{{tenant-id}}/{{check-dir}}/` — files:
|
||||
- {{list filenames the scripts produced}}
|
||||
117
.claude/skills/skill-creator/SKILL.md
Normal file
117
.claude/skills/skill-creator/SKILL.md
Normal file
@@ -0,0 +1,117 @@
|
||||
---
|
||||
name: skill-creator
|
||||
description: |
|
||||
Create new Claude Code custom skills and slash commands. Use when the user wants to create a new skill,
|
||||
add a slash command, build a custom command, or set up a new automation. Guides through the process of
|
||||
defining the skill's purpose, triggers, and implementation, then generates the proper file structure.
|
||||
---
|
||||
|
||||
# Skill Creator
|
||||
|
||||
You help the user create new Claude Code custom skills and slash commands.
|
||||
|
||||
## Two Types of Custom Extensions
|
||||
|
||||
### 1. Skills (`.claude/skills/{name}/SKILL.md`)
|
||||
- Rich, multi-purpose capabilities with automatic invocation triggers
|
||||
- Can include supporting files (scripts, references, checklists)
|
||||
- Best for: complex behaviors, design patterns, validation workflows, integrations
|
||||
|
||||
### 2. Slash Commands (`.claude/commands/{name}.md`)
|
||||
- Simple, user-invoked commands triggered by `/{name}`
|
||||
- Single markdown file with instructions
|
||||
- Best for: workflows the user explicitly triggers, task automation, shortcuts
|
||||
- Can accept arguments via `$ARGUMENTS`
|
||||
|
||||
## Creation Process
|
||||
|
||||
### Step 1: Gather Requirements
|
||||
|
||||
Ask the user:
|
||||
1. **What should this skill/command do?** (core purpose)
|
||||
2. **Skill or command?** Help them decide:
|
||||
- If it should run automatically in response to certain actions -> **Skill**
|
||||
- If the user will invoke it explicitly with `/{name}` -> **Command**
|
||||
- If unsure, recommend based on the use case
|
||||
3. **Name** - short, kebab-case identifier (e.g., `code-review`, `deploy-check`)
|
||||
4. **When should it trigger?** (for skills: automatic triggers; for commands: typical usage)
|
||||
|
||||
### Step 2: Generate the Files
|
||||
|
||||
#### For Skills
|
||||
|
||||
Create `.claude/skills/{name}/SKILL.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: {name}
|
||||
description: |
|
||||
{Detailed description. This is used for discovery/matching, so be specific about
|
||||
when this skill should be invoked. Include trigger keywords and example scenarios.}
|
||||
---
|
||||
|
||||
# {Skill Title}
|
||||
|
||||
{Clear instructions for what Claude should do when this skill is invoked.}
|
||||
|
||||
## When to Invoke
|
||||
|
||||
{List specific triggers - file types, actions, keywords that should activate this skill.}
|
||||
|
||||
## Workflow
|
||||
|
||||
{Step-by-step process the skill follows.}
|
||||
|
||||
## Guidelines
|
||||
|
||||
{Rules, patterns, and best practices to follow.}
|
||||
```
|
||||
|
||||
#### For Commands
|
||||
|
||||
Create `.claude/commands/{name}.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: {One-line description shown in command list}
|
||||
---
|
||||
|
||||
# {Command Title}
|
||||
|
||||
{Instructions for what Claude should do when the user runs /{name}.}
|
||||
|
||||
## Arguments
|
||||
|
||||
If the command accepts arguments, reference them via `$ARGUMENTS`.
|
||||
|
||||
## Workflow
|
||||
|
||||
{Step-by-step process.}
|
||||
```
|
||||
|
||||
### Step 3: Register and Validate
|
||||
|
||||
After creating the files:
|
||||
1. Confirm the file was created in the correct location
|
||||
2. Tell the user they can invoke it:
|
||||
- Skills: Explain the automatic triggers or manual invocation via `/skill-name`
|
||||
- Commands: Tell them to use `/{name}` or `/{name} arguments`
|
||||
3. Remind them to update CLAUDE.md's Commands & Skills table if they want it documented there
|
||||
|
||||
## Quality Checklist
|
||||
|
||||
Before finalizing, verify:
|
||||
- [ ] Description is detailed enough for Claude to match it to relevant situations
|
||||
- [ ] Instructions are clear and actionable (Claude will follow them literally)
|
||||
- [ ] The skill/command doesn't duplicate an existing one
|
||||
- [ ] File is in the correct location (`.claude/skills/` or `.claude/commands/`)
|
||||
- [ ] Name uses kebab-case and is concise
|
||||
- [ ] For skills with auto-triggers: triggers are specific enough to avoid false positives
|
||||
|
||||
## Tips for Good Skills/Commands
|
||||
|
||||
- **Be specific in descriptions** - vague descriptions lead to missed or false invocations
|
||||
- **Include examples** in the instructions so Claude understands edge cases
|
||||
- **Keep scope focused** - one skill per concern, don't create mega-skills
|
||||
- **Test after creation** - have the user try invoking it to verify behavior
|
||||
- **Reference existing patterns** - look at `.claude/skills/` and `.claude/commands/` for examples
|
||||
105
.claude/skills/stop-slop/SKILL.md
Normal file
105
.claude/skills/stop-slop/SKILL.md
Normal file
@@ -0,0 +1,105 @@
|
||||
---
|
||||
name: stop-slop
|
||||
description: |
|
||||
Enforce high-quality, slop-free output in all Claude responses. MANDATORY AUTOMATIC INVOCATION:
|
||||
This skill is always active. It governs how Claude writes text, code comments, commit messages,
|
||||
documentation, and any other output. Detects and eliminates generic AI filler, hollow phrases,
|
||||
unnecessary verbosity, and performative enthusiasm. Applies to all output — conversation, code,
|
||||
docs, and generated content.
|
||||
---
|
||||
|
||||
# Stop Slop
|
||||
|
||||
You are a direct, competent engineer. Write like one. Every word must earn its place.
|
||||
|
||||
## Always-On Rules
|
||||
|
||||
These rules apply to ALL output at ALL times. No exceptions.
|
||||
|
||||
### Banned Patterns -- Never Write These
|
||||
|
||||
**Performative enthusiasm and filler openers:**
|
||||
- "Great question!", "Excellent point!", "That's a really interesting..."
|
||||
- "Certainly!", "Absolutely!", "Of course!", "Sure thing!"
|
||||
- "I'd be happy to help!", "Let me help you with that!"
|
||||
- "Good news!", "Here's the exciting part..."
|
||||
|
||||
**Hollow transitions and hedging:**
|
||||
- "It's worth noting that..." (just state it)
|
||||
- "It's important to remember..." (just state it)
|
||||
- "As you can see..." / "As we discussed..."
|
||||
- "Basically..." / "Essentially..." / "Fundamentally..."
|
||||
- "In order to..." (use "to")
|
||||
- "It should be noted that..." (just note it)
|
||||
- "At the end of the day..."
|
||||
- "Moving forward..."
|
||||
|
||||
**Unnecessary meta-commentary:**
|
||||
- "Let me explain..." (just explain)
|
||||
- "I'll now..." / "Next, I'll..." (just do it)
|
||||
- "Here's what I found..." (just show it)
|
||||
- "Let me break this down..." (just break it down)
|
||||
|
||||
**Trailing summaries and sign-offs:**
|
||||
- Restating what was just done at the end of a response
|
||||
- "Let me know if you have any questions!"
|
||||
- "Hope this helps!"
|
||||
- "Feel free to ask if you need anything else!"
|
||||
- "Happy coding!" / "Happy hacking!"
|
||||
- Any variation of "don't hesitate to reach out"
|
||||
|
||||
**Weasel words and padding:**
|
||||
- "Very", "really", "quite", "rather", "somewhat", "fairly"
|
||||
- "Just" (when used as filler, not as "only")
|
||||
- "Simply" (when the thing isn't simple, or as filler)
|
||||
- "Actually" (at start of sentences, as filler)
|
||||
- "Obviously" / "Clearly" (if it were obvious, you wouldn't say it)
|
||||
|
||||
**Sycophantic agreement:**
|
||||
- "You're absolutely right that..."
|
||||
- "That's a great approach!"
|
||||
- "What a thoughtful question!"
|
||||
- Praising the user's code/ideas before giving feedback
|
||||
|
||||
### Writing Standards
|
||||
|
||||
**Lead with the answer.** Don't build up to it. State the conclusion, then support it if needed.
|
||||
|
||||
**One sentence beats three.** If you can say it shorter, do. Compress ruthlessly.
|
||||
|
||||
**No preamble.** Start with the substance. Drop throat-clearing intros.
|
||||
|
||||
**No postamble.** End when the content ends. Don't summarize what you just said. Don't offer further help.
|
||||
|
||||
**Be specific.** "This fails because X" not "There might be some issues with this approach."
|
||||
|
||||
**Code comments: only when non-obvious.** Don't add comments that restate what the code does. Comment the *why*, not the *what*. Most code needs zero comments.
|
||||
|
||||
**Commit messages: state the change.** Not "This commit updates the..." -- just "Update X to handle Y."
|
||||
|
||||
**Error messages: state what went wrong and what to do.** Not "Oops! It looks like something went wrong."
|
||||
|
||||
### Calibration Examples
|
||||
|
||||
**Slop:**
|
||||
> Great question! Let me help you with that. So basically, what's happening here is that the function is essentially trying to parse the input string. It's worth noting that this can sometimes fail if the input isn't valid JSON. I'd recommend wrapping it in a try-catch block to handle any potential errors that might occur. Let me know if you have any questions!
|
||||
|
||||
**Clean:**
|
||||
> The function fails on invalid JSON. Wrap it in try-catch:
|
||||
> ```js
|
||||
> try { return JSON.parse(input); } catch { return null; }
|
||||
> ```
|
||||
|
||||
**Slop:**
|
||||
> I've successfully updated the configuration file to include the new database connection settings. The changes include adding the host, port, username, and password fields as requested. Everything should be working correctly now. Feel free to test it out and let me know if you run into any issues!
|
||||
|
||||
**Clean:**
|
||||
> Updated the database config with the new connection settings.
|
||||
|
||||
### What This Skill Does NOT Do
|
||||
|
||||
- It does not make responses terse to the point of being unhelpful
|
||||
- It does not remove necessary technical explanation
|
||||
- It does not prevent friendly, human tone -- just fake enthusiasm
|
||||
- It does not restrict response length when length is warranted by complexity
|
||||
- Thoroughness is good. Fluff is not. Know the difference.
|
||||
202
.claude/skills/theme-factory/LICENSE.txt
Normal file
202
.claude/skills/theme-factory/LICENSE.txt
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
59
.claude/skills/theme-factory/SKILL.md
Normal file
59
.claude/skills/theme-factory/SKILL.md
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
name: theme-factory
|
||||
description: Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.
|
||||
license: Complete terms in LICENSE.txt
|
||||
---
|
||||
|
||||
|
||||
# Theme Factory Skill
|
||||
|
||||
This skill provides a curated collection of professional font and color themes themes, each with carefully selected color palettes and font pairings. Once a theme is chosen, it can be applied to any artifact.
|
||||
|
||||
## Purpose
|
||||
|
||||
To apply consistent, professional styling to presentation slide decks, use this skill. Each theme includes:
|
||||
- A cohesive color palette with hex codes
|
||||
- Complementary font pairings for headers and body text
|
||||
- A distinct visual identity suitable for different contexts and audiences
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
To apply styling to a slide deck or other artifact:
|
||||
|
||||
1. **Show the theme showcase**: Display the `theme-showcase.pdf` file to allow users to see all available themes visually. Do not make any modifications to it; simply show the file for viewing.
|
||||
2. **Ask for their choice**: Ask which theme to apply to the deck
|
||||
3. **Wait for selection**: Get explicit confirmation about the chosen theme
|
||||
4. **Apply the theme**: Once a theme has been chosen, apply the selected theme's colors and fonts to the deck/artifact
|
||||
|
||||
## Themes Available
|
||||
|
||||
The following 10 themes are available, each showcased in `theme-showcase.pdf`:
|
||||
|
||||
1. **Ocean Depths** - Professional and calming maritime theme
|
||||
2. **Sunset Boulevard** - Warm and vibrant sunset colors
|
||||
3. **Forest Canopy** - Natural and grounded earth tones
|
||||
4. **Modern Minimalist** - Clean and contemporary grayscale
|
||||
5. **Golden Hour** - Rich and warm autumnal palette
|
||||
6. **Arctic Frost** - Cool and crisp winter-inspired theme
|
||||
7. **Desert Rose** - Soft and sophisticated dusty tones
|
||||
8. **Tech Innovation** - Bold and modern tech aesthetic
|
||||
9. **Botanical Garden** - Fresh and organic garden colors
|
||||
10. **Midnight Galaxy** - Dramatic and cosmic deep tones
|
||||
|
||||
## Theme Details
|
||||
|
||||
Each theme is defined in the `themes/` directory with complete specifications including:
|
||||
- Cohesive color palette with hex codes
|
||||
- Complementary font pairings for headers and body text
|
||||
- Distinct visual identity suitable for different contexts and audiences
|
||||
|
||||
## Application Process
|
||||
|
||||
After a preferred theme is selected:
|
||||
1. Read the corresponding theme file from the `themes/` directory
|
||||
2. Apply the specified colors and fonts consistently throughout the deck
|
||||
3. Ensure proper contrast and readability
|
||||
4. Maintain the theme's visual identity across all slides
|
||||
|
||||
## Create your Own Theme
|
||||
To handle cases where none of the existing themes work for an artifact, create a custom theme. Based on provided inputs, generate a new theme similar to the ones above. Give the theme a similar name describing what the font/color combinations represent. Use any basic description provided to choose appropriate colors/fonts. After generating the theme, show it for review and verification. Following that, apply the theme as described above.
|
||||
BIN
.claude/skills/theme-factory/theme-showcase.pdf
Normal file
BIN
.claude/skills/theme-factory/theme-showcase.pdf
Normal file
Binary file not shown.
19
.claude/skills/theme-factory/themes/arctic-frost.md
Normal file
19
.claude/skills/theme-factory/themes/arctic-frost.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Arctic Frost
|
||||
|
||||
A cool and crisp winter-inspired theme that conveys clarity, precision, and professionalism.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Ice Blue**: `#d4e4f7` - Light backgrounds and highlights
|
||||
- **Steel Blue**: `#4a6fa5` - Primary accent color
|
||||
- **Silver**: `#c0c0c0` - Metallic accent elements
|
||||
- **Crisp White**: `#fafafa` - Clean backgrounds and text
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: DejaVu Sans Bold
|
||||
- **Body Text**: DejaVu Sans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Healthcare presentations, technology solutions, winter sports, clean tech, pharmaceutical content.
|
||||
19
.claude/skills/theme-factory/themes/botanical-garden.md
Normal file
19
.claude/skills/theme-factory/themes/botanical-garden.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Botanical Garden
|
||||
|
||||
A fresh and organic theme featuring vibrant garden-inspired colors for lively presentations.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Fern Green**: `#4a7c59` - Rich natural green
|
||||
- **Marigold**: `#f9a620` - Bright floral accent
|
||||
- **Terracotta**: `#b7472a` - Earthy warm tone
|
||||
- **Cream**: `#f5f3ed` - Soft neutral backgrounds
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: DejaVu Serif Bold
|
||||
- **Body Text**: DejaVu Sans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Garden centers, food presentations, farm-to-table content, botanical brands, natural products.
|
||||
19
.claude/skills/theme-factory/themes/desert-rose.md
Normal file
19
.claude/skills/theme-factory/themes/desert-rose.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Desert Rose
|
||||
|
||||
A soft and sophisticated theme with dusty, muted tones perfect for elegant presentations.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Dusty Rose**: `#d4a5a5` - Soft primary color
|
||||
- **Clay**: `#b87d6d` - Earthy accent
|
||||
- **Sand**: `#e8d5c4` - Warm neutral backgrounds
|
||||
- **Deep Burgundy**: `#5d2e46` - Rich dark contrast
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: FreeSans Bold
|
||||
- **Body Text**: FreeSans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Fashion presentations, beauty brands, wedding planning, interior design, boutique businesses.
|
||||
19
.claude/skills/theme-factory/themes/forest-canopy.md
Normal file
19
.claude/skills/theme-factory/themes/forest-canopy.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Forest Canopy
|
||||
|
||||
A natural and grounded theme featuring earth tones inspired by dense forest environments.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Forest Green**: `#2d4a2b` - Primary dark green
|
||||
- **Sage**: `#7d8471` - Muted green accent
|
||||
- **Olive**: `#a4ac86` - Light accent color
|
||||
- **Ivory**: `#faf9f6` - Backgrounds and text
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: FreeSerif Bold
|
||||
- **Body Text**: FreeSans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Environmental presentations, sustainability reports, outdoor brands, wellness content, organic products.
|
||||
19
.claude/skills/theme-factory/themes/golden-hour.md
Normal file
19
.claude/skills/theme-factory/themes/golden-hour.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Golden Hour
|
||||
|
||||
A rich and warm autumnal palette that creates an inviting and sophisticated atmosphere.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Mustard Yellow**: `#f4a900` - Bold primary accent
|
||||
- **Terracotta**: `#c1666b` - Warm secondary color
|
||||
- **Warm Beige**: `#d4b896` - Neutral backgrounds
|
||||
- **Chocolate Brown**: `#4a403a` - Dark text and anchors
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: FreeSans Bold
|
||||
- **Body Text**: FreeSans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Restaurant presentations, hospitality brands, fall campaigns, cozy lifestyle content, artisan products.
|
||||
19
.claude/skills/theme-factory/themes/midnight-galaxy.md
Normal file
19
.claude/skills/theme-factory/themes/midnight-galaxy.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Midnight Galaxy
|
||||
|
||||
A dramatic and cosmic theme with deep purples and mystical tones for impactful presentations.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Deep Purple**: `#2b1e3e` - Rich dark base
|
||||
- **Cosmic Blue**: `#4a4e8f` - Mystical mid-tone
|
||||
- **Lavender**: `#a490c2` - Soft accent color
|
||||
- **Silver**: `#e6e6fa` - Light highlights and text
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: FreeSans Bold
|
||||
- **Body Text**: FreeSans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Entertainment industry, gaming presentations, nightlife venues, luxury brands, creative agencies.
|
||||
19
.claude/skills/theme-factory/themes/modern-minimalist.md
Normal file
19
.claude/skills/theme-factory/themes/modern-minimalist.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Modern Minimalist
|
||||
|
||||
A clean and contemporary theme with a sophisticated grayscale palette for maximum versatility.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Charcoal**: `#36454f` - Primary dark color
|
||||
- **Slate Gray**: `#708090` - Medium gray for accents
|
||||
- **Light Gray**: `#d3d3d3` - Backgrounds and dividers
|
||||
- **White**: `#ffffff` - Text and clean backgrounds
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: DejaVu Sans Bold
|
||||
- **Body Text**: DejaVu Sans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Tech presentations, architecture portfolios, design showcases, modern business proposals, data visualization.
|
||||
19
.claude/skills/theme-factory/themes/ocean-depths.md
Normal file
19
.claude/skills/theme-factory/themes/ocean-depths.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Ocean Depths
|
||||
|
||||
A professional and calming maritime theme that evokes the serenity of deep ocean waters.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Deep Navy**: `#1a2332` - Primary background color
|
||||
- **Teal**: `#2d8b8b` - Accent color for highlights and emphasis
|
||||
- **Seafoam**: `#a8dadc` - Secondary accent for lighter elements
|
||||
- **Cream**: `#f1faee` - Text and light backgrounds
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: DejaVu Sans Bold
|
||||
- **Body Text**: DejaVu Sans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Corporate presentations, financial reports, professional consulting decks, trust-building content.
|
||||
19
.claude/skills/theme-factory/themes/sunset-boulevard.md
Normal file
19
.claude/skills/theme-factory/themes/sunset-boulevard.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Sunset Boulevard
|
||||
|
||||
A warm and vibrant theme inspired by golden hour sunsets, perfect for energetic and creative presentations.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Burnt Orange**: `#e76f51` - Primary accent color
|
||||
- **Coral**: `#f4a261` - Secondary warm accent
|
||||
- **Warm Sand**: `#e9c46a` - Highlighting and backgrounds
|
||||
- **Deep Purple**: `#264653` - Dark contrast and text
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: DejaVu Serif Bold
|
||||
- **Body Text**: DejaVu Sans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Creative pitches, marketing presentations, lifestyle brands, event promotions, inspirational content.
|
||||
19
.claude/skills/theme-factory/themes/tech-innovation.md
Normal file
19
.claude/skills/theme-factory/themes/tech-innovation.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Tech Innovation
|
||||
|
||||
A bold and modern theme with high-contrast colors perfect for cutting-edge technology presentations.
|
||||
|
||||
## Color Palette
|
||||
|
||||
- **Electric Blue**: `#0066ff` - Vibrant primary accent
|
||||
- **Neon Cyan**: `#00ffff` - Bright highlight color
|
||||
- **Dark Gray**: `#1e1e1e` - Deep backgrounds
|
||||
- **White**: `#ffffff` - Clean text and contrast
|
||||
|
||||
## Typography
|
||||
|
||||
- **Headers**: DejaVu Sans Bold
|
||||
- **Body Text**: DejaVu Sans
|
||||
|
||||
## Best Used For
|
||||
|
||||
Tech startups, software launches, innovation showcases, AI/ML presentations, digital transformation content.
|
||||
31
.claude/users.json
Normal file
31
.claude/users.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"users": {
|
||||
"mike": {
|
||||
"full_name": "Mike Swanson",
|
||||
"email": "mike@azcomputerguru.com",
|
||||
"role": "admin",
|
||||
"title": "President",
|
||||
"known_machines": ["DESKTOP-0O8A1RL"],
|
||||
"git_name": "Mike Swanson",
|
||||
"git_email": "mike@azcomputerguru.com",
|
||||
"notes": "Owner. Full access to everything."
|
||||
},
|
||||
"howard": {
|
||||
"full_name": "Howard Enos",
|
||||
"email": "howard@azcomputerguru.com",
|
||||
"role": "tech",
|
||||
"title": "Technician",
|
||||
"known_machines": ["ACG-TECH03L"],
|
||||
"git_name": "Howard Enos",
|
||||
"git_email": "howard@azcomputerguru.com",
|
||||
"gitea_username": "howard",
|
||||
"gitea_initial_password": "ACG-Tech2026!",
|
||||
"gitea_must_change_password": true,
|
||||
"notes": "Employee, Mike's brother. Full trust. Same access as Mike for MSP tracking and daily work. Has own Gitea account (howard) with admin access to all repos."
|
||||
}
|
||||
},
|
||||
"roles": {
|
||||
"admin": "Full access to all systems, credentials, deployments, and infrastructure.",
|
||||
"tech": "Full access to all systems, credentials, and client work. Same as admin for this organization."
|
||||
}
|
||||
}
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -3,12 +3,20 @@ backups/
|
||||
|
||||
# Local settings (machine-specific)
|
||||
.claude/settings.local.json
|
||||
.claude/identity.json
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.log
|
||||
*.bak
|
||||
|
||||
# Live secrets / tokens — never commit
|
||||
.token
|
||||
.token_*
|
||||
*.jwt
|
||||
token.txt
|
||||
.token.txt
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "projects/msp-tools/guru-rmm"]
|
||||
path = projects/msp-tools/guru-rmm
|
||||
url = https://git.azcomputerguru.com/azcomputerguru/gururmm.git
|
||||
264
CONTEXT.md
Normal file
264
CONTEXT.md
Normal file
@@ -0,0 +1,264 @@
|
||||
# ClaudeTools - Project Context
|
||||
|
||||
**Last Updated:** 2026-04-14
|
||||
**Status:** Active - Production Stable
|
||||
|
||||
## Quick Start - Infrastructure Overview
|
||||
|
||||
| Component | Location | Access | Notes |
|
||||
|-----------|----------|--------|-------|
|
||||
| **Production API** | http://172.16.3.30:8001 | Public access | ClaudeTools work tracking API |
|
||||
| **Production DB** | MariaDB @ 172.16.3.30:3306/claudetools | Vault credentials | 38 tables, AES-256-GCM encryption |
|
||||
| **Vault (SOPS)** | D:\vault\ | age-encrypted YAML | Primary credential store |
|
||||
| **1Password** | Service account | Fallback | op://Projects/ClaudeTools * |
|
||||
| **Gitea Repo** | git.azcomputerguru.com/azcomputerguru/claudetools | Active development | Main codebase |
|
||||
|
||||
**Get DB credentials:**
|
||||
```bash
|
||||
bash D:/vault/scripts/vault.sh get-field projects/claudetools/database.sops.yaml credentials.password
|
||||
```
|
||||
|
||||
## Current State (READ THIS FIRST)
|
||||
|
||||
### Project Status
|
||||
- **API:** 95+ endpoints, production-stable
|
||||
- **Database:** 38 tables, fully encrypted sensitive fields
|
||||
- **Authentication:** JWT-based, AES-256-GCM for API keys
|
||||
- **Deployment:** Auto-deploy via Gitea webhooks (planned)
|
||||
|
||||
### Active Subprojects
|
||||
1. **GuruRMM** - Remote monitoring system (see projects/msp-tools/guru-rmm/CONTEXT.md)
|
||||
2. **Dataforth DOS** - Test datasheet pipeline (see projects/dataforth-dos/CONTEXT.md)
|
||||
|
||||
### Session Logs
|
||||
- **Project-specific:** projects/*/session-logs/
|
||||
- **Client work:** clients/*/session-logs/
|
||||
- **General:** session-logs/ (root)
|
||||
|
||||
## Anti-Patterns (DON'T DO THIS)
|
||||
|
||||
❌ **DO NOT query database directly** - Use Database Agent for ALL operations
|
||||
|
||||
❌ **DO NOT write production code yourself** - Delegate to Coding Agent, coordinate as needed
|
||||
|
||||
❌ **DO NOT use emojis** - ASCII markers only: [OK], [ERROR], [WARNING], [SUCCESS], [INFO]
|
||||
|
||||
❌ **DO NOT hardcode credentials** - Always use SOPS vault (primary) or 1Password (fallback)
|
||||
|
||||
❌ **DO NOT skip Code Review Agent** - MANDATORY after any code changes
|
||||
|
||||
❌ **DO NOT execute >500 token operations directly** - Delegate to appropriate agent
|
||||
|
||||
## Where to Find Things
|
||||
|
||||
### Repository Structure
|
||||
```
|
||||
ClaudeTools/
|
||||
├── .claude/
|
||||
│ ├── CLAUDE.md # Project instructions (directives)
|
||||
│ ├── REFERENCE.md # Technical reference
|
||||
│ ├── CODING_GUIDELINES.md # Code standards
|
||||
│ ├── FILE_PLACEMENT_GUIDE.md # Where to save files
|
||||
│ ├── agents/ # Agent definitions
|
||||
│ └── memory/ # Persistent facts (syncs via Git)
|
||||
├── credentials.md # Infrastructure reference (migrating to vault)
|
||||
├── session-logs/ # General session logs
|
||||
├── projects/
|
||||
│ ├── msp-tools/guru-rmm/ # GuruRMM (CONTEXT.md there)
|
||||
│ ├── dataforth-dos/ # Dataforth (CONTEXT.md there)
|
||||
│ └── claudetools-api/ # API codebase (legacy)
|
||||
├── clients/
|
||||
│ └── [client-name]/ # Client-specific work
|
||||
└── D:\vault\ # SOPS encrypted credentials (separate repo)
|
||||
```
|
||||
|
||||
### Credential Locations
|
||||
|
||||
**Primary: SOPS Vault (D:\vault\)**
|
||||
```bash
|
||||
# Search for keywords (no decryption needed)
|
||||
bash D:/vault/scripts/vault.sh search "claudetools"
|
||||
|
||||
# Get specific field
|
||||
bash D:/vault/scripts/vault.sh get-field projects/claudetools/database.sops.yaml credentials.password
|
||||
|
||||
# List all entries
|
||||
bash D:/vault/scripts/vault.sh list
|
||||
```
|
||||
|
||||
**Structure:**
|
||||
- infrastructure/ - Servers, network gear
|
||||
- clients/ - Client-specific credentials
|
||||
- services/ - External services (GitHub, APIs)
|
||||
- projects/ - Project databases, APIs
|
||||
- msp-tools/ - MSP application credentials
|
||||
|
||||
**Fallback: 1Password**
|
||||
```bash
|
||||
# ClaudeTools database credentials
|
||||
op read "op://Projects/ClaudeTools Database/password"
|
||||
|
||||
# ClaudeTools API auth
|
||||
op read "op://Projects/ClaudeTools API Auth/credential"
|
||||
```
|
||||
|
||||
## Common Operations
|
||||
|
||||
### Start Work on Subproject
|
||||
```
|
||||
User: "Let's work on GuruRMM tunnel Phase 2"
|
||||
|
||||
Claude should:
|
||||
1. Read projects/msp-tools/guru-rmm/CONTEXT.md (this file)
|
||||
2. Check recent session logs referenced in CONTEXT.md
|
||||
3. Understand current state, infrastructure, anti-patterns
|
||||
4. Proceed without asking user for context
|
||||
|
||||
DO NOT:
|
||||
- Ask user "what's the server IP?"
|
||||
- Ask user "where is the database?"
|
||||
- Ask user "what credentials should I use?"
|
||||
All of this is in CONTEXT.md
|
||||
```
|
||||
|
||||
### Database Operations
|
||||
```bash
|
||||
# WRONG: Direct query
|
||||
ssh user@172.16.3.30 "mysql -u claudetools -p claudetools -e 'SELECT * FROM ...'"
|
||||
|
||||
# RIGHT: Delegate to Database Agent
|
||||
"Use Database Agent to query work_logs table for entries from last 7 days"
|
||||
```
|
||||
|
||||
### Deploy Code Changes
|
||||
```bash
|
||||
# WRONG: Deploy yourself
|
||||
scp file.js user@172.16.3.30:/path/
|
||||
|
||||
# RIGHT: Follow project deployment process
|
||||
# (See project-specific CONTEXT.md for deployment steps)
|
||||
```
|
||||
|
||||
## Project-Specific Context Files
|
||||
|
||||
**When user says "work on [project]", read that project's CONTEXT.md FIRST:**
|
||||
|
||||
| Project | CONTEXT.md Location | What It Contains |
|
||||
|---------|---------------------|------------------|
|
||||
| GuruRMM | projects/msp-tools/guru-rmm/CONTEXT.md | Server IPs, deployment, tunnel architecture, agent status |
|
||||
| Dataforth DOS | projects/dataforth-dos/CONTEXT.md | AD2/AD1 infrastructure, testdatadb service, log formats |
|
||||
| ClaudeTools API | (This file) | Main project overview, credential locations |
|
||||
|
||||
## Coordination Rules (My Role)
|
||||
|
||||
I am a **Coordinator**, NOT an executor:
|
||||
|
||||
| Operation | Delegate To |
|
||||
|-----------|-------------|
|
||||
| Database queries/updates | Database Agent |
|
||||
| Production code generation | Coding Agent |
|
||||
| Code review (MANDATORY) | Code Review Agent |
|
||||
| Test execution | Testing Agent |
|
||||
| Git commit/push | Gitea Agent |
|
||||
| Backups/restore | Backup Agent |
|
||||
| File exploration | Explore Agent |
|
||||
| Semantic code search | deep-explore Agent (GrepAI) |
|
||||
| Complex reasoning | General-purpose + Sequential Thinking |
|
||||
|
||||
**I do myself:** Simple responses, reading 1-2 files, presenting results, planning, decisions
|
||||
|
||||
**Rule:** >500 tokens of work = delegate
|
||||
|
||||
## Memory System
|
||||
|
||||
**Location:** `.claude/memory/` (syncs across machines via Git)
|
||||
|
||||
**Structure:**
|
||||
- MEMORY.md - Index of all facts
|
||||
- [topic]-context.md - Topic-specific persistent facts
|
||||
|
||||
**IMPORTANT:** Always write to `.claude/memory/` (repo-relative), NOT `~/.claude/projects/*/memory/`
|
||||
|
||||
## Session Log Locations
|
||||
|
||||
**Follow these rules:**
|
||||
|
||||
| Work Type | Save To |
|
||||
|-----------|---------|
|
||||
| Dataforth DOS work | projects/dataforth-dos/session-logs/ |
|
||||
| ClaudeTools API code | projects/claudetools-api/session-logs/ |
|
||||
| GuruRMM work | projects/msp-tools/guru-rmm/session-logs/ |
|
||||
| Client work | clients/[client-name]/session-logs/ |
|
||||
| General/mixed work | session-logs/ (root) |
|
||||
|
||||
**See:** .claude/FILE_PLACEMENT_GUIDE.md for full rules
|
||||
|
||||
## Auto-Invoke Skills
|
||||
|
||||
**Frontend Design:** Auto-invoke `/frontend-design` skill after ANY UI change (HTML/CSS/JSX/styling)
|
||||
|
||||
**Sequential Thinking:** Use for genuine complexity only:
|
||||
- Rejection loops (3+ failed attempts)
|
||||
- Critical architectural decisions
|
||||
- Multi-step debugging with unclear root cause
|
||||
- NOT for every task
|
||||
|
||||
## Key Commands
|
||||
|
||||
| Command | Purpose | When |
|
||||
|---------|---------|------|
|
||||
| `/checkpoint` | Git commit + database context save | After code changes |
|
||||
| `/save` | Comprehensive session log | End of session |
|
||||
| `/context` | Search session logs + credentials | User references previous work |
|
||||
| `/1password` | 1Password operations | Manage secrets |
|
||||
| `/sync` | Sync from Gitea | Update local config |
|
||||
| `/refresh-directives` | Re-read CLAUDE.md | After summarization, large tasks |
|
||||
|
||||
## Reference Documents (Read On-Demand)
|
||||
|
||||
- **Project instructions:** .claude/CLAUDE.md (my role, agent delegation rules)
|
||||
- **Technical reference:** .claude/REFERENCE.md (endpoints, database, workflows)
|
||||
- **Coding standards:** .claude/CODING_GUIDELINES.md (agents read, not every session)
|
||||
- **File placement:** .claude/FILE_PLACEMENT_GUIDE.md (where to save files)
|
||||
- **MCP servers:** MCP_SERVERS.md (available integrations)
|
||||
- **Agent definitions:** .claude/agents/*.md (agent capabilities)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "I don't know the database password"
|
||||
- **Check:** D:\vault\ (SOPS encrypted)
|
||||
- **Command:** `bash D:/vault/scripts/vault.sh get-field projects/claudetools/database.sops.yaml credentials.password`
|
||||
- **Fallback:** credentials.md (has 1Password references)
|
||||
|
||||
### "Where is the GuruRMM server?"
|
||||
- **Check:** projects/msp-tools/guru-rmm/CONTEXT.md
|
||||
- **Answer:** 172.16.3.30 (listed in first table)
|
||||
|
||||
### "How do I deploy Dataforth changes?"
|
||||
- **Check:** projects/dataforth-dos/CONTEXT.md
|
||||
- **Section:** "Common Operations → Deploy Code to AD2"
|
||||
|
||||
### "I forgot my role as Coordinator"
|
||||
- **Read:** .claude/CLAUDE.md
|
||||
- **Command:** `/refresh-directives`
|
||||
|
||||
## Quick Links
|
||||
|
||||
- **Credentials (vault):** D:\vault\ (SOPS encrypted YAML)
|
||||
- **Credentials (legacy):** credentials.md (migrating to vault)
|
||||
- **Gitea:** http://172.16.3.20:3000/azcomputerguru/claudetools
|
||||
- **API Docs:** http://172.16.3.30:8001/api/docs
|
||||
|
||||
---
|
||||
|
||||
**When user says "work on [project]":**
|
||||
1. Read [project]/CONTEXT.md FIRST (don't ask user for context)
|
||||
2. Check recent session logs mentioned in CONTEXT.md
|
||||
3. Understand infrastructure, anti-patterns, current state
|
||||
4. Proceed with work
|
||||
|
||||
**This eliminates:**
|
||||
- "What's the server IP?" → In CONTEXT.md
|
||||
- "Where's the database?" → In CONTEXT.md
|
||||
- "What credentials?" → In CONTEXT.md
|
||||
- "What did we do last time?" → In session logs referenced by CONTEXT.md
|
||||
45
WORKITEMS.md
Normal file
45
WORKITEMS.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Shared Work Items
|
||||
|
||||
Tag yourself to claim. Check off when done. Add new items at the bottom of the relevant section.
|
||||
|
||||
**Syntax:** `- [ ] Description — @mike/@howard/@unassigned | added YYYY-MM-DD`
|
||||
|
||||
---
|
||||
|
||||
## Active
|
||||
|
||||
- [ ] Deploy session manager to SAGE-SQL (IIS app, Windows Auth) — files ready at `clients/dataforth/session-manager/` — @mike | added 2026-04-17
|
||||
- [x] Cascades Synology (cascadesds) — get admin creds, add to vault — @howard | done 2026-04-17 (vault: `clients/cascades-tucson/synology-cascadesds.sops.yaml`)
|
||||
- [ ] Cascades — second Life Enrichment machine: end-to-end folder redirection test (tomorrow). See `clients/cascades-tucson/session-logs/2026-04-17-howard-cascades-onboarding-and-folder-redirection.md` — @howard | added 2026-04-17
|
||||
- [ ] Cascades GPO — add Desktop/Pictures/Music/Videos/Favorites once 2nd machine validates the pattern, and retire the DLTAGOI Desktop reg hack — @howard | added 2026-04-17
|
||||
- [ ] Cascades — build matching folder-redirection GPOs for every other department (Nursing, Admin, Maintenance, etc.) once Life Enrichment is proven — @howard | added 2026-04-17
|
||||
- [ ] Cascades — design OneDrive-to-server migration plan (machines with Documents/Desktop already in OneDrive KFM need data-migration + unlink BEFORE the GPO applies) — @unassigned | added 2026-04-17
|
||||
- [ ] Cascades HIPAA hardening — `Set-SmbShare -Name homes -EncryptData $true`, enable file-access auditing on D:\Homes, verify BitLocker on CS-SERVER D: — @unassigned | added 2026-04-17
|
||||
- [ ] GuruRMM bug — agent command executor can wedge after a user-context PS command hangs; doesn't recover on reboot. File + fix. — @mike | added 2026-04-17
|
||||
- [ ] Howard Gitea account — create via web UI at git.azcomputerguru.com — @mike | added 2026-04-16
|
||||
- [ ] desertrat.com — add DMARC p=reject + harden SPF on Route 53 (need AWS access) — @unassigned | added 2026-04-17
|
||||
- [ ] desertrat.com — long-term migration from WebSvr to IX + MailProtector — @unassigned | added 2026-04-17
|
||||
- [ ] MVAN other domains — only mvaninc.com has DMARC; client has other domains needing protection — @unassigned | added 2026-04-17
|
||||
- [ ] Glaztech Syncro ticket #32165 — timer entry billed wrong (should be comment+time); fix in Syncro GUI — @mike | added 2026-04-17
|
||||
- [ ] jparkinsonaz.com certbot — retry autodiscover cert once A record TTL expires — @unassigned | added 2026-04-17
|
||||
- [ ] Neptune jparkinson password — set to jP$48504850, verify mail working — @unassigned | added 2026-04-17
|
||||
- [ ] Len's Auto Brokerage — deploy GuruRMM v0.6.1 to 10 Windows endpoints — @mike | added 2026-04-16
|
||||
- [ ] GuruRMM server migration 5 — sqlx checksum drift blocks new server build — @mike | added 2026-04-16
|
||||
- [ ] Jupiter Windows VM — Server 2022 build worker for MSI CI — @unassigned | added 2026-04-16
|
||||
- [ ] Cloudflare SXG — disable via dashboard (API tokens lack scope), auto-removes June 23 — @unassigned | added 2026-04-17
|
||||
- [ ] GrepAI index — run `grepai watch` to build semantic search index — @unassigned | added 2026-04-16
|
||||
- [ ] Change LAN subnet for ACG-DC16/NEPTUNE on Dataforth network — current 172.16.x.x collides with ACG network (172.16.x.x/22) — @unassigned | added 2026-04-18
|
||||
|
||||
## Completed
|
||||
|
||||
_Move items here when done. Keep for 30 days then delete._
|
||||
|
||||
---
|
||||
|
||||
## How to use
|
||||
|
||||
- **Claim:** change `@unassigned` to your name
|
||||
- **Add:** append to Active section with today's date
|
||||
- **Complete:** move to Completed with date: `- [x] Description — @mike | done 2026-04-18`
|
||||
- **Claude:** say "show work items" or "add work item: ..." and Claude reads/updates this file
|
||||
- **Sync:** items sync via `/sync` like everything else
|
||||
28
clients/_client_template/cloud/azure.md
Normal file
28
clients/_client_template/cloud/azure.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Azure / Cloud Services
|
||||
|
||||
## Azure Subscription
|
||||
- Subscription Name:
|
||||
- Subscription ID:
|
||||
- Resource Group(s):
|
||||
- Region:
|
||||
- Monthly Spend (approx):
|
||||
|
||||
## Virtual Machines
|
||||
| VM Name | Size | OS | IP | Purpose |
|
||||
|---------------|------------|------------|------------|-----------------|
|
||||
| | | | | |
|
||||
|
||||
## Networking
|
||||
- Virtual Network:
|
||||
- Address Space:
|
||||
- Subnets:
|
||||
- VPN Gateway to On-Prem: Yes/No
|
||||
- ExpressRoute: Yes/No
|
||||
|
||||
## Other Cloud Services
|
||||
<!-- AWS, Google Workspace, third-party SaaS -->
|
||||
| Service | Purpose | Admin URL | Notes |
|
||||
|-----------------|------------------|------------------|-----------------|
|
||||
| | | | |
|
||||
|
||||
## Notes
|
||||
52
clients/_client_template/cloud/m365.md
Normal file
52
clients/_client_template/cloud/m365.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Microsoft 365
|
||||
|
||||
## Tenant Info
|
||||
- Tenant Name:
|
||||
- Tenant ID:
|
||||
- Primary Domain:
|
||||
- Admin Portal URL: https://admin.microsoft.com
|
||||
|
||||
## Licensing
|
||||
| License Type | Quantity | Assigned | Available |
|
||||
|--------------------------|----------|----------|-----------|
|
||||
| Microsoft 365 Business Basic | | | |
|
||||
| Microsoft 365 Business Standard | | | |
|
||||
| Microsoft 365 Business Premium | | | |
|
||||
| Exchange Online Plan 1/2 | | | |
|
||||
| Other | | | |
|
||||
|
||||
## Exchange Online
|
||||
- Mail Domain(s):
|
||||
- MX Record Points To:
|
||||
- SPF Record:
|
||||
- DKIM Enabled: Yes/No
|
||||
- DMARC Policy:
|
||||
- Shared Mailboxes:
|
||||
- Distribution Groups:
|
||||
- Mail Flow Rules: Yes/No (describe below)
|
||||
|
||||
## SharePoint / OneDrive
|
||||
- SharePoint Sites:
|
||||
- External Sharing: Enabled/Disabled
|
||||
- OneDrive Storage Limit:
|
||||
|
||||
## Teams
|
||||
- Teams Phone System: Yes/No
|
||||
- Calling Plan / Direct Routing:
|
||||
- Auto Attendant:
|
||||
|
||||
## Entra ID (Azure AD)
|
||||
- Hybrid Joined: Yes/No
|
||||
- Azure AD Connect Server:
|
||||
- Sync Schedule:
|
||||
- Password Hash Sync: Yes/No
|
||||
- MFA Enforced: Yes/No
|
||||
- Conditional Access Policies:
|
||||
|
||||
## Security
|
||||
- Defender for Office 365: Yes/No
|
||||
- Safe Links: Yes/No
|
||||
- Safe Attachments: Yes/No
|
||||
- Audit Log Retention:
|
||||
|
||||
## Notes
|
||||
19
clients/_client_template/issues/log.md
Normal file
19
clients/_client_template/issues/log.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Issue Log
|
||||
|
||||
Record past issues and their resolutions here. This helps the AI learn from historical
|
||||
troubleshooting and avoid repeating failed approaches.
|
||||
|
||||
## Template
|
||||
|
||||
### [DATE] - [Brief Description]
|
||||
- **Reported By:**
|
||||
- **Severity:** Low / Medium / High / Critical
|
||||
- **Symptoms:**
|
||||
- **Root Cause:**
|
||||
- **Resolution:**
|
||||
- **Time to Resolve:**
|
||||
- **Lessons Learned:**
|
||||
|
||||
---
|
||||
|
||||
<!-- Add new issues above this line, newest first -->
|
||||
31
clients/_client_template/network/dhcp.md
Normal file
31
clients/_client_template/network/dhcp.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# DHCP Configuration
|
||||
|
||||
## DHCP Server
|
||||
- Server Name:
|
||||
- Server IP:
|
||||
- Failover Partner:
|
||||
|
||||
## Scopes
|
||||
|
||||
### Scope - [VLAN Name]
|
||||
- Subnet:
|
||||
- Range Start:
|
||||
- Range End:
|
||||
- Subnet Mask:
|
||||
- Default Gateway:
|
||||
- DNS Servers:
|
||||
- Lease Duration:
|
||||
- Exclusions:
|
||||
|
||||
<!-- Copy the block above for each DHCP scope -->
|
||||
|
||||
## Reservations
|
||||
| Device Name | MAC Address | IP Address | Scope | Notes |
|
||||
|-----------------|-------------------|-----------------|---------------|---------------|
|
||||
| | | | | |
|
||||
|
||||
## DHCP Relay
|
||||
- Relay agents configured on:
|
||||
- Helper address:
|
||||
|
||||
## Notes
|
||||
33
clients/_client_template/network/dns.md
Normal file
33
clients/_client_template/network/dns.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# DNS Configuration
|
||||
|
||||
## Internal DNS Servers
|
||||
| Server Name | IP Address | Role |
|
||||
|-------------|-----------|-------------------|
|
||||
| | | Primary |
|
||||
| | | Secondary |
|
||||
|
||||
## DNS Forwarders
|
||||
- Forwarder 1:
|
||||
- Forwarder 2:
|
||||
|
||||
## Conditional Forwarders
|
||||
| Domain | Forward To | Purpose |
|
||||
|----------------------|-----------------|-------------------|
|
||||
| | | |
|
||||
|
||||
## Key DNS Records
|
||||
| Record Type | Name | Value | Notes |
|
||||
|-------------|------------------|------------------|------------------|
|
||||
| A | | | |
|
||||
| CNAME | | | |
|
||||
| MX | | | |
|
||||
| TXT | | | |
|
||||
|
||||
## External DNS
|
||||
- Registrar:
|
||||
- Hosted At:
|
||||
- Primary Domain:
|
||||
- Management URL:
|
||||
|
||||
## Notes
|
||||
<!-- Split-brain DNS, special zones, etc. -->
|
||||
47
clients/_client_template/network/firewall.md
Normal file
47
clients/_client_template/network/firewall.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Firewall Configuration
|
||||
|
||||
## Device Info
|
||||
- Vendor/Model:
|
||||
- Firmware Version:
|
||||
- Management IP:
|
||||
- Management URL:
|
||||
- HA Pair: Yes/No
|
||||
- License Expiry:
|
||||
|
||||
## Interfaces
|
||||
| Interface | Zone | IP Address | VLAN | Description |
|
||||
|-----------|-----------|-----------------|------|-------------------|
|
||||
| WAN1 | WAN | | | Primary Internet |
|
||||
| WAN2 | WAN | | | Backup Internet |
|
||||
| LAN | LAN | | | |
|
||||
| DMZ | DMZ | | | |
|
||||
|
||||
## NAT Rules
|
||||
| Name | Source | Destination | Port(s) | NAT To |
|
||||
|-------------------|---------------|----------------|-------------|-----------------|
|
||||
| | | | | |
|
||||
|
||||
## Key Firewall Policies
|
||||
| Name | Source Zone | Dest Zone | Service | Action | Notes |
|
||||
|-------------------|--------------|---------------|-------------|--------|--------|
|
||||
| | | | | | |
|
||||
|
||||
## VPN
|
||||
### Site-to-Site VPNs
|
||||
| Peer Name | Peer IP | Local Subnet | Remote Subnet | Status |
|
||||
|-------------------|--------------|----------------|---------------|--------|
|
||||
| | | | | |
|
||||
|
||||
### SSL/Client VPN
|
||||
- Enabled: Yes/No
|
||||
- Portal URL:
|
||||
- Auth Method:
|
||||
- IP Pool:
|
||||
- Split Tunnel: Yes/No
|
||||
|
||||
## Content Filtering
|
||||
- Web Filter Profile:
|
||||
- App Control Profile:
|
||||
- DNS Filter:
|
||||
|
||||
## Notes
|
||||
43
clients/_client_template/network/topology.md
Normal file
43
clients/_client_template/network/topology.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Network Topology
|
||||
|
||||
## Internet Connection
|
||||
- ISP:
|
||||
- Circuit Type:
|
||||
- Speed (Down/Up):
|
||||
- Public IP:
|
||||
- Gateway:
|
||||
- Modem Model:
|
||||
|
||||
## Core Switch
|
||||
- Model:
|
||||
- IP Address:
|
||||
- Management URL:
|
||||
- Firmware Version:
|
||||
- Location:
|
||||
|
||||
## Additional Switches
|
||||
<!-- Copy this block for each switch -->
|
||||
### Switch - [Name/Location]
|
||||
- Model:
|
||||
- IP Address:
|
||||
- Port Count:
|
||||
- PoE: Yes/No
|
||||
- Uplink To:
|
||||
|
||||
## Wireless
|
||||
- Controller Model:
|
||||
- Controller IP:
|
||||
- Number of APs:
|
||||
- AP Model(s):
|
||||
|
||||
### Access Points
|
||||
<!-- Copy for each AP -->
|
||||
- AP Name:
|
||||
- Location:
|
||||
- IP Address:
|
||||
- Connected Switch/Port:
|
||||
|
||||
## WAN / SD-WAN
|
||||
- SD-WAN Vendor:
|
||||
- Number of Sites:
|
||||
- Hub Site:
|
||||
21
clients/_client_template/network/vlans.md
Normal file
21
clients/_client_template/network/vlans.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# VLANs
|
||||
|
||||
## VLAN Table
|
||||
|
||||
| VLAN ID | Name | Subnet | Gateway | DHCP Scope | Purpose |
|
||||
|---------|---------------|-----------------|-----------------|------------------|------------------------|
|
||||
| 1 | Default | | | | |
|
||||
| 10 | Management | | | | Network devices |
|
||||
| 20 | Servers | | | | Server infrastructure |
|
||||
| 30 | Workstations | | | | End user devices |
|
||||
| 40 | VoIP | | | | Phone system |
|
||||
| 50 | WiFi-Corp | | | | Corporate wireless |
|
||||
| 60 | WiFi-Guest | | | | Guest wireless |
|
||||
| 100 | Security | | | | Cameras / access ctrl |
|
||||
|
||||
## Inter-VLAN Routing
|
||||
- Performed by:
|
||||
- Routing device IP:
|
||||
|
||||
## VLAN Notes
|
||||
<!-- Any special considerations, trunk ports, tagged/untagged config -->
|
||||
31
clients/_client_template/overview.md
Normal file
31
clients/_client_template/overview.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Client Overview
|
||||
|
||||
## Company Name
|
||||
<!-- Replace with company name -->
|
||||
|
||||
## Primary Contact
|
||||
- Name:
|
||||
- Phone:
|
||||
- Email:
|
||||
|
||||
## IT Contact
|
||||
- Name:
|
||||
- Phone:
|
||||
- Email:
|
||||
|
||||
## Contract Details
|
||||
- Service Level:
|
||||
- Hours Covered:
|
||||
- Contract Renewal Date:
|
||||
|
||||
## Environment Summary
|
||||
- Total Users:
|
||||
- Total Locations:
|
||||
- Domain Name:
|
||||
- Primary Site Address:
|
||||
- RMM Agent Count:
|
||||
- Workstation Count:
|
||||
- Server Count:
|
||||
|
||||
## Notes
|
||||
<!-- General notes about this client -->
|
||||
34
clients/_client_template/rmm/rmm.md
Normal file
34
clients/_client_template/rmm/rmm.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# RMM / Monitoring
|
||||
|
||||
## RMM Solution
|
||||
- Product:
|
||||
- Console URL:
|
||||
- Agent Version:
|
||||
|
||||
## Agent Deployment
|
||||
- Total Devices:
|
||||
- Servers Monitored:
|
||||
- Workstations Monitored:
|
||||
- Network Devices Monitored:
|
||||
|
||||
## Monitoring Policies
|
||||
| Policy Name | Applies To | Alert Condition | Action |
|
||||
|-------------------|----------------|-------------------------|---------------|
|
||||
| Disk Space | All Servers | < 10% free | Alert + Ticket|
|
||||
| CPU | All Servers | > 90% for 15 min | Alert |
|
||||
| Service Monitor | All Servers | | |
|
||||
| Backup Monitor | | | |
|
||||
| Offline Alert | All Agents | Offline > 30 min | Alert |
|
||||
|
||||
## Patch Management
|
||||
- Patch Policy:
|
||||
- Patch Window:
|
||||
- Auto-approve: Yes/No
|
||||
- Exclusions:
|
||||
|
||||
## Scripting / Automation
|
||||
| Script Name | Schedule | Purpose |
|
||||
|---------------------|-------------|--------------------------|
|
||||
| | | |
|
||||
|
||||
## Notes
|
||||
26
clients/_client_template/security/antivirus.md
Normal file
26
clients/_client_template/security/antivirus.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Endpoint Security / Antivirus
|
||||
|
||||
## Solution
|
||||
- Product:
|
||||
- Console URL:
|
||||
- License Count:
|
||||
- License Expiry:
|
||||
- Managed By:
|
||||
|
||||
## Policy
|
||||
- Real-time Protection: Yes/No
|
||||
- Scheduled Scans: (frequency)
|
||||
- Exclusions:
|
||||
|
||||
## Deployment Status
|
||||
- Total Endpoints:
|
||||
- Protected:
|
||||
- Missing Agent:
|
||||
- Out of Date:
|
||||
|
||||
## EDR / XDR
|
||||
- EDR Enabled: Yes/No
|
||||
- Product:
|
||||
- Console URL:
|
||||
|
||||
## Notes
|
||||
34
clients/_client_template/security/backup.md
Normal file
34
clients/_client_template/security/backup.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Backup and Disaster Recovery
|
||||
|
||||
## Backup Solution
|
||||
- Product:
|
||||
- Console URL:
|
||||
- License/Subscription:
|
||||
|
||||
## Backup Targets
|
||||
| Target Name | Type | Location | Capacity | Encrypted |
|
||||
|----------------|----------------|-----------------|--------------|-----------|
|
||||
| | Local NAS | | | Yes/No |
|
||||
| | Cloud | | | Yes/No |
|
||||
| | Offsite | | | Yes/No |
|
||||
|
||||
## Backup Jobs
|
||||
| Job Name | Source | Target | Schedule | Retention | Status |
|
||||
|-----------------|-------------------|------------|---------------|-------------|--------|
|
||||
| | | | | | |
|
||||
|
||||
## M365 Backup
|
||||
- M365 Backup Product:
|
||||
- Exchange Backed Up: Yes/No
|
||||
- SharePoint Backed Up: Yes/No
|
||||
- OneDrive Backed Up: Yes/No
|
||||
- Teams Backed Up: Yes/No
|
||||
|
||||
## Disaster Recovery Plan
|
||||
- RTO Target:
|
||||
- RPO Target:
|
||||
- DR Site:
|
||||
- Last DR Test Date:
|
||||
- DR Test Result:
|
||||
|
||||
## Notes
|
||||
49
clients/_client_template/servers/server_template.md
Normal file
49
clients/_client_template/servers/server_template.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Server: [SERVER NAME]
|
||||
|
||||
## General Info
|
||||
- Hostname:
|
||||
- IP Address:
|
||||
- OS:
|
||||
- OS Version:
|
||||
- Physical / Virtual:
|
||||
- Host (if virtual):
|
||||
- Location:
|
||||
- Last Patched:
|
||||
|
||||
## Hardware (if physical)
|
||||
- Make/Model:
|
||||
- CPU:
|
||||
- RAM:
|
||||
- Storage:
|
||||
- Warranty Expiry:
|
||||
|
||||
## Roles and Services
|
||||
<!-- List all roles this server performs -->
|
||||
- [ ] Domain Controller
|
||||
- [ ] DNS Server
|
||||
- [ ] DHCP Server
|
||||
- [ ] File Server
|
||||
- [ ] Print Server
|
||||
- [ ] Application Server
|
||||
- [ ] Database Server
|
||||
- [ ] Backup Target
|
||||
- [ ] RDS / Terminal Server
|
||||
- [ ] Hyper-V Host
|
||||
|
||||
## Shares (if file server)
|
||||
| Share Name | Path | Permissions Group | Notes |
|
||||
|---------------|-------------------|---------------------|----------------|
|
||||
| | | | |
|
||||
|
||||
## Applications Installed
|
||||
| Application | Version | Purpose | License |
|
||||
|-------------------|------------|----------------------|---------------|
|
||||
| | | | |
|
||||
|
||||
## Backup
|
||||
- Backup Method:
|
||||
- Backup Schedule:
|
||||
- Backup Target:
|
||||
- Last Verified Restore:
|
||||
|
||||
## Notes
|
||||
28
clients/anaise/docs/cloud/azure.md
Normal file
28
clients/anaise/docs/cloud/azure.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Azure / Cloud Services
|
||||
|
||||
## Azure Subscription
|
||||
- Subscription Name:
|
||||
- Subscription ID:
|
||||
- Resource Group(s):
|
||||
- Region:
|
||||
- Monthly Spend (approx):
|
||||
|
||||
## Virtual Machines
|
||||
| VM Name | Size | OS | IP | Purpose |
|
||||
|---------------|------------|------------|------------|-----------------|
|
||||
| | | | | |
|
||||
|
||||
## Networking
|
||||
- Virtual Network:
|
||||
- Address Space:
|
||||
- Subnets:
|
||||
- VPN Gateway to On-Prem: Yes/No
|
||||
- ExpressRoute: Yes/No
|
||||
|
||||
## Other Cloud Services
|
||||
<!-- AWS, Google Workspace, third-party SaaS -->
|
||||
| Service | Purpose | Admin URL | Notes |
|
||||
|-----------------|------------------|------------------|-----------------|
|
||||
| | | | |
|
||||
|
||||
## Notes
|
||||
52
clients/anaise/docs/cloud/m365.md
Normal file
52
clients/anaise/docs/cloud/m365.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Microsoft 365
|
||||
|
||||
## Tenant Info
|
||||
- Tenant Name:
|
||||
- Tenant ID:
|
||||
- Primary Domain:
|
||||
- Admin Portal URL: https://admin.microsoft.com
|
||||
|
||||
## Licensing
|
||||
| License Type | Quantity | Assigned | Available |
|
||||
|--------------------------|----------|----------|-----------|
|
||||
| Microsoft 365 Business Basic | | | |
|
||||
| Microsoft 365 Business Standard | | | |
|
||||
| Microsoft 365 Business Premium | | | |
|
||||
| Exchange Online Plan 1/2 | | | |
|
||||
| Other | | | |
|
||||
|
||||
## Exchange Online
|
||||
- Mail Domain(s):
|
||||
- MX Record Points To:
|
||||
- SPF Record:
|
||||
- DKIM Enabled: Yes/No
|
||||
- DMARC Policy:
|
||||
- Shared Mailboxes:
|
||||
- Distribution Groups:
|
||||
- Mail Flow Rules: Yes/No (describe below)
|
||||
|
||||
## SharePoint / OneDrive
|
||||
- SharePoint Sites:
|
||||
- External Sharing: Enabled/Disabled
|
||||
- OneDrive Storage Limit:
|
||||
|
||||
## Teams
|
||||
- Teams Phone System: Yes/No
|
||||
- Calling Plan / Direct Routing:
|
||||
- Auto Attendant:
|
||||
|
||||
## Entra ID (Azure AD)
|
||||
- Hybrid Joined: Yes/No
|
||||
- Azure AD Connect Server:
|
||||
- Sync Schedule:
|
||||
- Password Hash Sync: Yes/No
|
||||
- MFA Enforced: Yes/No
|
||||
- Conditional Access Policies:
|
||||
|
||||
## Security
|
||||
- Defender for Office 365: Yes/No
|
||||
- Safe Links: Yes/No
|
||||
- Safe Attachments: Yes/No
|
||||
- Audit Log Retention:
|
||||
|
||||
## Notes
|
||||
19
clients/anaise/docs/issues/log.md
Normal file
19
clients/anaise/docs/issues/log.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Issue Log
|
||||
|
||||
Record past issues and their resolutions here. This helps the AI learn from historical
|
||||
troubleshooting and avoid repeating failed approaches.
|
||||
|
||||
## Template
|
||||
|
||||
### [DATE] - [Brief Description]
|
||||
- **Reported By:**
|
||||
- **Severity:** Low / Medium / High / Critical
|
||||
- **Symptoms:**
|
||||
- **Root Cause:**
|
||||
- **Resolution:**
|
||||
- **Time to Resolve:**
|
||||
- **Lessons Learned:**
|
||||
|
||||
---
|
||||
|
||||
<!-- Add new issues above this line, newest first -->
|
||||
31
clients/anaise/docs/network/dhcp.md
Normal file
31
clients/anaise/docs/network/dhcp.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# DHCP Configuration
|
||||
|
||||
## DHCP Server
|
||||
- Server Name:
|
||||
- Server IP:
|
||||
- Failover Partner:
|
||||
|
||||
## Scopes
|
||||
|
||||
### Scope - [VLAN Name]
|
||||
- Subnet:
|
||||
- Range Start:
|
||||
- Range End:
|
||||
- Subnet Mask:
|
||||
- Default Gateway:
|
||||
- DNS Servers:
|
||||
- Lease Duration:
|
||||
- Exclusions:
|
||||
|
||||
<!-- Copy the block above for each DHCP scope -->
|
||||
|
||||
## Reservations
|
||||
| Device Name | MAC Address | IP Address | Scope | Notes |
|
||||
|-----------------|-------------------|-----------------|---------------|---------------|
|
||||
| | | | | |
|
||||
|
||||
## DHCP Relay
|
||||
- Relay agents configured on:
|
||||
- Helper address:
|
||||
|
||||
## Notes
|
||||
33
clients/anaise/docs/network/dns.md
Normal file
33
clients/anaise/docs/network/dns.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# DNS Configuration
|
||||
|
||||
## Internal DNS Servers
|
||||
| Server Name | IP Address | Role |
|
||||
|-------------|-----------|-------------------|
|
||||
| | | Primary |
|
||||
| | | Secondary |
|
||||
|
||||
## DNS Forwarders
|
||||
- Forwarder 1:
|
||||
- Forwarder 2:
|
||||
|
||||
## Conditional Forwarders
|
||||
| Domain | Forward To | Purpose |
|
||||
|----------------------|-----------------|-------------------|
|
||||
| | | |
|
||||
|
||||
## Key DNS Records
|
||||
| Record Type | Name | Value | Notes |
|
||||
|-------------|------------------|------------------|------------------|
|
||||
| A | | | |
|
||||
| CNAME | | | |
|
||||
| MX | | | |
|
||||
| TXT | | | |
|
||||
|
||||
## External DNS
|
||||
- Registrar:
|
||||
- Hosted At:
|
||||
- Primary Domain:
|
||||
- Management URL:
|
||||
|
||||
## Notes
|
||||
<!-- Split-brain DNS, special zones, etc. -->
|
||||
47
clients/anaise/docs/network/firewall.md
Normal file
47
clients/anaise/docs/network/firewall.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Firewall Configuration
|
||||
|
||||
## Device Info
|
||||
- Vendor/Model:
|
||||
- Firmware Version:
|
||||
- Management IP:
|
||||
- Management URL:
|
||||
- HA Pair: Yes/No
|
||||
- License Expiry:
|
||||
|
||||
## Interfaces
|
||||
| Interface | Zone | IP Address | VLAN | Description |
|
||||
|-----------|-----------|-----------------|------|-------------------|
|
||||
| WAN1 | WAN | | | Primary Internet |
|
||||
| WAN2 | WAN | | | Backup Internet |
|
||||
| LAN | LAN | | | |
|
||||
| DMZ | DMZ | | | |
|
||||
|
||||
## NAT Rules
|
||||
| Name | Source | Destination | Port(s) | NAT To |
|
||||
|-------------------|---------------|----------------|-------------|-----------------|
|
||||
| | | | | |
|
||||
|
||||
## Key Firewall Policies
|
||||
| Name | Source Zone | Dest Zone | Service | Action | Notes |
|
||||
|-------------------|--------------|---------------|-------------|--------|--------|
|
||||
| | | | | | |
|
||||
|
||||
## VPN
|
||||
### Site-to-Site VPNs
|
||||
| Peer Name | Peer IP | Local Subnet | Remote Subnet | Status |
|
||||
|-------------------|--------------|----------------|---------------|--------|
|
||||
| | | | | |
|
||||
|
||||
### SSL/Client VPN
|
||||
- Enabled: Yes/No
|
||||
- Portal URL:
|
||||
- Auth Method:
|
||||
- IP Pool:
|
||||
- Split Tunnel: Yes/No
|
||||
|
||||
## Content Filtering
|
||||
- Web Filter Profile:
|
||||
- App Control Profile:
|
||||
- DNS Filter:
|
||||
|
||||
## Notes
|
||||
43
clients/anaise/docs/network/topology.md
Normal file
43
clients/anaise/docs/network/topology.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Network Topology
|
||||
|
||||
## Internet Connection
|
||||
- ISP:
|
||||
- Circuit Type:
|
||||
- Speed (Down/Up):
|
||||
- Public IP:
|
||||
- Gateway:
|
||||
- Modem Model:
|
||||
|
||||
## Core Switch
|
||||
- Model:
|
||||
- IP Address:
|
||||
- Management URL:
|
||||
- Firmware Version:
|
||||
- Location:
|
||||
|
||||
## Additional Switches
|
||||
<!-- Copy this block for each switch -->
|
||||
### Switch - [Name/Location]
|
||||
- Model:
|
||||
- IP Address:
|
||||
- Port Count:
|
||||
- PoE: Yes/No
|
||||
- Uplink To:
|
||||
|
||||
## Wireless
|
||||
- Controller Model:
|
||||
- Controller IP:
|
||||
- Number of APs:
|
||||
- AP Model(s):
|
||||
|
||||
### Access Points
|
||||
<!-- Copy for each AP -->
|
||||
- AP Name:
|
||||
- Location:
|
||||
- IP Address:
|
||||
- Connected Switch/Port:
|
||||
|
||||
## WAN / SD-WAN
|
||||
- SD-WAN Vendor:
|
||||
- Number of Sites:
|
||||
- Hub Site:
|
||||
21
clients/anaise/docs/network/vlans.md
Normal file
21
clients/anaise/docs/network/vlans.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# VLANs
|
||||
|
||||
## VLAN Table
|
||||
|
||||
| VLAN ID | Name | Subnet | Gateway | DHCP Scope | Purpose |
|
||||
|---------|---------------|-----------------|-----------------|------------------|------------------------|
|
||||
| 1 | Default | | | | |
|
||||
| 10 | Management | | | | Network devices |
|
||||
| 20 | Servers | | | | Server infrastructure |
|
||||
| 30 | Workstations | | | | End user devices |
|
||||
| 40 | VoIP | | | | Phone system |
|
||||
| 50 | WiFi-Corp | | | | Corporate wireless |
|
||||
| 60 | WiFi-Guest | | | | Guest wireless |
|
||||
| 100 | Security | | | | Cameras / access ctrl |
|
||||
|
||||
## Inter-VLAN Routing
|
||||
- Performed by:
|
||||
- Routing device IP:
|
||||
|
||||
## VLAN Notes
|
||||
<!-- Any special considerations, trunk ports, tagged/untagged config -->
|
||||
26
clients/anaise/docs/overview.md
Normal file
26
clients/anaise/docs/overview.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Client Overview
|
||||
|
||||
## Company Name
|
||||
Anaise
|
||||
|
||||
## Primary Contact
|
||||
- Name: David
|
||||
- Email: anaisedavid.office@gmail.com
|
||||
|
||||
## Workstations
|
||||
|
||||
| Machine | Username | OS | Notes |
|
||||
|---------|----------|-----|-------|
|
||||
| DESKTOP-O8GF4SD | david | | |
|
||||
|
||||
## Credentials
|
||||
|
||||
Stored in SOPS vault. Do not put plaintext passwords in this file.
|
||||
|
||||
| Machine | Username | Vault Reference |
|
||||
|---------|----------|-----------------|
|
||||
| DESKTOP-O8GF4SD | david | `clients/anaise/desktop-o8gf4sd.sops.yaml` → `credentials.password` |
|
||||
|
||||
Retrieve with: `bash C:/vault/scripts/vault.sh get-field clients/anaise/desktop-o8gf4sd.sops.yaml credentials.password`
|
||||
|
||||
## Notes
|
||||
34
clients/anaise/docs/rmm/rmm.md
Normal file
34
clients/anaise/docs/rmm/rmm.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# RMM / Monitoring
|
||||
|
||||
## RMM Solution
|
||||
- Product:
|
||||
- Console URL:
|
||||
- Agent Version:
|
||||
|
||||
## Agent Deployment
|
||||
- Total Devices:
|
||||
- Servers Monitored:
|
||||
- Workstations Monitored:
|
||||
- Network Devices Monitored:
|
||||
|
||||
## Monitoring Policies
|
||||
| Policy Name | Applies To | Alert Condition | Action |
|
||||
|-------------------|----------------|-------------------------|---------------|
|
||||
| Disk Space | All Servers | < 10% free | Alert + Ticket|
|
||||
| CPU | All Servers | > 90% for 15 min | Alert |
|
||||
| Service Monitor | All Servers | | |
|
||||
| Backup Monitor | | | |
|
||||
| Offline Alert | All Agents | Offline > 30 min | Alert |
|
||||
|
||||
## Patch Management
|
||||
- Patch Policy:
|
||||
- Patch Window:
|
||||
- Auto-approve: Yes/No
|
||||
- Exclusions:
|
||||
|
||||
## Scripting / Automation
|
||||
| Script Name | Schedule | Purpose |
|
||||
|---------------------|-------------|--------------------------|
|
||||
| | | |
|
||||
|
||||
## Notes
|
||||
26
clients/anaise/docs/security/antivirus.md
Normal file
26
clients/anaise/docs/security/antivirus.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Endpoint Security / Antivirus
|
||||
|
||||
## Solution
|
||||
- Product:
|
||||
- Console URL:
|
||||
- License Count:
|
||||
- License Expiry:
|
||||
- Managed By:
|
||||
|
||||
## Policy
|
||||
- Real-time Protection: Yes/No
|
||||
- Scheduled Scans: (frequency)
|
||||
- Exclusions:
|
||||
|
||||
## Deployment Status
|
||||
- Total Endpoints:
|
||||
- Protected:
|
||||
- Missing Agent:
|
||||
- Out of Date:
|
||||
|
||||
## EDR / XDR
|
||||
- EDR Enabled: Yes/No
|
||||
- Product:
|
||||
- Console URL:
|
||||
|
||||
## Notes
|
||||
34
clients/anaise/docs/security/backup.md
Normal file
34
clients/anaise/docs/security/backup.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Backup and Disaster Recovery
|
||||
|
||||
## Backup Solution
|
||||
- Product:
|
||||
- Console URL:
|
||||
- License/Subscription:
|
||||
|
||||
## Backup Targets
|
||||
| Target Name | Type | Location | Capacity | Encrypted |
|
||||
|----------------|----------------|-----------------|--------------|-----------|
|
||||
| | Local NAS | | | Yes/No |
|
||||
| | Cloud | | | Yes/No |
|
||||
| | Offsite | | | Yes/No |
|
||||
|
||||
## Backup Jobs
|
||||
| Job Name | Source | Target | Schedule | Retention | Status |
|
||||
|-----------------|-------------------|------------|---------------|-------------|--------|
|
||||
| | | | | | |
|
||||
|
||||
## M365 Backup
|
||||
- M365 Backup Product:
|
||||
- Exchange Backed Up: Yes/No
|
||||
- SharePoint Backed Up: Yes/No
|
||||
- OneDrive Backed Up: Yes/No
|
||||
- Teams Backed Up: Yes/No
|
||||
|
||||
## Disaster Recovery Plan
|
||||
- RTO Target:
|
||||
- RPO Target:
|
||||
- DR Site:
|
||||
- Last DR Test Date:
|
||||
- DR Test Result:
|
||||
|
||||
## Notes
|
||||
49
clients/anaise/docs/servers/server_template.md
Normal file
49
clients/anaise/docs/servers/server_template.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Server: [SERVER NAME]
|
||||
|
||||
## General Info
|
||||
- Hostname:
|
||||
- IP Address:
|
||||
- OS:
|
||||
- OS Version:
|
||||
- Physical / Virtual:
|
||||
- Host (if virtual):
|
||||
- Location:
|
||||
- Last Patched:
|
||||
|
||||
## Hardware (if physical)
|
||||
- Make/Model:
|
||||
- CPU:
|
||||
- RAM:
|
||||
- Storage:
|
||||
- Warranty Expiry:
|
||||
|
||||
## Roles and Services
|
||||
<!-- List all roles this server performs -->
|
||||
- [ ] Domain Controller
|
||||
- [ ] DNS Server
|
||||
- [ ] DHCP Server
|
||||
- [ ] File Server
|
||||
- [ ] Print Server
|
||||
- [ ] Application Server
|
||||
- [ ] Database Server
|
||||
- [ ] Backup Target
|
||||
- [ ] RDS / Terminal Server
|
||||
- [ ] Hyper-V Host
|
||||
|
||||
## Shares (if file server)
|
||||
| Share Name | Path | Permissions Group | Notes |
|
||||
|---------------|-------------------|---------------------|----------------|
|
||||
| | | | |
|
||||
|
||||
## Applications Installed
|
||||
| Application | Version | Purpose | License |
|
||||
|-------------------|------------|----------------------|---------------|
|
||||
| | | | |
|
||||
|
||||
## Backup
|
||||
- Backup Method:
|
||||
- Backup Schedule:
|
||||
- Backup Target:
|
||||
- Last Verified Restore:
|
||||
|
||||
## Notes
|
||||
28
clients/at-trebesch/cloud/azure.md
Normal file
28
clients/at-trebesch/cloud/azure.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Azure / Cloud Services
|
||||
|
||||
## Azure Subscription
|
||||
- Subscription Name:
|
||||
- Subscription ID:
|
||||
- Resource Group(s):
|
||||
- Region:
|
||||
- Monthly Spend (approx):
|
||||
|
||||
## Virtual Machines
|
||||
| VM Name | Size | OS | IP | Purpose |
|
||||
|---------------|------------|------------|------------|-----------------|
|
||||
| | | | | |
|
||||
|
||||
## Networking
|
||||
- Virtual Network:
|
||||
- Address Space:
|
||||
- Subnets:
|
||||
- VPN Gateway to On-Prem: Yes/No
|
||||
- ExpressRoute: Yes/No
|
||||
|
||||
## Other Cloud Services
|
||||
<!-- AWS, Google Workspace, third-party SaaS -->
|
||||
| Service | Purpose | Admin URL | Notes |
|
||||
|-----------------|------------------|------------------|-----------------|
|
||||
| | | | |
|
||||
|
||||
## Notes
|
||||
52
clients/at-trebesch/cloud/m365.md
Normal file
52
clients/at-trebesch/cloud/m365.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Microsoft 365
|
||||
|
||||
## Tenant Info
|
||||
- Tenant Name:
|
||||
- Tenant ID:
|
||||
- Primary Domain:
|
||||
- Admin Portal URL: https://admin.microsoft.com
|
||||
|
||||
## Licensing
|
||||
| License Type | Quantity | Assigned | Available |
|
||||
|--------------------------|----------|----------|-----------|
|
||||
| Microsoft 365 Business Basic | | | |
|
||||
| Microsoft 365 Business Standard | | | |
|
||||
| Microsoft 365 Business Premium | | | |
|
||||
| Exchange Online Plan 1/2 | | | |
|
||||
| Other | | | |
|
||||
|
||||
## Exchange Online
|
||||
- Mail Domain(s):
|
||||
- MX Record Points To:
|
||||
- SPF Record:
|
||||
- DKIM Enabled: Yes/No
|
||||
- DMARC Policy:
|
||||
- Shared Mailboxes:
|
||||
- Distribution Groups:
|
||||
- Mail Flow Rules: Yes/No (describe below)
|
||||
|
||||
## SharePoint / OneDrive
|
||||
- SharePoint Sites:
|
||||
- External Sharing: Enabled/Disabled
|
||||
- OneDrive Storage Limit:
|
||||
|
||||
## Teams
|
||||
- Teams Phone System: Yes/No
|
||||
- Calling Plan / Direct Routing:
|
||||
- Auto Attendant:
|
||||
|
||||
## Entra ID (Azure AD)
|
||||
- Hybrid Joined: Yes/No
|
||||
- Azure AD Connect Server:
|
||||
- Sync Schedule:
|
||||
- Password Hash Sync: Yes/No
|
||||
- MFA Enforced: Yes/No
|
||||
- Conditional Access Policies:
|
||||
|
||||
## Security
|
||||
- Defender for Office 365: Yes/No
|
||||
- Safe Links: Yes/No
|
||||
- Safe Attachments: Yes/No
|
||||
- Audit Log Retention:
|
||||
|
||||
## Notes
|
||||
19
clients/at-trebesch/issues/log.md
Normal file
19
clients/at-trebesch/issues/log.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Issue Log
|
||||
|
||||
Record past issues and their resolutions here. This helps the AI learn from historical
|
||||
troubleshooting and avoid repeating failed approaches.
|
||||
|
||||
## Template
|
||||
|
||||
### [DATE] - [Brief Description]
|
||||
- **Reported By:**
|
||||
- **Severity:** Low / Medium / High / Critical
|
||||
- **Symptoms:**
|
||||
- **Root Cause:**
|
||||
- **Resolution:**
|
||||
- **Time to Resolve:**
|
||||
- **Lessons Learned:**
|
||||
|
||||
---
|
||||
|
||||
<!-- Add new issues above this line, newest first -->
|
||||
31
clients/at-trebesch/network/dhcp.md
Normal file
31
clients/at-trebesch/network/dhcp.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# DHCP Configuration
|
||||
|
||||
## DHCP Server
|
||||
- Server Name:
|
||||
- Server IP:
|
||||
- Failover Partner:
|
||||
|
||||
## Scopes
|
||||
|
||||
### Scope - [VLAN Name]
|
||||
- Subnet:
|
||||
- Range Start:
|
||||
- Range End:
|
||||
- Subnet Mask:
|
||||
- Default Gateway:
|
||||
- DNS Servers:
|
||||
- Lease Duration:
|
||||
- Exclusions:
|
||||
|
||||
<!-- Copy the block above for each DHCP scope -->
|
||||
|
||||
## Reservations
|
||||
| Device Name | MAC Address | IP Address | Scope | Notes |
|
||||
|-----------------|-------------------|-----------------|---------------|---------------|
|
||||
| | | | | |
|
||||
|
||||
## DHCP Relay
|
||||
- Relay agents configured on:
|
||||
- Helper address:
|
||||
|
||||
## Notes
|
||||
33
clients/at-trebesch/network/dns.md
Normal file
33
clients/at-trebesch/network/dns.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# DNS Configuration
|
||||
|
||||
## Internal DNS Servers
|
||||
| Server Name | IP Address | Role |
|
||||
|-------------|-----------|-------------------|
|
||||
| | | Primary |
|
||||
| | | Secondary |
|
||||
|
||||
## DNS Forwarders
|
||||
- Forwarder 1:
|
||||
- Forwarder 2:
|
||||
|
||||
## Conditional Forwarders
|
||||
| Domain | Forward To | Purpose |
|
||||
|----------------------|-----------------|-------------------|
|
||||
| | | |
|
||||
|
||||
## Key DNS Records
|
||||
| Record Type | Name | Value | Notes |
|
||||
|-------------|------------------|------------------|------------------|
|
||||
| A | | | |
|
||||
| CNAME | | | |
|
||||
| MX | | | |
|
||||
| TXT | | | |
|
||||
|
||||
## External DNS
|
||||
- Registrar:
|
||||
- Hosted At:
|
||||
- Primary Domain:
|
||||
- Management URL:
|
||||
|
||||
## Notes
|
||||
<!-- Split-brain DNS, special zones, etc. -->
|
||||
47
clients/at-trebesch/network/firewall.md
Normal file
47
clients/at-trebesch/network/firewall.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Firewall Configuration
|
||||
|
||||
## Device Info
|
||||
- Vendor/Model:
|
||||
- Firmware Version:
|
||||
- Management IP:
|
||||
- Management URL:
|
||||
- HA Pair: Yes/No
|
||||
- License Expiry:
|
||||
|
||||
## Interfaces
|
||||
| Interface | Zone | IP Address | VLAN | Description |
|
||||
|-----------|-----------|-----------------|------|-------------------|
|
||||
| WAN1 | WAN | | | Primary Internet |
|
||||
| WAN2 | WAN | | | Backup Internet |
|
||||
| LAN | LAN | | | |
|
||||
| DMZ | DMZ | | | |
|
||||
|
||||
## NAT Rules
|
||||
| Name | Source | Destination | Port(s) | NAT To |
|
||||
|-------------------|---------------|----------------|-------------|-----------------|
|
||||
| | | | | |
|
||||
|
||||
## Key Firewall Policies
|
||||
| Name | Source Zone | Dest Zone | Service | Action | Notes |
|
||||
|-------------------|--------------|---------------|-------------|--------|--------|
|
||||
| | | | | | |
|
||||
|
||||
## VPN
|
||||
### Site-to-Site VPNs
|
||||
| Peer Name | Peer IP | Local Subnet | Remote Subnet | Status |
|
||||
|-------------------|--------------|----------------|---------------|--------|
|
||||
| | | | | |
|
||||
|
||||
### SSL/Client VPN
|
||||
- Enabled: Yes/No
|
||||
- Portal URL:
|
||||
- Auth Method:
|
||||
- IP Pool:
|
||||
- Split Tunnel: Yes/No
|
||||
|
||||
## Content Filtering
|
||||
- Web Filter Profile:
|
||||
- App Control Profile:
|
||||
- DNS Filter:
|
||||
|
||||
## Notes
|
||||
43
clients/at-trebesch/network/topology.md
Normal file
43
clients/at-trebesch/network/topology.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Network Topology
|
||||
|
||||
## Internet Connection
|
||||
- ISP:
|
||||
- Circuit Type:
|
||||
- Speed (Down/Up):
|
||||
- Public IP:
|
||||
- Gateway:
|
||||
- Modem Model:
|
||||
|
||||
## Core Switch
|
||||
- Model:
|
||||
- IP Address:
|
||||
- Management URL:
|
||||
- Firmware Version:
|
||||
- Location:
|
||||
|
||||
## Additional Switches
|
||||
<!-- Copy this block for each switch -->
|
||||
### Switch - [Name/Location]
|
||||
- Model:
|
||||
- IP Address:
|
||||
- Port Count:
|
||||
- PoE: Yes/No
|
||||
- Uplink To:
|
||||
|
||||
## Wireless
|
||||
- Controller Model:
|
||||
- Controller IP:
|
||||
- Number of APs:
|
||||
- AP Model(s):
|
||||
|
||||
### Access Points
|
||||
<!-- Copy for each AP -->
|
||||
- AP Name:
|
||||
- Location:
|
||||
- IP Address:
|
||||
- Connected Switch/Port:
|
||||
|
||||
## WAN / SD-WAN
|
||||
- SD-WAN Vendor:
|
||||
- Number of Sites:
|
||||
- Hub Site:
|
||||
21
clients/at-trebesch/network/vlans.md
Normal file
21
clients/at-trebesch/network/vlans.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# VLANs
|
||||
|
||||
## VLAN Table
|
||||
|
||||
| VLAN ID | Name | Subnet | Gateway | DHCP Scope | Purpose |
|
||||
|---------|---------------|-----------------|-----------------|------------------|------------------------|
|
||||
| 1 | Default | | | | |
|
||||
| 10 | Management | | | | Network devices |
|
||||
| 20 | Servers | | | | Server infrastructure |
|
||||
| 30 | Workstations | | | | End user devices |
|
||||
| 40 | VoIP | | | | Phone system |
|
||||
| 50 | WiFi-Corp | | | | Corporate wireless |
|
||||
| 60 | WiFi-Guest | | | | Guest wireless |
|
||||
| 100 | Security | | | | Cameras / access ctrl |
|
||||
|
||||
## Inter-VLAN Routing
|
||||
- Performed by:
|
||||
- Routing device IP:
|
||||
|
||||
## VLAN Notes
|
||||
<!-- Any special considerations, trunk ports, tagged/untagged config -->
|
||||
47
clients/at-trebesch/overview.md
Normal file
47
clients/at-trebesch/overview.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Client Overview
|
||||
|
||||
## Company Name
|
||||
AT Trebesch
|
||||
|
||||
## Primary Contact
|
||||
- Name:
|
||||
- Phone:
|
||||
- Email:
|
||||
|
||||
## IT Contact
|
||||
- Name: Howard Enos (MSP)
|
||||
- Phone:
|
||||
- Email: howard@azcomputerguru.com
|
||||
|
||||
## Contract Details
|
||||
- Service Level:
|
||||
- Hours Covered:
|
||||
- Contract Renewal Date:
|
||||
|
||||
## Environment Summary
|
||||
- Total Users: 1+ (`Owner` confirmed; verify others on next visit)
|
||||
- Total Locations: 1
|
||||
- Domain Name: WORKGROUP (no AD)
|
||||
- Primary Site Address: Tucson area (timezone US Mountain Standard Time, no DST)
|
||||
- RMM Agent Count: 1 confirmed (Syncro + ScreenConnect + Splashtop all installed)
|
||||
- Workstation Count: 1 confirmed (DESKTOP-QNP3ON5) — full inventory pending
|
||||
- Server Count: 0 confirmed
|
||||
|
||||
## Stack Summary (from 2026-04-17 audit of DESKTOP-QNP3ON5)
|
||||
|
||||
| Category | Tooling | Notes |
|
||||
|---|---|---|
|
||||
| EDR / AV | Bitdefender Endpoint Security Tools 8.26.4.628 | Primary, all 4 services running |
|
||||
| Secondary AV | Malwarebytes 5.5.4.252 | **CONFLICT** — running real-time alongside Bitdefender. Recommend uninstall or set to scheduled-only. |
|
||||
| Backup | Carbonite 6.6.0 build 670 (Dec 2025) | Cloud backup, online |
|
||||
| Remote Access | ScreenConnect 26.1.24 + Splashtop 3.8.0.4 | Both running. Splashtop likely from Syncro bundle. |
|
||||
| RMM | Syncro 1.0.200.18380 | Agent installed |
|
||||
| Office | Microsoft 365 Apps for business / Office 2024 Pro Plus | C2R 16.0.19822.20182 |
|
||||
| OS | Windows 11 **Home** 25H2 | **Should be Pro** for any business workstation (BitLocker, GPO, etc.) |
|
||||
|
||||
## Notes
|
||||
|
||||
- All workstations currently on Windows 11 Home — flag for Pro upgrade as part of any new-machine refresh cycle.
|
||||
- Workgroup environment, no AD. Local accounts only.
|
||||
- "guru" local Administrator account exists on DESKTOP-QNP3ON5 (last logon 2025-10-18) — MSP backdoor, confirm current password is in vault.
|
||||
- "localadmin" also exists alongside guru — pick one MSP-standard account, retire the other.
|
||||
@@ -0,0 +1,81 @@
|
||||
# DESKTOP-QNP3ON5 — initial audit findings (AT Trebesch)
|
||||
|
||||
**Date:** 2026-04-17
|
||||
**Technician:** Howard Enos
|
||||
**Machine:** DESKTOP-QNP3ON5 (Lenovo desktop, Owner)
|
||||
**Audit script:** workstation_audit.ps1 v2.0.2 (schema 2.0)
|
||||
**JSON artifact:** `clients/at-trebesch/diagnostics/DESKTOP-QNP3ON5_workstation_audit_2026-04-17.json` (when uploaded)
|
||||
|
||||
## Critical — fix this week
|
||||
|
||||
1. **`Owner` local account requires no password** — anyone with physical access gets a full admin shell. Fix:
|
||||
```powershell
|
||||
Set-LocalUser -Name Owner -PasswordRequired $true
|
||||
$p = Read-Host -AsSecureString "New password for Owner"
|
||||
Set-LocalUser -Name Owner -Password $p
|
||||
```
|
||||
Hand the new password to the user directly. Store nothing in the script.
|
||||
|
||||
2. **Two real-time AV engines installed and active** — Bitdefender Endpoint Security Tools 8.26.4.628 (primary) **and** Malwarebytes 5.5.4.252 are both registered with Security Center and running real-time. Two engines fight over file scans, cause file-lock errors, slow boot, and occasionally bluescreen. Confirm Bitdefender is the intended primary (it is, per our MSP standard) and either uninstall Malwarebytes or set it to scheduled/manual scan only.
|
||||
|
||||
3. **Secure Boot DISABLED** — UEFI machine with TPM 2.0 ready. No reason to be off; turn on in BIOS. Also unblocks BitLocker enrollment if/when this machine moves to Win 11 Pro.
|
||||
|
||||
4. **Windows 11 Home (not Pro)** — for a business workstation, Pro is the right SKU. Without Pro:
|
||||
- No real BitLocker (only "Device Encryption" auto-mode tied to Microsoft account)
|
||||
- No GPO, no Group Policy Editor
|
||||
- No remote management of inactivity timeout, USB lockdown, etc.
|
||||
- Limits Bitdefender / Defender hardening
|
||||
|
||||
Recommend upgrade path: in-place upgrade to Win 11 Pro via license key (`changepk.exe`). Cost: ~$99/license retail, less via volume.
|
||||
|
||||
## High — fix this month
|
||||
|
||||
5. **Defender Tamper Protection OFF** — registry value 4 = explicitly disabled. Even though Defender is in passive mode, Tamper Protection prevents an attacker from twiddling Defender settings if they ever take over. Enable in Windows Security → Virus & threat protection → Manage settings.
|
||||
|
||||
6. **Defender ASR rules: only 1 rule configured, all disabled** — apply Microsoft's Standard preset rules even in passive mode (sets a fallback baseline if Defender ever becomes primary).
|
||||
|
||||
7. **`localadmin` + `guru` — two MSP backdoor accounts** on the same machine. Pick one as standard, retire the other. Confirm chosen account's password is current and in the SOPS vault.
|
||||
|
||||
8. **Memory at 85% used** (2.3 GB free of 15.3 GB) with only 263 processes — investigate top procs (in JSON) for the offender. Likely candidate: Bitdefender + Malwarebytes overlap (item 2 above) or a leaking app. Reboot + monitor.
|
||||
|
||||
9. **NETLOGON 3095 errors on a WORKGROUP machine** — multiple NETLOGON failures on 2026-04-14. NETLOGON should not be doing anything on a non-domain-joined PC. Verify:
|
||||
```powershell
|
||||
Get-Service Netlogon | Format-List Name, Status, StartType
|
||||
nltest /sc_query:WORKGROUP
|
||||
```
|
||||
If Netlogon is running or set to Auto, change to Manual + Stopped.
|
||||
|
||||
## Medium — schedule
|
||||
|
||||
10. **No screen lock / inactivity timeout configured** — set `MachineInactivityLimit = 900` (15 min) via local policy.
|
||||
11. **USB storage unrestricted** — depending on what AT Trebesch handles, lock down via local policy.
|
||||
12. **AutoPlay not disabled** — disable to reduce USB-borne malware risk.
|
||||
13. **HOSTS file has 17 active entries** — unusual on a clean workgroup workstation. Pull from JSON and review what's there. Could be legit dev mappings, ad-blocker entries, or worth investigating further.
|
||||
14. **Cached logons count = 10** — lower to 4 for security on a single-user workstation.
|
||||
15. **NTLM LmCompatibilityLevel blank** — set explicitly to 5.
|
||||
16. **TLS protocols all "OS Default"** — Win 11 25H2 defaults are reasonable; explicit policy is better but low priority.
|
||||
|
||||
## Cleanup
|
||||
|
||||
17. **Classic Shell 4.3.1** — abandoned (last release 2017). Replace with maintained fork "Open-Shell-Menu", or remove if Win 11 default Start menu is acceptable to user.
|
||||
18. **ExplorerPatcher** — third-party shell mod, sometimes breaks after Windows feature updates and occasionally flagged by AV. Confirm intentional with user. Likely paired with Classic Shell for Win 10 look.
|
||||
19. **Windows 11 Installation Assistant** — leftover from Win 10 → Win 11 upgrade. Safe to uninstall.
|
||||
20. **Bluetooth Network Connection adapter** — usually unused. Disable adapter if not actively used.
|
||||
21. **`Time source / Last sync` blank** — verify with `w32tm /query /status` from elevated prompt. Either parsing failure in the audit script or W32time service isn't healthy.
|
||||
|
||||
## Working well — call out the wins
|
||||
|
||||
- Bitdefender EDR running, all 4 services up
|
||||
- Carbonite cloud backup installed (Dec 2025 build)
|
||||
- Firewall enabled on all 3 profiles
|
||||
- LSA Protection (RunAsPPL) enabled
|
||||
- WDigest cleartext disabled
|
||||
- 0 suspicious scheduled tasks, 0 IFEO debugger hijacks, 0 suspicious recently-modified files
|
||||
- 0 Defender detections in last 30 days
|
||||
- Updates current (KB5088467 + KB5083769 from 4/15)
|
||||
- Disk healthy with 598 GB / 953 GB free
|
||||
|
||||
## Audit script false positives noted (to fix in v2.0.3, NOT findings on this machine)
|
||||
|
||||
- Section 38 flagged `SyncroOvermind` (legitimate Syncro RMM agent at `C:\ProgramData\Syncro\bin\`). Need to add Syncro to the path allowlist alongside the Defender Platform exception.
|
||||
- Section 35 displayed `Full scan age: d` (cosmetic — empty value rendering when full scan never ran; JSON value is correctly null).
|
||||
34
clients/at-trebesch/rmm/rmm.md
Normal file
34
clients/at-trebesch/rmm/rmm.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# RMM / Monitoring
|
||||
|
||||
## RMM Solution
|
||||
- Product:
|
||||
- Console URL:
|
||||
- Agent Version:
|
||||
|
||||
## Agent Deployment
|
||||
- Total Devices:
|
||||
- Servers Monitored:
|
||||
- Workstations Monitored:
|
||||
- Network Devices Monitored:
|
||||
|
||||
## Monitoring Policies
|
||||
| Policy Name | Applies To | Alert Condition | Action |
|
||||
|-------------------|----------------|-------------------------|---------------|
|
||||
| Disk Space | All Servers | < 10% free | Alert + Ticket|
|
||||
| CPU | All Servers | > 90% for 15 min | Alert |
|
||||
| Service Monitor | All Servers | | |
|
||||
| Backup Monitor | | | |
|
||||
| Offline Alert | All Agents | Offline > 30 min | Alert |
|
||||
|
||||
## Patch Management
|
||||
- Patch Policy:
|
||||
- Patch Window:
|
||||
- Auto-approve: Yes/No
|
||||
- Exclusions:
|
||||
|
||||
## Scripting / Automation
|
||||
| Script Name | Schedule | Purpose |
|
||||
|---------------------|-------------|--------------------------|
|
||||
| | | |
|
||||
|
||||
## Notes
|
||||
26
clients/at-trebesch/security/antivirus.md
Normal file
26
clients/at-trebesch/security/antivirus.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Endpoint Security / Antivirus
|
||||
|
||||
## Solution
|
||||
- Product:
|
||||
- Console URL:
|
||||
- License Count:
|
||||
- License Expiry:
|
||||
- Managed By:
|
||||
|
||||
## Policy
|
||||
- Real-time Protection: Yes/No
|
||||
- Scheduled Scans: (frequency)
|
||||
- Exclusions:
|
||||
|
||||
## Deployment Status
|
||||
- Total Endpoints:
|
||||
- Protected:
|
||||
- Missing Agent:
|
||||
- Out of Date:
|
||||
|
||||
## EDR / XDR
|
||||
- EDR Enabled: Yes/No
|
||||
- Product:
|
||||
- Console URL:
|
||||
|
||||
## Notes
|
||||
34
clients/at-trebesch/security/backup.md
Normal file
34
clients/at-trebesch/security/backup.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Backup and Disaster Recovery
|
||||
|
||||
## Backup Solution
|
||||
- Product:
|
||||
- Console URL:
|
||||
- License/Subscription:
|
||||
|
||||
## Backup Targets
|
||||
| Target Name | Type | Location | Capacity | Encrypted |
|
||||
|----------------|----------------|-----------------|--------------|-----------|
|
||||
| | Local NAS | | | Yes/No |
|
||||
| | Cloud | | | Yes/No |
|
||||
| | Offsite | | | Yes/No |
|
||||
|
||||
## Backup Jobs
|
||||
| Job Name | Source | Target | Schedule | Retention | Status |
|
||||
|-----------------|-------------------|------------|---------------|-------------|--------|
|
||||
| | | | | | |
|
||||
|
||||
## M365 Backup
|
||||
- M365 Backup Product:
|
||||
- Exchange Backed Up: Yes/No
|
||||
- SharePoint Backed Up: Yes/No
|
||||
- OneDrive Backed Up: Yes/No
|
||||
- Teams Backed Up: Yes/No
|
||||
|
||||
## Disaster Recovery Plan
|
||||
- RTO Target:
|
||||
- RPO Target:
|
||||
- DR Site:
|
||||
- Last DR Test Date:
|
||||
- DR Test Result:
|
||||
|
||||
## Notes
|
||||
49
clients/at-trebesch/servers/server_template.md
Normal file
49
clients/at-trebesch/servers/server_template.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Server: [SERVER NAME]
|
||||
|
||||
## General Info
|
||||
- Hostname:
|
||||
- IP Address:
|
||||
- OS:
|
||||
- OS Version:
|
||||
- Physical / Virtual:
|
||||
- Host (if virtual):
|
||||
- Location:
|
||||
- Last Patched:
|
||||
|
||||
## Hardware (if physical)
|
||||
- Make/Model:
|
||||
- CPU:
|
||||
- RAM:
|
||||
- Storage:
|
||||
- Warranty Expiry:
|
||||
|
||||
## Roles and Services
|
||||
<!-- List all roles this server performs -->
|
||||
- [ ] Domain Controller
|
||||
- [ ] DNS Server
|
||||
- [ ] DHCP Server
|
||||
- [ ] File Server
|
||||
- [ ] Print Server
|
||||
- [ ] Application Server
|
||||
- [ ] Database Server
|
||||
- [ ] Backup Target
|
||||
- [ ] RDS / Terminal Server
|
||||
- [ ] Hyper-V Host
|
||||
|
||||
## Shares (if file server)
|
||||
| Share Name | Path | Permissions Group | Notes |
|
||||
|---------------|-------------------|---------------------|----------------|
|
||||
| | | | |
|
||||
|
||||
## Applications Installed
|
||||
| Application | Version | Purpose | License |
|
||||
|-------------------|------------|----------------------|---------------|
|
||||
| | | | |
|
||||
|
||||
## Backup
|
||||
- Backup Method:
|
||||
- Backup Schedule:
|
||||
- Backup Target:
|
||||
- Last Verified Restore:
|
||||
|
||||
## Notes
|
||||
81
clients/at-trebesch/workstations.md
Normal file
81
clients/at-trebesch/workstations.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Workstations — AT Trebesch
|
||||
|
||||
Inventory built from on-machine audit runs. Last updated 2026-04-17.
|
||||
|
||||
## Summary
|
||||
|
||||
| PC Name | User/Role | OS | Edition | Domain | BitLocker | Last Audit |
|
||||
|---|---|---|---|---|---|---|
|
||||
| DESKTOP-QNP3ON5 | Owner | Win 11 25H2 | **Home** | WORKGROUP | None (decrypted) | 2026-04-17 |
|
||||
|
||||
## DESKTOP-QNP3ON5
|
||||
|
||||
**Hardware**
|
||||
- Lenovo (model 91D00000US)
|
||||
- Serial: MZ025MVK
|
||||
- BIOS: M68KT23A
|
||||
- CPU: AMD Ryzen 7 250 w/ Radeon 780M Graphics (8 cores / 16 threads)
|
||||
- RAM: 15.3 GB
|
||||
- Storage: 953 GB KIOXIA KBG6AZNV1T02 LA SSD (NVMe), 598 GB free, healthy
|
||||
- Chassis: Desktop, no battery
|
||||
|
||||
**OS / Activation**
|
||||
- Windows 11 Home 25H2 (build 26200), 64-bit
|
||||
- Installed 2025-10-12
|
||||
- License: Licensed (StatusCode 1), partial key 6F4JW
|
||||
|
||||
**Network**
|
||||
- Ethernet: Realtek PCIe GbE — UP, 1 Gbps, 10.0.0.15
|
||||
- Wi-Fi: Realtek RTL8852BE WiFi 6 — disconnected
|
||||
- Bluetooth NIC enabled (unused — recommend disable)
|
||||
- Saved Wi-Fi profiles: ComputerGuru, Scurda2
|
||||
|
||||
**Local accounts (enabled)**
|
||||
| Name | Last Logon | PasswordRequired | Notes |
|
||||
|---|---|---|---|
|
||||
| Owner | 2026-04-15 | **False** | **PASSWORD NOT REQUIRED — fix immediately** |
|
||||
| guru | 2025-10-18 | True | MSP backdoor, in Administrators |
|
||||
| localadmin | (never logged) | True | Second MSP backdoor, in Administrators |
|
||||
|
||||
**Local Administrators:** Administrator (disabled), guru, localadmin, Owner
|
||||
|
||||
**Security posture (highlights)**
|
||||
- BitLocker: Off, drive fully decrypted (Win Home limits BitLocker to "Device Encryption" only)
|
||||
- Secure Boot: **DISABLED** (UEFI capable, TPM 2.0 ready — turn on)
|
||||
- TPM: present + ready
|
||||
- WinRE: enabled
|
||||
- Firewall: enabled on all 3 profiles
|
||||
- LSA Protection (RunAsPPL): enabled (good)
|
||||
- WDigest cleartext: disabled (good)
|
||||
- Cached logons: 10 (recommend lower to 4)
|
||||
- NTLM LmCompatibilityLevel: blank (defaults to 3, recommend explicit 5)
|
||||
- UAC: enabled (default settings)
|
||||
- RDP: disabled
|
||||
- USB storage: unrestricted
|
||||
- AutoPlay: not disabled
|
||||
|
||||
**Antivirus posture**
|
||||
- Bitdefender Endpoint Security Tools 8.26.4.628 — primary EDR, 4 services running
|
||||
- Malwarebytes 5.5.4.252 — **CONFLICT, also real-time. Pick one.**
|
||||
- Defender: Passive Mode (correct, deferring to Bitdefender), but Tamper Protection disabled
|
||||
- Defender ASR rules: 1 configured, 0 in Block mode
|
||||
|
||||
**Apps of note**
|
||||
- Office 365 Apps Pro Plus (Office 2024)
|
||||
- Carbonite 6.6.0 (Dec 2025 build)
|
||||
- Classic Shell 4.3.1 — abandoned project, replace with Open-Shell-Menu or remove
|
||||
- ExplorerPatcher 26100.4946.69.6 — Win10-style shell mod
|
||||
- Lenovo System Update 5.08.03.59
|
||||
- AMD Software 26.3.1
|
||||
- Canon MX490 series MP Drivers 1.02 (printer)
|
||||
- Windows 11 Installation Assistant — leftover, can uninstall
|
||||
|
||||
**Performance**
|
||||
- Memory at 85.1% used (2.3 GB free of 15.3 GB) — investigate top procs in audit JSON
|
||||
- Uptime: 2.6 days (boot 2026-04-14)
|
||||
- 263 processes running
|
||||
|
||||
**Updates**
|
||||
- KB5083769, KB5082417, KB5088467 (4/14-4/15 cycle) installed
|
||||
- 1 pending update
|
||||
- 0 WU failures in last 30d
|
||||
65
clients/cascades-tucson/CONTEXT.md
Normal file
65
clients/cascades-tucson/CONTEXT.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Cascades of Tucson — Client Context
|
||||
|
||||
**Last updated:** 2026-04-17 (Howard)
|
||||
|
||||
## Identity
|
||||
|
||||
- Business: Cascades of Tucson (senior living community)
|
||||
- Syncro customer ID: **20149445**
|
||||
- Primary contact: Meredith Kuhn — meredith.kuhn@cascadestucson.com — (520) 886-3171
|
||||
- Location: 201 N Jessica Ave, Tucson AZ 85710
|
||||
|
||||
Full contact list + Wi-Fi, KPAX, M365 admin, UniFi hardware MACs, GoDaddy are in the Syncro customer notes field for 20149445.
|
||||
|
||||
## Infrastructure
|
||||
|
||||
| Resource | Address | Vault path |
|
||||
|---|---|---|
|
||||
| pfSense firewall | 192.168.0.1 | `clients/cascades-tucson/pfsense-firewall.sops.yaml` |
|
||||
| Synology NAS `cascadesds` | 192.168.0.120:5000 (DSM) | `clients/cascades-tucson/synology-cascadesds.sops.yaml` |
|
||||
| CS-SERVER (DC + file server) | reachable at 192.168.2.254 from the Wi-Fi-2 subnet on DLTAGOI; domain `cascades.local` | `clients/cascades-tucson/cs-server.sops.yaml` |
|
||||
| `svc-audit-upload` | service account for Syncro audit upload to `AuditDrop$` share | `clients/cascades-tucson/svc-audit-upload.sops.yaml` |
|
||||
| `\\CS-SERVER\homes` | file share at `D:\Homes`; per-user subfolders for folder redirection. Domain Users: Change. Domain Admins: Full. **EncryptData currently false — HIPAA workitem to flip on.** | — |
|
||||
|
||||
## GuruRMM
|
||||
|
||||
- Client: **Cascades of Tucson** (code `CASC`, id `42e1b0e3-f8b7-4fc5-86bd-06bdbb073b7f`)
|
||||
- Site: **CascadesTucson** (code `GOLD-MOON-4620`, id `c157c399-82d3-4581-979a-b9fad70f4fef`)
|
||||
- Agent enrollment key: encrypted at `clients/cascades-tucson/gururmm-site-main.sops.yaml` (shown once by the API; do not regenerate unless compromised — agents using the current key keep working on regeneration only if the server rotates atomically)
|
||||
|
||||
### Agents currently enrolled
|
||||
|
||||
| Hostname | Role | Agent ID |
|
||||
|---|---|---|
|
||||
| DESKTOP-DLTAGOI | Life Enrichment test workstation (Sharon Edwards) | `0ed72c1c-40c7-4bd4-afed-e0bcb198936f` |
|
||||
| CS-SERVER | Domain controller / file server | `6766e973-e703-47c1-be56-76950290f87c` |
|
||||
|
||||
### Agent deployment (ScreenConnect)
|
||||
|
||||
```powershell
|
||||
$u='https://rmm-api.azcomputerguru.com/downloads/gururmm-agent-windows-amd64-latest.exe';
|
||||
$d='C:\Windows\Temp\gururmm-agent.exe';
|
||||
Invoke-WebRequest $u -UseBasicParsing -OutFile $d;
|
||||
& $d install --server-url 'wss://rmm-api.azcomputerguru.com/ws' --api-key 'grmm_3gGYreG0u_QCvt5v3lDVKwLhZDAzF4On'
|
||||
```
|
||||
|
||||
Run via ScreenConnect Commands tab (SYSTEM context). Agent heartbeats within ~60 seconds.
|
||||
|
||||
## Active project — folder redirection GPO rollout
|
||||
|
||||
**Goal:** HIPAA-compliant user data storage. Everyone's Documents/Downloads/Desktop/Pictures on `\\CS-SERVER\homes\<username>\`, driven by per-OU folder redirection GPOs.
|
||||
|
||||
**Status:** pattern validated on one user (Sharon Edwards in Life Enrichment). Documents + Downloads successfully redirecting through GPO `CSC - Folder Redirection (LE)` ({889BE7BE-202E-4153-89AD-B5DB62A52D25}). Explorer sidebar working. Detailed journey in `session-logs/2026-04-17-howard-cascades-onboarding-and-folder-redirection.md`.
|
||||
|
||||
**Next:** second LE machine end-to-end tomorrow, then Desktop + other folders, then matching GPOs for other departments.
|
||||
|
||||
### Known traps
|
||||
|
||||
- **Every ProfWiz-migrated user has potentially poisoned `User Shell Folders`** pointing at `C:\Windows\system32\config\systemprofile\...`. Check first, clean before testing redirection. Script: `scripts/hive-cleanup-shellfolders.ps1`.
|
||||
- **GPMC on Server 2019/2022 writes `fdeploy1.ini` incorrectly when adding + modifying entries in the same editor session.** Workaround: one folder per save, close/reopen editor between adds.
|
||||
- **Explorer sidebar uses the KnownFolder GUID form** (`{FDD39AD0-...}` for Documents, `{374DE290-...}` for Downloads), not legacy names. CSE may set only the legacy name — manually mirror to the GUID form if sidebar doesn't resolve. Script: `scripts/fix-live-shellfolders.ps1`.
|
||||
- **Some machines have Documents/Desktop in OneDrive (Known Folder Move).** Don't apply the GPO until OneDrive KFM is unlinked and data is migrated back to local — otherwise data leaves OneDrive's scope and may be orphaned.
|
||||
|
||||
### GPO backups
|
||||
|
||||
On CS-SERVER: `C:\GPO-Backups\pre-fix-20260417-221701\` — broken-state backup ID `9c6ff7c9-0942-4cfb-b4a5-936913a3da87`. `Restore-GPO -BackupId 9c6ff7c9-... -Path C:\GPO-Backups\pre-fix-20260417-221701 -TargetGuid 889be7be-202e-4153-89ad-b5db62a52d25` to roll back.
|
||||
488
clients/cascades-tucson/docs/billing-log.md
Normal file
488
clients/cascades-tucson/docs/billing-log.md
Normal file
@@ -0,0 +1,488 @@
|
||||
# Cascades — Work Log / Billing Record
|
||||
|
||||
## Session 1 — 2026-03-06 (Remote)
|
||||
|
||||
**Focus:** Initial audit, data gathering, documentation buildout
|
||||
|
||||
| Time | Task | Details |
|
||||
|------|------|---------|
|
||||
| | Initial server audit | Gathered systeminfo, AD users/computers/groups, DNS records, installed software, Hyper-V VMs, listening ports, disk info from CS-SERVER |
|
||||
| | Network audit | Reviewed pfSense config (interfaces, firewall rules, VLANs, DHCP), UniFi APs/switches/SSIDs |
|
||||
| | ARP/DHCP dump | Captured 802 ARP entries, 624 DHCP leases, identified all devices on network |
|
||||
| | Printer inventory | Documented all printers with IPs, MACs, models, status |
|
||||
| | Workstation inventory | Documented all PCs on INTERNAL and LAN with MACs, status, domain join state |
|
||||
| | MDIRECTOR-PC audit | Gathered OS info (Win10 Home), users, network config via ScreenConnect |
|
||||
| | Synology audit | Documented shares, storage capacity, permission report |
|
||||
| | Full documentation buildout | Created/updated all .md files: overview, network/*, servers/*, security/*, migration/* |
|
||||
| | Migration plan | Created phased migration plan with runbooks and PowerShell scripts |
|
||||
| | CLAUDE.md | Created repo-level guidance file for AI tooling |
|
||||
|
||||
---
|
||||
|
||||
## Session 2 — 2026-03-06 (Remote)
|
||||
|
||||
**Focus:** Guest WiFi isolation, DNS fixes, security hardening
|
||||
|
||||
| Time | Task | Details |
|
||||
|------|------|---------|
|
||||
| | Guest WiFi isolation | Created VLAN 50 on pfSense (igc1.50, 10.0.50.1/24), DHCP scope, 4 firewall rules, UniFi Guest network, reassigned Guest SSID |
|
||||
| | ~~RFC1918 alias~~ | ~~Created firewall alias~~ **CORRECTION (Session 6):** Never actually created. Using built-in `_private4_` alias instead. |
|
||||
| | CS-SERVER DNS client fix | Changed DNS servers from pfSense+8.8.8.8 to 127.0.0.1+192.168.0.1, verified |
|
||||
| | Stale DNS cleanup | Removed 9 stale records, added 3 correct records (@ → 192.168.2.254, DomainDnsZones, ForestDnsZones) |
|
||||
| | pfSense domain overrides | Added cascades.local + _msdcs.cascades.local → 192.168.2.254 |
|
||||
| | Reverse lookup zones | Created 5 zones (0/1/2/3.168.192 + 20.0.10.in-addr.arpa) |
|
||||
| | DNS scavenging | Enabled server-level scavenging (7-day), zone aging on cascades.local |
|
||||
| | Documentation updates | Updated all affected .md files to reflect changes |
|
||||
|
||||
---
|
||||
|
||||
## Session 3 — 2026-03-07 (Remote)
|
||||
|
||||
**Focus:** Backup setup, config exports, quick fixes, network diagnostics
|
||||
|
||||
| Time | Task | Details |
|
||||
|------|------|---------|
|
||||
| | CS-SERVER DNS forwarder verified | Confirmed forwarder is 192.168.0.1 (item G) |
|
||||
| | CS-SERVER timezone fixed | Changed from Pacific to Arizona (UTC-07:00, no DST) to match pfSense |
|
||||
| | Room 218 DHCP fixed | Changed range end from 10.2.18.2 to 10.2.18.14 in pfSense |
|
||||
| | Room 130 firewall rule deleted | Removed disabled TCP PASS rule from Room130 interface |
|
||||
| | pfSense config exported | Downloaded XML config (with and without RRD data), saved to D:\Shares\IT\Backups\pfSense\ |
|
||||
| | Synology Active Backup for Business | Installed on Synology — **BLOCKED: requires Btrfs, NAS is ext4.** Cannot use ABB. Will use Windows Server Backup instead. |
|
||||
| | Synology Drive Client | Reinstalled on CS-SERVER, configured live sync to D:\Shares\Main (all Synology shares) |
|
||||
| | Synology share audit | Enumerated shares via SMB: homes (228 GB), Public (50 GB), SalesDept (13 GB), Server (2 GB), Management (1.4 GB), chat (0), home (0). Total ~294 GB. 4 shares (Activities, pacs, Sandra Fish, web) not visible via SMB. |
|
||||
| | ARP flapping investigation | Analyzed pfSense ARP logs, found 5 IP conflicts |
|
||||
| | LG TV ARP conflict fixed | TV was dual-connected (WiFi + ethernet). Disabled ethernet port on 1st Floor USW Port 18. Flapping resolved. |
|
||||
| | Brother printer conflict identified | 192.168.2.53 — printer dual-connected (WiFi + ethernet). Needs onsite fix. |
|
||||
| | Minor ARP conflicts triaged | Room 307, Room 130, iPhone MAC randomization — low priority, noted for onsite |
|
||||
| | AD/DNS/Permissions exported | Exported users, computers, groups, domain admins, DNS records, zones, forwarders, SMB shares, GPOs to D:\Shares\IT\Backups\ |
|
||||
| | AD export analysis | Identified: 3 non-IT users in Domain Admins, 12 accounts to remove, 3 undocumented GPOs from Dec 2025, most users never logged in |
|
||||
| | GPO report export + analysis | Exported full GPO report (Get-GPOReport -All). Reviewed all 6 GPOs: 3 Dec 2025 GPOs (CopyRoomPrinter, Nurses-Kiosk, MemCareMedTechPrinter) are completely empty — no settings, no links. Found account lockout disabled (threshold=0) in Default Domain Policy. |
|
||||
| | Session planning | Created session3 runbook, phase0-remote-checks.ps1 script |
|
||||
| | Documentation updates | Updated issue log (6 issues resolved), AD docs, backup docs, migration docs, session log |
|
||||
|
||||
---
|
||||
|
||||
## Session 4 — 2026-03-07 (Remote)
|
||||
|
||||
**Focus:** AD OU structure cleanup planning + script creation
|
||||
|
||||
| Time | Task | Details |
|
||||
|------|------|---------|
|
||||
| | AD OU structure audit | Identified 10 duplicate root-level department OUs, 3 empty root OUs (Managment, MemCare, Sales), 20 misplaced accounts in CN=Users |
|
||||
| | phase2-ou-cleanup.ps1 | Created script: audit root OUs (confirm empty + no GP links), delete 13 root-level OUs, delete/disable stale CN=Users accounts, flag Lupe.Sanchez duplicate |
|
||||
| | phase2-ad-setup.ps1 updated | Added prerequisite note for OU cleanup, CS-QB exclusion comment |
|
||||
| | active-directory.md updated | Added current vs target OU structure, CN=Users placement plan, 4 new issues (root OUs, CN=Users, CN=Computers, Lupe.Sanchez) |
|
||||
| | Issue log updated | Added 2 issues: root-level OU junk, Lupe.Sanchez duplicate |
|
||||
|
||||
---
|
||||
|
||||
## Session 5 — 2026-03-08 (Remote)
|
||||
|
||||
**Focus:** M365 tenant audit, AD↔M365 identity mapping, shared workstation GPO design
|
||||
|
||||
| Time | Task | Details |
|
||||
|------|------|---------|
|
||||
| | M365 tenant documented | Tenant: cascadestucson.com, ID: 207fa277-..., domain: cascadestucson.com, admin: Sandra Fish (admin@NETORGFT4257522.onmicrosoft.com) |
|
||||
| | User export analysis | Exported 51 M365 users, cross-referenced against 46 AD accounts. Built full AD↔M365 mapping. |
|
||||
| | Identity mapping | 24 AD accounts matched to M365. 13 AD users have no M365. 2 M365 users (nick pavloff, Kristiana Dowse) not in AD. |
|
||||
| | License audit | Business Standard 34/34 (0 available). 12 role-based accounts wasting licenses (~$150/mo). Entra ID P2 (1, Sandra Fish). |
|
||||
| | Shared mailbox audit | 4 shared mailboxes: 3 former employees (Anna Pitzlin, Jeff Bristol, Nela Durut-Azizi) + Fax Cascades |
|
||||
| | External guest audit | 6 guest accounts: 3 personal emails (jensen, dupras, rossini), 2 Howard accounts (1 typo "howaed"), 1 external partner (Debora Morris) |
|
||||
| | Name mismatch found | Tamra Johnson (AD) → tamra.matthews@ (M365) — married name not updated in AD |
|
||||
| | Shared workstation GPO | Added SharedComputers OU to phase2-ad-setup.ps1, GPO 6 design to phase2-server-prep.md, updated AD target OU tree |
|
||||
| | cloud/m365.md | Fully populated from blank template — tenant info, licensing, full AD↔M365 mapping, shared mailboxes, issues |
|
||||
| | 11 new issues logged | License exhaustion, role-account waste, Tamra name mismatch, 13 unmapped AD users, nick pavloff, Kristiana Dowse, Sandra Fish admin, former employee mailboxes, howaed typo, no Entra Connect |
|
||||
|
||||
---
|
||||
|
||||
## Session 6 — 2026-03-09 (Remote + Onsite Data)
|
||||
|
||||
**Focus:** Onsite data entry, printer inventory, AD quick fixes
|
||||
|
||||
| Time | Task | Details |
|
||||
|------|------|---------|
|
||||
| | Printer inventory update | Full onsite printer data entered — 15 printers documented with models, SNs, IPs, users, locations. Resolved 6 previously unidentified printers. |
|
||||
| | Name changes documented | Tamra.Johnson→Matthews, Alyssa.Shestko→Brooks confirmed. Michelle.Shestko→Brooks pending. Updated all docs and scripts. |
|
||||
| | **Remove Monica.Ramirez from Domain Admins (IMPLEMENTED)** | Removed disabled account from DA group |
|
||||
| | **Delete 3 empty GPOs (IMPLEMENTED)** | Deleted CopyRoomPrinter, Nurses-Kiosk, MemCareMedTechPrinter — all empty, no links |
|
||||
| | **Fix account lockout policy (IMPLEMENTED)** | Set lockout threshold to 5 attempts, 30 min duration/observation window |
|
||||
| | **Rename QuickBooks group (IMPLEMENTED)** | Fixed "Quickboosk acccess" → "QuickBooks Access" |
|
||||
| | **pfSense aliases created** | Server_IPs (192.168.2.254), NAS_IP (192.168.0.120) created. Printer_IPs, AD_Ports, Print_Ports created then removed — not needed. |
|
||||
| | Firewall strategy revised | Original plan: scoped INTERNAL→LAN rules for each resource. Revised: move all PCs and printers to INTERNAL VLAN 20 (same subnet), then lock down after migration. Simpler, fewer rules needed. |
|
||||
| | RFC1918 alias correction | Documented as created in Session 2 but was never actually created. Using built-in `_private4_` alias instead. |
|
||||
| | **ASSISTNURSE-PC upgraded to Win11 Pro (IMPLEMENTED)** | Upgraded from Windows Home to Windows 11 Pro using product key — enables domain join |
|
||||
|
||||
---
|
||||
|
||||
## Session 7 — 2026-03-11 (Onsite)
|
||||
|
||||
**Focus:** Quick wins — Guest WiFi test, kitchen thermal printer inventory, printer doc corrections
|
||||
|
||||
| Time | Task | Details |
|
||||
|------|------|---------|
|
||||
| | **Guest WiFi isolation tested (VERIFIED)** | Connected to Guest SSID, got 10.0.50.x IP. Fixed DHCP: changed DNS to 8.8.8.8/1.1.1.1, cleared domain name (was cascades.local). Internet works, cannot ping CS-SERVER or access shares — isolation confirmed. |
|
||||
| | **Guest DHCP DNS fix (IMPLEMENTED)** | GUEST DHCP scope was handing out pfSense DNS + cascades.local domain. Blocked by firewall rules (block all private IPs). Changed to public DNS 8.8.8.8/1.1.1.1, cleared domain name. |
|
||||
| | **Kitchen thermal printer inventory (DONE)** | 2 printers: Bistro — Epson TM-T88VII (M371A) at 192.168.2.207, Kitchen cooks — Epson TM-U220IIB (M384B) at 10.0.20.225. Both ethernet, both receive orders from 9 iPads. |
|
||||
| | **"Port 8 Epson" mystery resolved** | Previously unaccounted 192.168.2.207 is the Bistro thermal printer |
|
||||
| | **MemCare printer corrections** | Room 615 printer (192.168.2.53) is WiFi-only with static IP, NOT dual-connected. MemCare Reception needs dummy switch replaced with UniFi. Added room numbers (615, 603). |
|
||||
| | **Nick Pavloff clarification** | M365 account is for Synology admin only. Plan: change Synology admin email to another account, then delete Nick's M365 to free license. |
|
||||
| | **Bistro dummy switch identified** | Bistro has a non-managed switch splitting connection for thermal printer, CC, and other devices. Plan: replace with UniFi switch, set ports to VLAN 20 (CSCNet). Same situation as MemCare reception. |
|
||||
| | **Bistro printer VLAN move planned** | Bistro Epson TM-T88VII (192.168.2.207) to be moved to CSCNet (VLAN 20) once UniFi switch installed. Test iPad printing after move — cooks printer already on CSCNet (10.0.20.225) so iPads likely already route there. |
|
||||
|
||||
---
|
||||
|
||||
## Onsite / Remote — Migration Tasks
|
||||
|
||||
### PC Migration (Phase 1.4) — Move to CSCNet WiFi
|
||||
Connect each PC to CSCNet, forget CSC ENT, verify connectivity.
|
||||
|
||||
| PC | Current IP | User(s) | Status |
|
||||
|----|-----------|---------|--------|
|
||||
| RECEPTIONIST-PC | 192.168.2.17 | CJ, Christina, Kyla, Tiffany | [ ] |
|
||||
| RECEPTIONIST-PC (2nd) | 192.168.3.187 | Receptionist | [ ] |
|
||||
| ASSISTMAN-PC | 192.168.2.38 | Assistant Manager | [ ] |
|
||||
| ASSISTNURSE-PC | 192.168.2.153 | Assist Nurse | [ ] WiFi — upgraded to Win11 Pro, move to CSCNet later |
|
||||
| NURSESTATION-PC | 192.168.3.135 | Nurse Station | [ ] |
|
||||
| MEMRECEPT-PC | 192.168.3.41 | MemCare Reception | [ ] |
|
||||
| ANN-PC | 192.168.3.252 | Ann | [ ] |
|
||||
| MDIRECTOR-PC | 192.168.3.20 | Shelby Trozzi | [ ] Needs Pro upgrade first |
|
||||
| DESKTOP-LPOPV30 | 192.168.2.250 | Unknown | [ ] |
|
||||
| DESKTOP-U2DHAP0 | 192.168.3.37 | Unknown | [ ] |
|
||||
| DESKTOP-TRCIEJA | 192.168.3.93 | Unknown | [ ] |
|
||||
| DESKTOP-DLTAGOI | 192.168.3.133 | Unknown | [ ] |
|
||||
| DESKTOP-ROK7VNM | 192.168.3.148 | Unknown | [ ] |
|
||||
| DESKTOP-MD6UQI3 | 192.168.3.208 | Unknown | [ ] |
|
||||
|
||||
### Printer Migration (Phase 1.5) — Change switch port to VLAN 20
|
||||
Requires: identify switch port, change VLAN, DHCP reservation, update PCs.
|
||||
|
||||
| Printer | Current IP | Users | Status |
|
||||
|---------|-----------|-------|--------|
|
||||
| Chef Brother | 192.168.3.88 | Chef | [ ] |
|
||||
| Kitchen Manager Canon | 192.168.3.232 | Alyssa | [ ] |
|
||||
| Meredith's Canon | 192.168.2.67 | Meredith | [ ] |
|
||||
| MemCare Director Canon | 192.168.3.52 | Shelby | [ ] |
|
||||
| MemCare Nurse Brother | 192.168.2.53 | MemCare nurses | [ ] |
|
||||
| Room 103 Brother | 192.168.2.145 | Ashley, Christina | [ ] |
|
||||
| Room 132 Canon | 192.168.3.211 | Sharon, Susan | [ ] |
|
||||
| Room 217 Sales Brother | 192.168.3.44 | Sales team | [ ] |
|
||||
| Room 206 Bizhub | 192.168.1.138 | Health Services | [ ] |
|
||||
| Accounting Canon | 192.168.3.227 | Lauren | [ ] |
|
||||
| Front Desk Epson | 192.168.2.147 | 4 users | [ ] |
|
||||
| Copy Room Canon | 192.168.2.230 | Everyone | [ ] **LAST** |
|
||||
| MemCare Reception Epson | — | MemCare Recept | [ ] Needs hardwire first |
|
||||
|
||||
### Other Onsite Tasks
|
||||
|
||||
| Task | Details |
|
||||
|------|---------|
|
||||
| ~~Test Guest WiFi isolation~~ | ~~Connect to Guest SSID, verify 10.0.50.x IP, no LAN access~~ **DONE 2026-03-11** |
|
||||
| Identify unknown devices | DESKTOP-1ISF081, DESKTOP-KQSL232, DESKTOP-VAVKCIM |
|
||||
| User-to-machine mapping | Document who uses each PC for GPO targeting |
|
||||
| MDIRECTOR-PC Pro upgrade | Install Windows 10 Pro upgrade key |
|
||||
| SALES4-PC status | Locate or confirm decommissioned |
|
||||
| Two RECEPTIONIST-PCs | Determine which is primary |
|
||||
| 9 offline APs | Check PoE, cables, re-adopt |
|
||||
| Room 307 ARP conflict | Check if still occurring |
|
||||
|
||||
---
|
||||
|
||||
## Outstanding Work — Prioritized
|
||||
|
||||
### Priority 1: CRITICAL
|
||||
- [ ] **Set up backup** — Windows Server Backup to Synology SMB share (ABB blocked by ext4)
|
||||
- [x] ~~**Remove Monica.Ramirez from Domain Admins**~~ — DONE 2026-03-09
|
||||
|
||||
### Priority 2: HIGH (security)
|
||||
- [x] ~~Create firewall aliases~~ — Server_IPs and NAS_IP created. Others not needed (printers moving to INTERNAL VLAN). DONE 2026-03-09
|
||||
- [ ] Replace INTERNAL firewall rules — **deferred until after all devices migrated to VLAN 20**
|
||||
- [ ] Disable floating rule #4 + add scoped room internet rule — **deferred until post-migration**
|
||||
- [x] ~~Remove Meredith.Kuhn and John.Trozzi from Domain Admins~~ — DONE 2026-04-13
|
||||
- [x] ~~Review 3 undocumented GPOs~~ — REVIEWED: all 3 are empty (no settings, no links). Delete in Phase 2.2.
|
||||
- [x] ~~Delete 3 empty GPOs (CopyRoomPrinter, Nurses-Kiosk, MemCareMedTechPrinter)~~ — DONE 2026-03-09
|
||||
- [x] ~~Fix account lockout policy~~ — Set to 5 attempts / 30 min lockout — DONE 2026-03-09
|
||||
|
||||
### Priority 3: MEDIUM (cleanup)
|
||||
- [ ] Delete VLAN 10 from UniFi
|
||||
- [x] ~~Disable/delete 12 stale AD accounts~~ — DONE 2026-04-13 (13 accounts deleted)
|
||||
- [ ] Remove unused server roles (NPS, RDS)
|
||||
- [ ] Create DHCP reservation for LG TV WiFi MAC (e0:85:4d:4d:f0:3e → 192.168.2.148)
|
||||
- [x] ~~Fix Brother printer dual-connection (onsite)~~ — NOT an issue. 192.168.2.53 is WiFi-only with static IP. DONE 2026-03-11
|
||||
|
||||
### Priority 4: Phase 2+ (AD/server prep)
|
||||
- [x] ~~**Run phase2-ou-cleanup.ps1** — audit + delete 13 root-level OUs, clean CN=Users accounts~~ — DONE 2026-04-13 (manual commands)
|
||||
- [x] ~~**Run phase2-ad-setup.ps1** — security fixes, Workstations OU (incl. Shared PCs), security groups, computer moves~~ — Partially DONE 2026-04-13 (Workstations OU created, DA cleaned, UPNs updated. Security groups + computer moves still pending)
|
||||
- [ ] Set up file share permissions on CS-SERVER
|
||||
- [ ] Create GPOs (drive maps, printers, security baseline, updates, folder redirection, shared workstation)
|
||||
- [ ] Domain-join non-domain machines
|
||||
- [ ] Synology retirement + backup-only repurpose
|
||||
|
||||
### Priority 5: M365 Cleanup
|
||||
- [ ] **Convert 12 role-based accounts to shared mailboxes** — accounting@, frontdesk@, hr@, security@, memcarereceptionist@, boadmin@, accountingassistant@, Training@, Kitchenipad@, medtech@, nurse@, transportation@. Frees ~12 licenses (~$150/mo)
|
||||
- [ ] **Delete nick pavloff M365 account** — account was only for Synology admin. Change Synology admin email to another account first, then delete to free license.
|
||||
- [x] ~~**Update Tamra.Johnson → Tamra.Matthews in AD**~~ — DONE 2026-04-13
|
||||
- [ ] **Delete Kristiana Dowse M365 account** — HR confirmed not current employee (2026-03-10). Frees 1 license.
|
||||
- [ ] **Delete "howaed" guest account** — typo duplicate of howard@azcomputerguru.com
|
||||
- [ ] **Delete Anna Pitzlin & Nela Durut-Azizi shared mailboxes** — HR confirmed OK to delete (were forwarded to Meredith, no longer needed). Jeff Bristol still pending.
|
||||
- [ ] **Review Sandra Fish global admin** — previous owner still holds the only global admin. Create break-glass admin?
|
||||
- [ ] **Install Entra Connect** — planned for CS-SERVER, AD cleanup complete, UPNs updated. Blocked on: M365 shared mailbox conversions
|
||||
- [ ] **Determine if AD users need M365** — HR confirmed all current employees (2026-03-10). Roles: Front Desk/Courtesy Patrol, MC Front Desk, Transportation, Housekeeping. Do they need email? Free licenses first via role account cleanup.
|
||||
|
||||
### Priority 6: Audit Findings (2026-03-10)
|
||||
|
||||
**Doc fixes:**
|
||||
- [x] Fix Room 206 printers in `phase2-print-server.ps1` — Added Bizhub C368 + 206 Nurse Station Brother as separate entries — DONE
|
||||
- [x] Fix `firewall.md` post-migration rules — changed "RFC1918" to `_private4_` — DONE
|
||||
- [x] Fix `dhcp.md` Room 218 — marked as FIXED 2026-03-07 — DONE
|
||||
- [x] Fix `dhcp.md` printer 192.168.2.53 — updated to online with MAC — DONE
|
||||
- [x] Fix `step3-switch-ports.md` — Added Bizhub C368 + 206 Nurse Station — DONE
|
||||
- [x] Fix RFC1918 alias entry in Session 2 billing record — corrected — DONE
|
||||
- [x] Standardize "MemCare MedTech" printer naming across all docs — DONE
|
||||
|
||||
**Resolved with Howard's input:**
|
||||
- [x] ~~**Duplicate Alyssa accounts**~~ — Resolved: Alyssa.Shestko renamed to Alyssa.Brooks, lowercase duplicate deleted — DONE 2026-04-13
|
||||
- [x] **SALES4-PC** — Active, used by Tamra Matthews. Was just offline during audit. Updated overview.md. — DONE
|
||||
- [x] **Azure docs** — No Azure services. M365 + GoDaddy web hosting only. Updated `cloud/azure.md`. — DONE
|
||||
|
||||
**Needs onsite / separate session:**
|
||||
- [ ] M365 email audit — SPF, DKIM, DMARC, MX records all TBD
|
||||
- [ ] Synology shares "pacs" and "web" — purpose unknown (may contain PHI)
|
||||
- [ ] CS-SERVER ports 5504, 6783, 8019 — unidentified listeners
|
||||
- [ ] Room 339 interface — may be disabled in pfSense
|
||||
- [ ] 9 offline APs — need physical investigation
|
||||
- [x] ~~**Kitchen thermal printer inventory**~~ — 2 printers: Bistro TM-T88VII (192.168.2.207), Kitchen TM-U220IIB (10.0.20.225). DONE 2026-03-11
|
||||
- [ ] **Verify ALIS BAA** — ask management if signed BAA exists with go-alis.com
|
||||
- [ ] **Sign Microsoft BAA** — M365 Admin → Settings → Org Settings → Security & Privacy → HIPAA BAA
|
||||
- [ ] **Enable MFA** — Security Defaults in Entra ID (free, 5 min to enable)
|
||||
|
||||
### Onsite Visit Additions (from M365 audit)
|
||||
- [ ] Identify shared workstation computer names for GPO 6 targeting
|
||||
- [ ] Confirm nick pavloff's department and PC assignment
|
||||
- [x] ~~Ask about Kristiana Dowse — current or former?~~ HR confirmed DELETE (2026-03-10)
|
||||
- [ ] Map user-to-shared-PC rotation matrix for shared mailbox permissions
|
||||
|
||||
---
|
||||
|
||||
## Session 8 — 2026-03-20 (Remote)
|
||||
|
||||
**Focus:** Audit script deployment, GitHub hosting, ScreenConnect Toolbox setup
|
||||
|
||||
| Time | Task | Details |
|
||||
|------|------|---------|
|
||||
| | Audit script updates | Removed .txt transcript output (JSON only), added hostname to filenames (HOSTNAME_audit_DATE.json) |
|
||||
| | Script self-relaunch fix | Changed `-Verb RunAs` to `-NoNewWindow -WindowStyle Hidden` for silent ScreenConnect execution |
|
||||
| | GitHub repo created | Created public repo `Howweird/msp-audit-scripts` with server_audit.ps1, workstation_audit.ps1, README.md |
|
||||
| | ScreenConnect Toolbox commands | Built commands for: server audit, workstation audit, clear C:\Temp. Documented ScreenConnect 80-char line limit. |
|
||||
| | ScreenConnect line-wrapping fix | Discovered ScreenConnect silently truncates long lines (~120 chars). Rewrote all commands with URLs in variables, short lines. Added rules to CLAUDE.md. |
|
||||
|
||||
---
|
||||
|
||||
## Session 9 — 2026-03-20/21/22 (Remote)
|
||||
|
||||
**Focus:** Full fleet audit, security remediation, Windows upgrades
|
||||
|
||||
| Time | Task | Details |
|
||||
|------|------|---------|
|
||||
| | **Full fleet audit** | Ran server + workstation audits on 19 machines (1 server, 18 workstations) via ScreenConnect Toolbox |
|
||||
| | **Workstation inventory created** | Created `cascades/workstations.md` — full hardware, OS, users, software, security findings for all 18 workstations |
|
||||
| | **Documentation updates** | Updated cs-server.md (security findings, disk usage, software, share permissions), active-directory.md (functional levels, new users, login activity), antivirus.md (deployment status for all 19 endpoints), hipaa.md (11 new gaps), overview.md (workstation table with audit data) |
|
||||
| | **Master issue tracker** | Built combined issue tracker (42 items) merging audit findings with all prior issue log entries, organized by severity |
|
||||
| | **Pro key applied to 4 machines** | ANN-PC, DESKTOP-DLTAGOI, MAINTENANCE-PC, MDIRECTOR-PC — Win 11 Home → Pro via changepk ScreenConnect command |
|
||||
| | **RDP disabled on 2 machines** | ASSISTMAN-PC and DESKTOP-U2DHAP0 — were exposed without NLA |
|
||||
| | **AD Recycle Bin enabled** | Was off — deleted objects were unrecoverable |
|
||||
| | **MachineAccountQuota set to 0** | Was 10 — any domain user could join machines |
|
||||
| | **RestrictAnonymous set to 1** | Was 0 — null sessions allowed on CS-SERVER |
|
||||
| | **Stale printer ports cleaned** | Ran cleanup script on all 18 workstations — removed orphan TCP/IP ports |
|
||||
| | **AutoPatch + Win 11 upgrade pushed** | Created PSWindowsUpdate scheduled tasks on 15 machines (overnight, auto-stop 5AM). Skipped CS-SERVER, RECEPTIONIST-PC, MEMRECEPT-PC |
|
||||
| | **Win 11 upgrade assistant** | Pushed to eligible Win 10 machines: DESKTOP-LPOPV30, NURSESTATION-PC, LAPTOP-DRQ5L558, LAPTOP-E0STJJE8. Also 25H2 upgrade for CRYSTAL-PC, DESKTOP-U2DHAP0, LAPTOP2 |
|
||||
| | **ScreenConnect Toolbox expanded** | Added commands for: auto-patch, auto-patch+upgrade, stop updates at 5AM, Pro key push, stale printer port cleanup |
|
||||
| | **Network analysis** | Identified DNS misconfiguration (15 machines pointing to pfSense instead of CS-SERVER), cross-subnet routing issues, printer port IP mismatches |
|
||||
| | **DirecTV VLAN issue documented** | Older DirecTV boxes can't connect to VLAN networks — must join CSC ENT first for update, then move to CSCNet |
|
||||
| | **Pro key documented** | Volume license key added to root CLAUDE.md with usage log tracking requirement |
|
||||
|
||||
---
|
||||
|
||||
## Session 10 — 2026-04-13 (Onsite + Remote)
|
||||
|
||||
**Focus:** Workstation upgrades, domain joins, printer setup, AD cleanup, Entra Connect planning, MDM planning
|
||||
|
||||
### Workstation Upgrades & Domain Joins
|
||||
| Task | Details |
|
||||
|------|---------|
|
||||
| **DESKTOP-DLTAGOI — Pro upgrade + domain join** | Upgraded Win 11 Home → Pro (manual key — PowerShell method caused Enterprise). Joined to cascades.local. |
|
||||
| **DESKTOP-DLTAGOI — User setup** | Created domain user Sharon.Edwards (Life Enrichment Assistant). Removed local accounts: casadmin201, rootadmin, local "Sharon Edwards". Disabled system accounts. |
|
||||
| **DESKTOP-DLTAGOI — Printer cleanup** | Removed all Brother printers. Added Copy Room printer manually. |
|
||||
| **DESKTOP-ROK7VNM — Pro upgrade + domain join** | New machine (not in previous audit). Upgraded to Pro (manual key). Joined to cascades.local. |
|
||||
| **DESKTOP-ROK7VNM — User setup** | Created domain user Susan.Hicks (Life Enrichment Director). Removed local accounts: casadmin201, nick, SusanH, Megan Wicker. |
|
||||
| **MAINTENANCE-PC — Pro upgrade** | Upgraded Win 11 Home → Pro (manual key). Domain join pending. |
|
||||
| **MAINTENANCE-PC — Disk cleanup** | Cleared SoftwareDistribution, temp files, DISM component cleanup, deleted nick user profile. |
|
||||
| **Pro key issue documented** | PowerShell `changepk` method from Session 9 caused Enterprise edition on some machines. Manual key entry through Settings is the correct method. |
|
||||
|
||||
### Printer Work
|
||||
| Task | Details |
|
||||
|------|---------|
|
||||
| **Room 132 Canon MF741CDW — Factory reset** | Printer was locked out (System Manager ID/PIN unknown). Factory reset successful. |
|
||||
| **Room 132 Canon — Moved to INTERNAL VLAN** | Connected to CSCNet WiFi, set static IP 10.0.20.94. Previously was 192.168.3.211 on LAN. |
|
||||
| **Print server planning** | Planned GPO-based printer deployment via CS-SERVER print server. Print Services role check needed. Naming convention: Floor-Room-Model (e.g. 1F-132-RecRoom-Canon). |
|
||||
|
||||
### AD Cleanup (on CS-SERVER)
|
||||
| Task | Details |
|
||||
|------|---------|
|
||||
| **Deleted 13 stale accounts** | Anna.Pitzlin, Nela.Durut-Azizi, Jodi.Ramstack, Monica.Ramirez (disabled/former). Haris.Durut, Nuria.Diaz, Cathy.Reece, Kelly.Wallace, Isabella.Islas, ann.dery (not on HR roster). alyssa.brooks (lowercase duplicate). Lupe.Sanchez (duplicate of Guadalupe). jeff.bristol (replaced by Lauren). |
|
||||
| **Renamed 5 accounts** | Tamra.Johnson → Tamra.Matthews, Alyssa.Shestko → Alyssa.Brooks, Guadalupe.Sanchez → Lupe.Sanchez, strozzi → Shelby.Trozzi, Christopher.Holik → Christopher.Holick |
|
||||
| **Removed non-IT from Domain Admins** | Removed Meredith.Kuhn and John.Trozzi. Only Administrator and sysadmin remain. |
|
||||
| **Deleted root-level duplicate OUs** | 13 empty root-level OUs (confirmed already deleted from previous session). |
|
||||
| **Created Workstations OU** | OU=Workstations with sub-OUs: Staff PCs, Shared PCs. |
|
||||
| **Added UPN suffix** | Added cascadestucson.com as UPN suffix to AD forest. |
|
||||
| **Updated all 33 user UPNs** | Changed from @cascades.local to @cascadestucson.com for Entra Connect SSO readiness. |
|
||||
| **Created Kyla.QuickTiffany account** | New Resident Services Receptionist. Placed in OU=Resident Services. |
|
||||
| **Full HR roster imported** | All 32 employees documented with positions, departments, and shared email group assignments. |
|
||||
|
||||
### Print Server & GPO Setup
|
||||
| Task | Details |
|
||||
|------|---------|
|
||||
| **Removed Roaming share** | Deleted D:\Roaming and SMB share — unused, replaced by Folder Redirection |
|
||||
| **Created homes share** | D:\Homes shared as \\CS-SERVER\homes — Domain Admins full, Domain Users change. For Folder Redirection. |
|
||||
| **RecRoom Canon added to print server** | Added printer port TCP_10.0.20.94, shared as "RecRoom-Canon" using Canon Generic Plus PCL6 driver |
|
||||
| **CSC - Life Enrichment Printers GPO** | Created and linked to OU=Life Enrichment. RecRoom Canon deployed via Print Management (per user). |
|
||||
| **CSC - Folder Redirection GPO** | Created and linked to OU=Departments. GPMC Folder Redirection extension broken on CS-SERVER — fdeploy.ini not being created. Worked around using GP Preferences > Registry to set shell folder paths (Desktop, Documents, Downloads → \\CS-SERVER\homes\%USERNAME%\). |
|
||||
| **Folder Redirection verified** | Tested with Sharon.Edwards — Desktop redirects to \\CS-SERVER\homes\sharon.edwards\Desktop. Documents and Downloads also configured. |
|
||||
| **Moved 6 PCs to Staff PCs OU** | ACCT2-PC, CRYSTAL-PC, DESKTOP-H6QHRR7, DESKTOP-1ISF081, DESKTOP-DLTAGOI, DESKTOP-ROK7VNM moved to OU=Staff PCs,OU=Workstations. CS-QB left in CN=Computers. |
|
||||
| **Data migration slow** | Robocopy to server limited by Sharon's 72 Mbps WiFi (~8 MB/s). Server storage is two PERC RAID virtual disks (300GB C: + 1.1TB D:), likely spinning SAS. Consider SSD upgrade + hardwiring PCs for speed. |
|
||||
|
||||
### Planning & Documentation
|
||||
| Task | Details |
|
||||
|------|---------|
|
||||
| **Entra Connect SSO plan** | Documented full plan in cloud/m365.md — prerequisites, install steps, sync scope. Enables single sign-on: AD login → Office/Edge/Outlook auto-activate. |
|
||||
| **M365 license optimization** | Planned conversion of 12 role-based accounts to shared mailboxes. 10 staff (drivers, receptionists, courtesy patrol) get AD + SSO but no paid license. Saves ~$137.50/month (11 licenses freed). |
|
||||
| **ManageEngine MDM** | Account created. Will manage employee Android phones (HIPAA compliance) + 9 kitchen iPads (lockdown/kiosk mode). Created security/mdm.md. |
|
||||
| **Len's Auto Brokerage (LAB)** | New client folder created. Documented lab-server (Server 2008 SP2, EOL) and DESKTOP-BMBTQLI (HPE MicroServer Gen10 Plus v2, current server). RDP troubleshooting on Server 2008 — CredSSP incompatibility. |
|
||||
|
||||
### Billing Summary — Session 10
|
||||
| Category | Items |
|
||||
|----------|-------|
|
||||
| Workstation upgrades (Pro key + domain join) | 3 machines (DLTAGOI, ROK7VNM, MAINTENANCE-PC) |
|
||||
| User setup + local account cleanup | 3 machines |
|
||||
| Printer reset + VLAN move + print server | 1 printer factory reset, moved to INTERNAL VLAN, added to print server, deployed via GPO |
|
||||
| AD cleanup | 13 accounts deleted, 5 renamed, 2 removed from Domain Admins, OU cleanup, UPN migration, 1 new account created |
|
||||
| GPO setup | 2 GPOs created (Life Enrichment Printers, Folder Redirection). Folder Redirection working via GP Preferences workaround. |
|
||||
| File server setup | Homes share created, Roaming share removed, 6 PCs moved to Staff PCs OU |
|
||||
| Infrastructure planning | Entra Connect SSO, M365 license optimization, MDM setup |
|
||||
| New client setup | Len's Auto Brokerage — folder + initial docs + RDP troubleshooting |
|
||||
|
||||
### Session 10b — 2026-04-14 (Remote + Onsite)
|
||||
|
||||
**Focus:** Continued Life Enrichment setup, GPO troubleshooting, OneDrive cleanup
|
||||
|
||||
| Task | Details |
|
||||
|------|---------|
|
||||
| **Narrowed Folder Redirection GPO** | Moved link from OU=Departments to OU=Life Enrichment only. Roll out dept by dept. |
|
||||
| **Susan.Hicks OneDrive cleanup** | ProfWiz migrated old SusanH profile with OneDrive folder redirection. Fixed shell folders (Desktop, Documents, Downloads, Videos, Pictures, Attachments) back to local %USERPROFILE% paths. Uninstalled OneDrive. |
|
||||
| **Printer GPO troubleshooting** | Print Management "Deploy with Group Policy" not saving to SYSVOL (same broken GPMC issue as Folder Redirection). Fixed using GP Preferences > Shared Printer instead — \\CS-SERVER\RecRoom-Canon. Printers.xml confirmed in SYSVOL. |
|
||||
| **Susan data migration** | Robocopy of Susan's data to \\CS-SERVER\homes in progress — slow due to WiFi. |
|
||||
|
||||
### Session 10c — 2026-04-14 (Remote)
|
||||
|
||||
**Focus:** M365 admin cleanup, MDM planning, ALIS SSO research, proposal
|
||||
|
||||
| Task | Details |
|
||||
|------|---------|
|
||||
| **Sandra Fish admin removed** | Revoked global admin, blocked sign-in, removed P2 license. sysadmin@cascadestucson.com is now sole global admin. |
|
||||
| **Entra P2 license freed** | 1 P2 license available for Conditional Access testing when ready. |
|
||||
| **ALIS SSO confirmed** | ALIS supports Microsoft Entra SSO (Azure AD / Office 365). Requires App Registration in Azure Portal + ALIS App Store config. Users must have matching email in ALIS and Entra. |
|
||||
| **M365 Business Premium proposal** | Created formal proposal at cascades/proposals/m365-premium-upgrade.md. Net savings of $56.50/mo after shared mailbox cleanup. Covers Intune, Conditional Access, Defender, DLP. |
|
||||
| **MDM plan documented** | Full 7-phase ManageEngine MDM rollout plan in security/mdm.md. 25 shared Android phones + 9 kitchen iPads. |
|
||||
| **Folder Redirection GPO narrowed** | Moved from OU=Departments to OU=Life Enrichment only. Roll out dept by dept. |
|
||||
| **Susan Hicks OneDrive cleanup** | Fixed shell folders pointing to old OneDrive paths after ProfWiz migration. Uninstalled OneDrive. |
|
||||
|
||||
### Session 10d — 2026-04-14 (Remote, extended diagnostic — inconclusive)
|
||||
|
||||
**Focus:** Try to make Folder Redirection work natively and retire the GP Preferences Registry hack.
|
||||
|
||||
| Task | Details |
|
||||
|------|---------|
|
||||
| **SYSVOL health verified** | `dcdiag /test:sysvolcheck` passed, SYSVOL permissions correct, writable as admin |
|
||||
| **FR extension registration confirmed** | `gPCUserExtensionNames` on the old GPO correctly lists `{25537BA6-77A8-11D2-9B6C-0000F8080861}` (FR CSE) |
|
||||
| **NTFS on D:\Homes hardened** | Removed `BUILTIN\Users ReadAndExecute` inheritance to subfolders/files — was allowing cross-user read of redirected PHI (HIPAA violation). Scoped to "This folder only". CREATOR OWNER Full Control still inherits so each user owns their own home folder. |
|
||||
| **First diagnosis (WRONG)** | Initially thought GPMC on CS-SERVER was writing FR config to the wrong location (`User\Documents & Settings\fdeploy1.ini` with `FullPath=` + `Flags=1231`). Hypothesized a broken legacy ADMX template. |
|
||||
| **RSAT installed + tested** | Installed RSAT GPMC on Sharon.Edwards' Win11 PC (`Add-WindowsCapability -Online -Name "Rsat.GroupPolicy.Management.Tools~~~~0.0.1.0"`). Recreated `CSC - Folder Redirection (LE)` GPO from RSAT. |
|
||||
| **First diagnosis disproven** | RSAT wrote to the **same path** as CS-SERVER's GPMC (`User\Documents & Settings\fdeploy1.ini` with `FullPath=`). Two independent tools writing identical files = that IS the correct modern format. The "Documents & Settings" subfolder and `FullPath=` syntax are NOT legacy — they're normal modern FR layout. The original GPO was broken simply because the save was incomplete (empty `fdeploy.ini`, stub `fdeploy1.ini` with `Flags=4` and no FullPath). |
|
||||
| **New GPO linked, old unlinked** | `CSC - Folder Redirection (LE)` linked to OU=Life Enrichment; `CSC - Folder Redirection` unlinked from OU=Life Enrichment (GPO itself kept as 1-week rollback). |
|
||||
| **FR refuses to commit on Sharon** | At Sharon's logon, FR CSE fires, logs event **1006 "Documents has to be redirected"** with correct path+flags, logs event **1001 "extension finished"**. **No event 1013 (success), no error events.** `User Shell Folders\Personal` stays at `C:\Users\Sharon Edwards\Documents`. Multiple logon cycles don't help. `gpupdate /force` doesn't help. Permissions verified (Sharon has FullControl, write test succeeds). Target path reachable. FR history key (`HKCU\...\History\{25537BA6-...}`) still references OLD unlinked GPO; key is SYSTEM-protected, can't clear from user context. |
|
||||
| **Investigation parked** | Howard wants to avoid the registry hack as the answer. Captured leading hypothesis + research search terms in plan file `C:\Users\howar\.claude\plans\immutable-imagining-spring.md`. |
|
||||
| **Documented** | Revised `servers/cs-server.md` "Known Admin Issues" section to correct the earlier wrong theories and accurately describe the silent-no-commit symptom. |
|
||||
|
||||
### Where We Left Off (2026-04-14 — Session end, investigation parked)
|
||||
|
||||
**Leading hypothesis (needs confirmation via research):**
|
||||
The FR policy has "Grant user exclusive rights" enabled (Flags=1231 bit 0x1). When the target folder `\\CS-SERVER\homes\sharon.edwards\Documents` already exists with a non-Sharon owner (sysadmin created it during the original registry-hack migration, and we re-created it manually during tonight's diagnostic), FR can't rewrite the folder's ACL to Sharon-only. Documented FR quirk: logs intent via 1006, silently aborts without logging to Operational channel. This matches our exact fingerprint (1006 fires, 1013 never fires, zero errors).
|
||||
|
||||
**Fast sanity-check for next session (read-only):**
|
||||
```powershell
|
||||
(Get-Acl "D:\Homes\sharon.edwards\Documents").Owner
|
||||
```
|
||||
If owner is anything other than `CASCADES\sharon.edwards`, hypothesis strongly supported.
|
||||
|
||||
**Search terms Howard will research:**
|
||||
1. Primary: `Folder Redirection "has to be redirected" event 1006 no 1013 silent no error`
|
||||
2. Hypothesis-driven: `Folder Redirection "Grant the user exclusive rights" existing folder silently fails ownership`
|
||||
3. Fallback: `Folder Redirection Windows 10 event 1001 finished but folder not redirected registry`
|
||||
|
||||
**If hypothesis confirmed — next steps:**
|
||||
1. `takeown /F "D:\Homes\sharon.edwards\Documents" /A` then `icacls ... /setowner "CASCADES\sharon.edwards" /T`
|
||||
2. Clear FR history from elevated context via `HKU\<SID>`
|
||||
3. Sharon log off + on, verify event 1013 fires and Documents redirects
|
||||
4. If successful, script this across all LE users' homes folders
|
||||
|
||||
**If hypothesis wrong — secondary paths to try:**
|
||||
- Enable FR verbose debug logging (`HKLM\...\Diagnostics\FdeployDebugLevel=0x10`), read `%windir%\debug\usermode\fdeploy.log` for the real skip reason
|
||||
- Test FR on a brand-new user with no profile history to rule out profile corruption
|
||||
- If still blocked, fall back to GP Preferences Registry for Documents (as already deployed for Desktop) — documented workaround, not the end state
|
||||
|
||||
**Current Sharon state (unchanged tonight):**
|
||||
- Desktop: `\\CS-SERVER\homes\Sharon.Edwards\Desktop` (working, via original registry hack — no FR involvement)
|
||||
- Documents: `C:\Users\Sharon Edwards\Documents` (local, FR failed to redirect)
|
||||
- Downloads: `C:\Users\Sharon Edwards\Downloads` (local)
|
||||
|
||||
**Phase D HIPAA hardening (still pending, after FR is working):**
|
||||
- `Set-SmbShare -Name homes -EncryptData $true -Force` (SMB encryption in transit)
|
||||
- Enable file access auditing on D:\Homes (§164.312(b) Audit Controls)
|
||||
- VSS + daily shadow copies on D: (§164.308(a)(7) Contingency Plan)
|
||||
- Backup D:\Homes to Synology via Windows Server Backup
|
||||
|
||||
**Phase D HIPAA hardening** (after FR is working):
|
||||
- `Set-SmbShare -Name homes -EncryptData $true -Force` (SMB encryption in transit)
|
||||
- Enable file access auditing on D:\Homes (§164.312(b) Audit Controls)
|
||||
- VSS + daily shadow copies on D: (§164.308(a)(7) Contingency Plan)
|
||||
- Backup D:\Homes to Synology via Windows Server Backup
|
||||
- Manually set NTFS permissions on D:\Homes (commands ready, not yet run):
|
||||
- CREATOR OWNER: full access to own folder only
|
||||
- Domain Users: can create subfolder, cannot access others
|
||||
- Domain Admins: full access
|
||||
- Lock down existing sharon.edwards and susan.hicks folders
|
||||
|
||||
**D:\Homes NTFS permissions (not yet run):**
|
||||
```
|
||||
icacls D:\Homes /inheritance:d
|
||||
icacls D:\Homes /remove "BUILTIN\Users"
|
||||
icacls D:\Homes /grant "CASCADES\Domain Admins:(OI)(CI)F"
|
||||
icacls D:\Homes /grant "CREATOR OWNER:(OI)(CI)F"
|
||||
icacls D:\Homes /grant "CASCADES\Domain Users:(CI)(AD)(RD)"
|
||||
```
|
||||
|
||||
**Data migration script ready (not yet run):**
|
||||
- Copy-only test version (robocopy /L for dry run, remove /L for real copy)
|
||||
- Move version (robocopy /MOVE) for production
|
||||
- Run on each user's machine while logged in as them
|
||||
|
||||
**Other pending:**
|
||||
- **Printer GPO:** RecRoom Canon added via GP Preferences. Needs gpupdate + re-login test on Sharon/Susan machines.
|
||||
- **Copy Room printer:** Not yet added to print server or GPO.
|
||||
- **MAINTENANCE-PC:** Pro upgraded, domain join + local account cleanup still pending.
|
||||
- **ANN-PC, MDIRECTOR-PC:** Check for Enterprise edition from PowerShell Pro key push.
|
||||
- **M365:** Sandra removed. Shared mailbox conversions pending. Entra Connect pending. Sign BAA. 23 licensed users confirmed.
|
||||
- **MDM:** ManageEngine Phase 1 tenant setup in progress. 25 shared Android phones + 9 kitchen iPads.
|
||||
- **ALIS SSO:** Confirmed Entra support. Needs App Registration in Azure Portal.
|
||||
- **Business Premium proposal:** cascades/proposals/m365-premium-upgrade.md — net -$56.50/mo.
|
||||
- **Len's:** RDP to Server 2008 still failing (CredSSP).
|
||||
- **Server storage:** Likely spinning SAS in Dell R610 — evaluate SSD upgrade.
|
||||
16
clients/cascades-tucson/docs/cloud/azure.md
Normal file
16
clients/cascades-tucson/docs/cloud/azure.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Azure / Cloud Services
|
||||
|
||||
## Azure Subscription
|
||||
- **No Azure services in use.** Cascades uses M365 only — no Azure VMs, networking, or cloud infrastructure.
|
||||
|
||||
## Other Cloud Services
|
||||
|
||||
| Service | Purpose | Notes |
|
||||
|---------|---------|-------|
|
||||
| Microsoft 365 Business Standard | Email, Office apps, OneDrive | See `cloud/m365.md` |
|
||||
| GoDaddy | Web hosting | cascadestucson.com website hosting |
|
||||
|
||||
## Notes
|
||||
- Cascades is a senior living / assisted living facility (not classified as medical, but has health services staff)
|
||||
- No Azure AD Connect / Entra Connect — AD and M365 are separate identity systems
|
||||
- No cloud backup configured — see `security/backup.md`
|
||||
183
clients/cascades-tucson/docs/cloud/caregiver-m365-p2-rollout.md
Normal file
183
clients/cascades-tucson/docs/cloud/caregiver-m365-p2-rollout.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Caregiver M365 + Entra P2 Rollout Plan (Cascades of Tucson)
|
||||
|
||||
**Status:** Documentation only — do NOT create accounts or assign licenses yet.
|
||||
**Created:** 2026-04-18 (Howard)
|
||||
**Source:** `C:\Users\howar\OneDrive\Documents\Caregiver Scheduled shifts and phone #.xlsx` (as of 2026-04-17)
|
||||
|
||||
## Goal / why this matters
|
||||
|
||||
Cascades is deploying 25 shared Android phones plus 9 kitchen iPads to get caregivers off shared workstations and into their own authenticated sessions (ALIS EHR, Outlook, Edge). For that to actually improve HIPAA posture, every caregiver needs:
|
||||
|
||||
1. Their own identity (AD user + M365 mailbox) so actions are attributable per-person rather than to a shared "Caregiver" login
|
||||
2. **Entra P2** so we can apply Conditional Access policies that restrict mobile email + ALIS access to:
|
||||
- Managed (Intune-enrolled) shared phones, AND
|
||||
- The Cascades physical network / trusted location (IP ranges or named location)
|
||||
3. Policy block on personal-device access to Exchange + ALIS (HIPAA §164.312 access control)
|
||||
|
||||
Today none of these caregivers exist in AD or M365 — they use shared workstation logins and don't have email at all. That is the gap this rollout closes.
|
||||
|
||||
**Also noted (explicit call-out to add to the proposal):** we did not previously frame the Business Premium proposal as "we're adding phones AND licenses to reach HIPAA compliance." The proposal currently lists 23 licensed users post-cleanup; with caregivers included it is closer to 62. The cost delta + HIPAA rationale should be surfaced in `docs/proposals/m365-premium-upgrade.md` before re-presenting to Meredith.
|
||||
|
||||
## Caregiver roster (39 people)
|
||||
|
||||
Location codes: **Tower** = assisted living tower, **MC** = Memory Care.
|
||||
Role flags: **CCG** = certified caregiver, **MedTech / MED TECH** = medication tech, **PRN** = as-needed/float, **NOC** = overnight.
|
||||
|
||||
### Tuesday–Saturday (14)
|
||||
|
||||
| # | Name | Proposed UPN | Shift | Location | Role | Phone |
|
||||
|---|------|--------------|-------|----------|------|-------|
|
||||
| 1 | Thelma Abainza | thelma.abainza@ | AM | Tower | Caregiver | 520-867-2579 |
|
||||
| 2 | Niel Castro | niel.castro@ | AM | Tower | MedTech / CCG | 520-697-4644 |
|
||||
| 3 | Espe Esperance | espe.esperance@ | PM | Tower | MedTech | 520-788-9558 |
|
||||
| 4 | Barbara Johnson | barbara.johnson@ | PM | Tower | Caregiver | 520-204-3449 |
|
||||
| 5 | Kasey Flores | kasey.flores@ | AM | MC | Caregiver | 520-250-1451 |
|
||||
| 6 | Richard Flores | richard.flores@ | AM | MC | Caregiver | 520-873-7727 |
|
||||
| 7 | Marie Kastner | marie.kastner@ | PM | MC | Caregiver | 714-576-9858 |
|
||||
| 8 | Bella Mendoza | bella.mendoza@ | PM | MC | Caregiver | 520-358-2000 |
|
||||
| 9 | Rosa Morales | rosa.morales@ | PM | MC | MedTech | 312-213-8780 |
|
||||
| 10 | Sandra Padilla | sandra.padilla@ | AM | Tower | MedTech / CCG | 520-585-3317 |
|
||||
| 11 | Polett Pinazavala | polett.pinazavala@ | AM | MC | MedTech | 520-449-5533 |
|
||||
| 12 | Whisper Reed | whisper.reed@ | Overnight | Tower | MedTech | 520-312-7575 |
|
||||
| 13 | Patricia Sandoval-Beck | patricia.sandoval-beck@ | AM | Tower | MedTech | 520-343-8093 |
|
||||
| 14 | Charity Sika | charity.sika@ | AM | MC | Caregiver | 623-251-8032 |
|
||||
| 15 | Ederick Yuzon | ederick.yuzon@ | PM | Tower | Caregiver | 520-603-8816 |
|
||||
|
||||
### Sunday–Thursday (10)
|
||||
|
||||
| # | Name | Proposed UPN | Shift | Location | Role | Phone |
|
||||
|---|------|--------------|-------|----------|------|-------|
|
||||
| 16 | Juan Andrade | juan.andrade@ | PM | MC | Caregiver | 520-528-4078 |
|
||||
| 17 | Jahmeka Clarke | jahmeka.clarke@ | PM | MC | MedTech | 520-649-7034 |
|
||||
| 18 | Karina Aziakpo | karina.aziakpo@ | Overnight | MC | MedTech / CCG | 520-392-6859 |
|
||||
| 19 | Jinnelle Dittbenner | jinnelle.dittbenner@ | PM | Tower | Caregiver | 520-499-9996 |
|
||||
| 20 | Christine Nyanzunda | christine.nyanzunda@ | AM (Sun/Mon only) | MC | MedTech | 520-304-4251 |
|
||||
| 21 | Agnes McFerren | agnes.mcferren@ | AM | Tower | Caregiver | 520-406-3063 |
|
||||
| 22 | Samuel Ramirez | samuel.ramirez@ | PM | Tower | Caregiver | 520-488-5798 |
|
||||
| 23 | Erica Sanchez | erica.sanchez@ | AM | MC | Caregiver | 520-528-3387 |
|
||||
| 24 | Katrina Wyzykowski | katrina.wyzykowski@ | AM | MC | MedTech | 520-347-1448 |
|
||||
| 25 | Corey Tate | corey.tate@ | NOC | Tower | Caregiver only (no MedTech) | 520-535-7821 |
|
||||
|
||||
### Friday–Monday / weekend (5)
|
||||
|
||||
| # | Name | Proposed UPN | Shift | Location | Role | Phone |
|
||||
|---|------|--------------|-------|----------|------|-------|
|
||||
| 26 | Ashli Atwood | ashli.atwood@ | Overnight | MC | MedTech / CCG | 715-200-1295 |
|
||||
| 27 | Cole Johnson | cole.johnson@ | PM | Tower | MedTech | 818-970-0890 |
|
||||
| 28 | Roseline Cooper | roseline.cooper@ | Overnight | MC | Caregiver | 520-278-6817 |
|
||||
| 29 | Monique Lopez | monique.lopez@ | Doubles (Fri & Sat) | Tower | Caregiver | 520-596-0969 |
|
||||
| 30 | Gloria Williford | gloria.williford@ | Doubles (Fri & Sat 5:45a–10p) | MC | MedTech | 928-551-1682 |
|
||||
|
||||
### Thursday–Monday (3)
|
||||
|
||||
| # | Name | Proposed UPN | Shift | Location | Role | Phone |
|
||||
|---|------|--------------|-------|----------|------|-------|
|
||||
| 31 | Sarah Carroll | sarah.carroll@ | PM | Tower | Caregiver | 520-409-2341 |
|
||||
| 32 | Luke Hogan | luke.hogan@ | AM | Tower | Caregiver | 520-312-0141 |
|
||||
| 33 | Gina Williams | gina.williams@ | AM | Tower | Caregiver | 520-612-5075 |
|
||||
|
||||
### Split / other patterns (3)
|
||||
|
||||
| # | Name | Proposed UPN | Shift | Location | Role | Phone |
|
||||
|---|------|--------------|-------|----------|------|-------|
|
||||
| 34 | Jen Higdon | jen.higdon@ | Mon/Wed/Fri AM | Tower | Caregiver | 520-730-3548 |
|
||||
| 35 | Mary Kariuki | mary.kariuki@ | Sat–Mon + Wed PM | Tower | Caregiver | 520-309-1247 |
|
||||
| 36 | CeCe Lassey | cece.lassey@ | Sun/Mon doubles + Tue PM | Tower | Caregiver | 520-248-5982 |
|
||||
|
||||
### Sunday & Monday only (1)
|
||||
|
||||
| # | Name | Proposed UPN | Shift | Location | Role | Phone |
|
||||
|---|------|--------------|-------|----------|------|-------|
|
||||
| 37 | Paty Doran | paty.doran@ | AM | Tower | MedTech / CCG | 520-591-7368 |
|
||||
|
||||
### PRN / float (2)
|
||||
|
||||
| # | Name | Proposed UPN | Shift | Location | Role | Phone |
|
||||
|---|------|--------------|-------|----------|------|-------|
|
||||
| 38 | Ezekiel Huerta | ezekiel.huerta@ | PRN | Tower | Caregiver | 520-591-6113 |
|
||||
| 39 | Maia Baker | maia.baker@ | PRN | MC | MedTech | TBD — not on shift list, only on Sheet2 |
|
||||
|
||||
All UPNs above use the `@cascadestucson.com` suffix (standard).
|
||||
|
||||
## Conflict / verify before creating
|
||||
|
||||
- **Christine Nyanzunda** already exists in AD as **Memory Care Admin Assistant** (`Christine.Nyanzunda`, susan.hicks@ department peer — see `docs/servers/active-directory.md` and existing M365 match in `docs/cloud/m365.md`). The caregiver list entry `Christine Nyanzunda-AM shift/MC MED TECH` is likely the same person picking up clinical shifts, not a second identity. **Do not create a second account.** Confirm with Shelby Trozzi / Meredith that her caregiver shifts should use the existing `christine.nyanzunda@` mailbox.
|
||||
- **Paty Doran** — spelling could be Patricia / Paty / Patti. Confirm with HR before creating.
|
||||
- **Polett Pinazavala** — unusual spelling, verify with HR.
|
||||
- **Patricia Sandoval-Beck** — hyphenated last name; SamAccountName may need to be `Patricia.SandovalBeck` if hyphens are disallowed in downstream tools (ALIS, MDM).
|
||||
- **Ederick Yuzon** — verify spelling.
|
||||
- **Maia Baker** — name on Sheet2 only, no shift/phone data. Confirm employment status with HR.
|
||||
|
||||
## Licensing plan (when ready — NOT now)
|
||||
|
||||
**Current licensing (per `docs/cloud/m365.md`):**
|
||||
- Business Standard: 34 purchased, all assigned (need to free via shared-mailbox conversion first)
|
||||
- Entra P2: 1 unassigned (was Sandra Fish)
|
||||
|
||||
**Target for caregiver rollout:**
|
||||
|
||||
| License | Who gets it | Qty | Rationale |
|
||||
|---|---|---|---|
|
||||
| M365 Business Premium (replaces Standard) | All 23 existing licensed staff + 38 net-new caregivers (Christine Nyanzunda already counted as existing staff) | **61** | Includes Intune Shared Device Mode + Defender + DLP + the P2-equivalent Conditional Access features — this is the SKU the proposal already describes |
|
||||
| Entra ID P2 (standalone, IF we stay on Business Standard instead) | Same 61 | 61 | Only needed if we do NOT upgrade to Business Premium. Premium already bundles the CA features we need; avoid double-paying |
|
||||
|
||||
**Recommended:** upgrade everyone to Business Premium, **don't** buy standalone P2. P2 is only listed here as the fallback if budget forces staying on Standard.
|
||||
|
||||
### Quick cost math (order-of-magnitude, double-check in proposal)
|
||||
|
||||
| Scenario | Licenses | Rate (monthly) | Monthly total |
|
||||
|---|---|---|---|
|
||||
| Today (actual) | 34 × Standard | $12.50 | $425 |
|
||||
| After shared-mailbox cleanup (no caregivers) | 23 × Premium | $22.00 | $506 |
|
||||
| After caregiver rollout (this doc) | 61 × Premium | $22.00 | **$1,342** |
|
||||
| Delta vs today | +$917/mo | | — |
|
||||
|
||||
That is a meaningful jump and needs to be in the proposal conversation with Meredith explicitly — it was missing from the 2026-04-14 version.
|
||||
|
||||
## Conditional Access policy plan (rough)
|
||||
|
||||
When licenses are in place and accounts exist:
|
||||
|
||||
1. **Named Location** in Entra = Cascades public IP(s) from pfSense WAN + VPN exit IP. Name it `CascadesTrustedLocation`.
|
||||
2. **Compliant Device** definition in Intune = corporate-enrolled Android (the 25 shared phones) + corporate-enrolled iPad (the 9 kitchen iPads) + domain-joined Windows PCs.
|
||||
3. **CA Policy: Caregivers — Mobile Email / ALIS access**
|
||||
- Assignment: Entra group `SG-Caregivers` (populated from AD group once accounts exist)
|
||||
- Cloud apps: Exchange Online, `ALIS` (once registered as Entra app), Outlook Mobile
|
||||
- Conditions: Device Platforms = Android, iOS; Locations = Any
|
||||
- Grant: Require compliant device **AND** require location `CascadesTrustedLocation` (combined grant, both required)
|
||||
- Block everything else (personal phones off-network → blocked)
|
||||
4. **CA Policy: Caregivers — Web/browser block off-network**
|
||||
- Same group + cloud apps
|
||||
- Platforms: browser (desktop)
|
||||
- Conditions: not in `CascadesTrustedLocation`
|
||||
- Grant: Block
|
||||
5. **Exclusion group** `SG-CA-BreakGlass` for Meredith + sysadmin so we can't lock ourselves out.
|
||||
|
||||
CA policies should be deployed in **Report-only** mode for at least 7 days, reviewed against Sign-in logs, then switched to On.
|
||||
|
||||
## AD placement (when accounts are created)
|
||||
|
||||
Put caregivers in the existing `OU=Departments,OU=...` department OUs:
|
||||
|
||||
- Tower/MC caregivers → `OU=Care-Assisted Living,OU=Departments` (or create `OU=Caregivers` sub-OU if we want finer GPO targeting)
|
||||
- MedTech-flagged staff → same OU; group membership (SG-MedTech) controls ALIS licensing tier
|
||||
- CCG-flagged staff → same OU; group membership (SG-CCG) controls higher-privilege ALIS rights if any
|
||||
|
||||
Group-policy impact: the `CSC - Folder Redirection (LE)` work done for Life Enrichment does NOT apply here. Care-Assisted Living GPO pattern needs to be cloned from the finalized LE GPO once that's proven on Susan Hicks' machine (DESKTOP-ROK7VNM).
|
||||
|
||||
## Open items / decisions needed from client
|
||||
|
||||
- [ ] Confirm Christine Nyanzunda is one person, not two (existing M365 account keeps working for caregiver shifts)
|
||||
- [ ] HR spelling confirmation on Paty Doran, Polett Pinazavala, Patricia Sandoval-Beck, Ederick Yuzon, Maia Baker
|
||||
- [ ] Will caregivers use ALIS on the shared phones (need ALIS accounts + Entra SSO) or only email?
|
||||
- [ ] Does Cascades want to purchase 39 additional Business Premium licenses up-front, or roll out in waves (e.g., MedTechs first, then CCGs, then Caregivers)?
|
||||
- [ ] Confirm pfSense WAN IP(s) are static enough to rely on in a CA Named Location policy
|
||||
- [ ] Timeline expectations — tying this to the phone deployment, the MDM rollout (7-phase plan in `docs/security/mdm.md`), and the Business Premium purchase
|
||||
|
||||
## Related docs
|
||||
|
||||
- Proposal: `docs/proposals/m365-premium-upgrade.md` — currently sized for 23 users; needs updating
|
||||
- MDM plan: `docs/security/mdm.md` — 25 phones + 9 iPads, ManageEngine; Intune Shared Device Mode is flagged as future
|
||||
- M365 current state: `docs/cloud/m365.md`
|
||||
- AD roster: `docs/servers/active-directory.md`
|
||||
- HIPAA program: `docs/security/hipaa.md`
|
||||
@@ -0,0 +1,97 @@
|
||||
# M365 Anti-Impersonation Protection — Cascades
|
||||
|
||||
**Status:** Documentation only — policy not yet configured. Requires Business Premium (Defender for Office 365 Plan 1) or equivalent Defender for O365 add-on; Business Standard alone does not include the anti-impersonation engine.
|
||||
**Trigger:** follow-up to Megan Hiatt's phishing email incident, 2026-04-17.
|
||||
**Last updated:** 2026-04-18 (Howard)
|
||||
|
||||
## What this covers
|
||||
|
||||
Microsoft 365 Defender anti-phishing impersonation protection has two lists that need to be curated per tenant:
|
||||
|
||||
1. **Trusted senders / domains** — partners we actually do business with. Adding them prevents legitimate mail from being caught by anti-impersonation rules (which flag lookalikes of these names/domains). This is NOT an allowlist that bypasses spam/malware scanning — it just tells the impersonation engine "yes, this one is the real one, anything that resembles it is suspect."
|
||||
2. **Protected users** — internal accounts that are high-value impersonation targets (executives, finance, anyone who can approve money or PHI disclosure). Inbound mail that mimics their display name from outside the tenant gets flagged.
|
||||
|
||||
For Cascades we're also protecting the **domain** `cascadestucson.com` itself so lookalike domains (e.g., `cascadestucsom.com`, `cascadestuscon.com`) get flagged as impersonation attempts.
|
||||
|
||||
## Currently configured (per Howard's 2026-04-17 email)
|
||||
|
||||
### Protected domains
|
||||
- cascadestucson.com
|
||||
- azcomputerguru.com
|
||||
|
||||
### Protected users
|
||||
- Megan Hiatt
|
||||
- John Trozzi
|
||||
- Crystal Rodriguez
|
||||
- Meredith Kuhn
|
||||
- Tamra Matthews
|
||||
- "accounting" (presumably the accounting@cascadestucson.com shared mailbox / anything with that display name)
|
||||
|
||||
**Verify on next portal visit:** double-check the exact protected-users list in Defender → Policies → Anti-phishing → Impersonation. Howard's email lists "Megan, John, crystal, Meredith, accounting, crystal and tamra" — the duplicate "crystal" is probably a typo.
|
||||
|
||||
## Trusted partners to add (from Megan Hiatt, 2026-04-17)
|
||||
|
||||
Megan's "top domains I regularly do business with" reply. Preferred configuration: add the **domain** where we want any sender on that domain trusted; add the **specific email** where we only want that one person trusted.
|
||||
|
||||
| Add as | Value | Business purpose |
|
||||
|---|---|---|
|
||||
| User | Matt Hermes — `Matt.Hermes@kold.com` | KOLD-TV — local media |
|
||||
| User | SoAPRA — `soapra.npra@gmail.com` | State senior-living industry assoc (individual Gmail — user, not domain) |
|
||||
| User | Lovely Laurence Garcia — `partnersuccess@caring.com` | Caring.com partner success |
|
||||
| User | Caring Leads Team — `leadsteam@caring.com` | Caring.com lead routing |
|
||||
| User | Assisted Living Locators (N. Tucson) — `sheril@assistedlivinglocators.com` | Senior-living placement agency |
|
||||
| User | Angel Ramirez — `angel@placitacare.com` | PlacitaCare — referral partner |
|
||||
| User | Anne Connell — `AnneC@cascadeliving.com` | Cascade Living (parent / affiliated property — verify relationship) |
|
||||
| User | A Place for Mom AR — `ar@aplaceformom.com` | APFM accounts receivable — referral fees |
|
||||
| User | `BillingWO@gray.tv` | Gray Television — ad billing |
|
||||
| User | 8x8 Support — `noreply@8x8.com` | VoIP vendor no-reply (may not need impersonation protection since it's already an automated sender — include per Megan) |
|
||||
| User | C.J. Duque — `cjduque@trucraftdesign.com` | Tru Craft Design — vendor |
|
||||
| User | `compressionprinting@gmail.com` | Compression Printing — vendor |
|
||||
| User | Lisa Burns — `lisab4421@gmail.com` | Personal/individual partner contact |
|
||||
| User | `jbuenafe-leads@caring.com` | Caring.com lead contact (one of many) |
|
||||
|
||||
**Domain-level adds to consider (Howard to decide):** because Cascades gets mail from many different addresses at Caring.com and aplaceformom.com, adding `caring.com` and `aplaceformom.com` as trusted **domains** instead of individual addresses saves constant curation. Megan explicitly called out that Caring.com contacts "are changing all the time." Adding the domain once covers them all. Only risk: if a domain itself is spoofed, any sender claiming to be from it will be trusted — but the anti-impersonation engine is specifically about lookalike sender domains, so this is the correct use case.
|
||||
|
||||
Recommended domain-level trusted partners:
|
||||
- `caring.com` — multiple contacts, constantly rotating
|
||||
- `aplaceformom.com` — same pattern (APFM has many reps)
|
||||
- `kold.com` — news media
|
||||
- `assistedlivinglocators.com` — agency with multiple reps
|
||||
- `cascadeliving.com` — **confirm this is a legitimate affiliated property before trusting the whole domain**
|
||||
- `gray.tv` — billing automation from multiple accounts
|
||||
|
||||
Individual addresses to keep as **user-level** entries (not domain):
|
||||
- The two gmail.com partners (Lisa Burns, Compression Printing) — cannot trust `gmail.com` as a domain, obviously
|
||||
- `soapra.npra@gmail.com` — same
|
||||
- `angel@placitacare.com` — small vendor, domain-level overkill
|
||||
- `cjduque@trucraftdesign.com` — same
|
||||
- `noreply@8x8.com` — utility address, not a lookalike impersonation target anyway; Megan may have listed it for general allowlisting rather than anti-impersonation — revisit
|
||||
|
||||
## Outstanding / awaiting input
|
||||
|
||||
- **John Trozzi** (per 2026-04-17 email, bottom of thread): "I will gather this information for you tomorrow." → follow up for his partners list.
|
||||
- **Meredith Kuhn** — did not respond yet on impersonation list; she's the one most likely to be impersonated in a wire-fraud attack as Executive Director. Follow up.
|
||||
- **Ashley Jensen** (Assistant ED, Accounting) — same; likely overlaps with Meredith's list heavily.
|
||||
- **Cascade Living affiliation** — Anne Connell at `cascadeliving.com`. Verify with Meredith whether Cascades of Tucson is owned/affiliated with Cascade Living properties before trusting the domain wholesale. If affiliated, add as trusted domain; if arm's-length, keep as user-level.
|
||||
|
||||
## Implementation notes (when ready)
|
||||
|
||||
1. Purchase Business Premium or Defender for O365 P1 add-on (impersonation engine lives in Defender, not EOP baseline)
|
||||
2. Defender portal → Email & collaboration → Policies & rules → Threat policies → Anti-phishing → edit the Standard preset or create `CSC - Anti-Phishing Standard`
|
||||
3. Impersonation tab:
|
||||
- Add protected users (Meredith, Megan, John, Crystal, Tamra, Ashley — anyone who can approve money/PHI)
|
||||
- Add protected domains: `cascadestucson.com`, `azcomputerguru.com`, and any affiliated properties verified above
|
||||
- Add trusted senders/domains (sections above)
|
||||
- Action when user is impersonated: **Quarantine message** (not just "move to Junk" — attackers test Junk-only delivery)
|
||||
- Mailbox intelligence: **On**, with "impersonated users" action = Quarantine
|
||||
4. Spoof intelligence: On, with action Quarantine
|
||||
5. Turn on Safety Tips
|
||||
6. Review quarantine daily for first 2 weeks — tune the trusted list based on false positives
|
||||
7. Document in this file any legitimate senders we have to add mid-operation so the list stays authoritative
|
||||
|
||||
## Related docs
|
||||
|
||||
- `docs/cloud/m365.md` — overall M365 state
|
||||
- `docs/cloud/p2-staff-candidates.md` — staff P2 rollout (overlapping stakeholders)
|
||||
- `docs/cloud/caregiver-m365-p2-rollout.md` — phone-side rollout (different user population)
|
||||
- `docs/security/hipaa.md` — HIPAA program this feeds into
|
||||
295
clients/cascades-tucson/docs/cloud/m365.md
Normal file
295
clients/cascades-tucson/docs/cloud/m365.md
Normal file
@@ -0,0 +1,295 @@
|
||||
# Microsoft 365
|
||||
|
||||
## Tenant Info
|
||||
- Tenant Name: cascadestucson.com
|
||||
- Tenant ID: 207fa277-e9d8-4eb7-ada1-1064d2221498
|
||||
- Primary Domain: cascadestucson.com
|
||||
- onmicrosoft Domain: NETORGFT4257522.onmicrosoft.com
|
||||
- Admin Portal URL: https://admin.microsoft.com
|
||||
- Global Admin: sysadmin@cascadestucson.com (Howard Enos, MSP)
|
||||
- Former Admin: admin@NETORGFT4257522.onmicrosoft.com (Sandra Fish — previous director, removed 2026-04-14: global admin revoked, sign-in blocked, P2 license removed)
|
||||
- DirSync / Entra Connect: **Not configured** (all accounts cloud-only) — **PLANNED: Install Entra Connect for SSO**
|
||||
- HIPAA BAA: **Not signed** — required since email may contain PHI
|
||||
- MFA: **Not enabled** — Security Defaults not configured
|
||||
|
||||
## Licensing
|
||||
|
||||
| License Type | Total | Assigned | Available |
|
||||
|---|---|---|---|
|
||||
| Microsoft 365 Business Standard | 34 | 34 | 0 |
|
||||
| Microsoft Entra ID P2 | 1 | 0 | 1 (unassigned — was Sandra Fish, available for testing) |
|
||||
| Microsoft Power Automate Free | 10000 | 2 | 9998 |
|
||||
| Microsoft Stream Trial | 1000000 | 0 | 1000000 |
|
||||
| Exchange Online Essentials | — | 4 | — |
|
||||
|
||||
**Note:** Business Standard is fully allocated (34/34, 0 available). Any new hires require purchasing additional licenses.
|
||||
|
||||
### Planned expansion — caregiver rollout (not yet purchased)
|
||||
|
||||
Separate from the current 34 users, there are **~39 caregivers / med techs / CCGs** with no current AD or M365 account who need identities + Conditional Access in order for the shared-phone + HIPAA story to actually work. Full roster, proposed UPNs, license math, and CA policy design are in `docs/cloud/caregiver-m365-p2-rollout.md`. Rough target: 61 total Business Premium licenses (23 existing staff post-cleanup + 38 net-new caregivers; Christine Nyanzunda overlaps and stays at one account). **Do not create any of these accounts yet** — documentation + proposal update first.
|
||||
|
||||
### Staff-side P2 / anti-impersonation tracking
|
||||
|
||||
These are in-flight and feed the same Business Premium purchase decision:
|
||||
- `docs/cloud/p2-staff-candidates.md` — office staff who need P2 for PHI-in-email or home-access scenarios (Crystal confirmed Megan/Crystal/Tamra; John Trozzi gathering the rest)
|
||||
- `docs/cloud/m365-impersonation-protection.md` — Defender anti-impersonation trusted partners + protected users (Megan's partner list captured; awaiting John's additions)
|
||||
|
||||
## AD ↔ M365 Account Mapping
|
||||
|
||||
### Matched Accounts (AD user → M365 mailbox)
|
||||
|
||||
| AD SamAccountName | M365 UPN | License | Notes |
|
||||
|---|---|---|---|
|
||||
| howard | dax.howard@cascadestucson.com | Business Standard | Alias: cara.lespron@ (reused mailbox from former employee) |
|
||||
| sysadmin | sysadmin@cascadestucson.com | Power Automate Free | Display: "Computer Guru Support" — no mailbox license |
|
||||
| Meredith.Kuhn | meredith.kuhn@cascadestucson.com | Business Standard | |
|
||||
| John.Trozzi | john.trozzi@cascadestucson.com | Business Standard | |
|
||||
| Lupe.Sanchez | lupe.sanchez@cascadestucson.com | Business Standard | |
|
||||
| Megan.Hiatt | megan.hiatt@cascadestucson.com | Business Standard | |
|
||||
| Crystal.Rodriguez | crystal.rodriguez@cascadestucson.com | Business Standard | Alias: crystal.suszek@ |
|
||||
| Tamra.Johnson | tamra.matthews@cascadestucson.com | Business Standard | **Rename AD to Tamra.Matthews** — M365 already correct. Alias: tamra.johnson@ still works |
|
||||
| Lois.Lane | lois.lane@cascadestucson.com | Business Standard | |
|
||||
| Christina.DuPras | christina.dupras@cascadestucson.com | Business Standard | |
|
||||
| Christine.Nyanzunda | christine.nyanzunda@cascadestucson.com | Business Standard | M365 last name: "Nyanzuda" (typo — AD has Nyanzunda) |
|
||||
| Susan.Hicks | susan.hicks@cascadestucson.com | Business Standard | |
|
||||
| Ashley.Jensen | ashley.jensen@cascadestucson.com | Business Standard + Power Automate Free | Alias: ashley.jenson@ |
|
||||
| Veronica.Feller | veronica.feller@cascadestucson.com | Business Standard | |
|
||||
| JD.Martin | jd.martin@cascadestucson.com | Business Standard | |
|
||||
| alyssa.brooks | alyssa.brooks@cascadestucson.com | Business Standard | |
|
||||
| Matt.Brooks | matthew.brooks@cascadestucson.com | Business Standard | AD: Matt, M365: Matthew |
|
||||
| Ramon.Castaneda | ramon.castaneda@cascadestucson.com | Business Standard | Aliases: ramon.castanada@, ramon.casteneda@ (typos kept as aliases) |
|
||||
| Sharon.Edwards | sharon.edwards@cascadestucson.com | Business Standard | |
|
||||
| britney.thompson | Britney.Thompson@cascadestucson.com | Business Standard + Exchange Online Essentials | |
|
||||
| ann.dery | ann.dery@cascadestucson.com | Business Standard | |
|
||||
| strozzi (Shelby Trozzi) | Shelby.Trozzi@cascadestucson.com | Business Standard + Exchange Online Essentials | AD username doesn't match M365 format |
|
||||
| karen.rossini | karen.rossini@cascadestucson.com | Business Standard | |
|
||||
| lauren.hasselman | lauren.hasselman@cascadestucson.com | Business Standard | Created 2026-02-26 (recent hire, replaced Jeff Bristol) |
|
||||
| Allison.Reibschied | Allison.Reibschied@cascadestucson.com | Business Standard | Accounting Assistant (new hire 2026-03) |
|
||||
|
||||
### AD Accounts with NO M365 Match
|
||||
|
||||
| AD SamAccountName | Type | Action Needed |
|
||||
|---|---|---|
|
||||
| Administrator | Built-in | None needed |
|
||||
| localadmin | Admin | None needed |
|
||||
| Sebastian.Leon | User | Front Desk/Courtesy Patrol — needs M365 account if they use email |
|
||||
| Michelle.Shestko | User | MC Front Desk — keep as Shestko. Needs M365 account if they use email |
|
||||
| Alyssa.Shestko (now Alyssa Brooks) | User | **Rename to Alyssa.Brooks in AD.** This is the real account. M365 already alyssa.brooks@. Duplicate lowercase `alyssa.brooks` in CN=Users to be deleted. |
|
||||
| Guadalupe.Sanchez | User | Housekeeping — already has M365 as lupe.sanchez@cascadestucson.com |
|
||||
| Sheldon.Gardfrey | User | Front Desk/Courtesy Patrol — needs M365 if they use email |
|
||||
| Cathy.Kingston | User | Front Desk/Courtesy Patrol — needs M365 if they use email |
|
||||
| Shontiel.Nunn | User | Transferring soon — keep for now |
|
||||
| Ray.Rai | User | Front Desk/Courtesy Patrol — needs M365 if they use email |
|
||||
| Richard.Adams | User | Transportation — needs M365 if they use email |
|
||||
| Julian.Crim | User | Transportation — needs M365 if they use email |
|
||||
| Christopher.Holik | User | Transportation — needs M365 if they use email |
|
||||
| QBDataServiceUser34 | Service | None needed |
|
||||
| Culinary | Shared/Generic | None needed (AD shared account) |
|
||||
| Receptionist | Shared/Generic | Maps to frontdesk@cascadestucson.com? |
|
||||
| saleshare | Shared/Generic | None needed |
|
||||
| directoryshare | Shared/Generic | None needed |
|
||||
|
||||
### M365 Accounts with NO AD Match
|
||||
|
||||
#### Real users (need AD accounts created or are new hires)
|
||||
|
||||
| M365 Display Name | UPN | License | Notes |
|
||||
|---|---|---|---|
|
||||
| Kristiana Dowse | kristiana.dowse@cascadestucson.com | Business Standard | **DELETE** — HR confirmed not current employee. Remove license + delete account |
|
||||
| nick pavloff | nick.pavloff@cascadestucson.com | Business Standard | Created 2026-03-07 — **new hire**, needs AD account |
|
||||
|
||||
#### Role-Based Accounts — Convert to Shared Mailboxes (saves ~$125/mo)
|
||||
|
||||
All of these are currently licensed user accounts. Convert to **shared mailboxes** (free) and remove licenses. Then assign members from AD-synced accounts.
|
||||
|
||||
| M365 Display Name | UPN | Current License | Action | Members (after conversion) |
|
||||
|---|---|---|---|---|
|
||||
| Accounting Dept. | accounting@cascadestucson.com | Business Standard | Convert to shared | Ashley.Jensen, lauren.hasselman |
|
||||
| Accounting Assistant | accountingassistant@cascadestucson.com | Business Standard | Convert to shared | Allison.Reibschied |
|
||||
| Bookkeeping Office | boadmin@cascadestucson.com | Business Standard | Convert to shared | TBD |
|
||||
| Front Desk | frontdesk@cascadestucson.com | Business Standard | Convert to shared | Cathy.Kingston, Shontiel.Nunn, Kyla.QuickTiffany, Sebastian.Leon, Sheldon.Gardfrey, Ray.Rai |
|
||||
| Human Resources | hr@cascadestucson.com | Business Standard | Convert to shared | Meredith.Kuhn |
|
||||
| MemCare Receptionist | memcarereceptionist@cascadestucson.com | Business Standard | Convert to shared | Michelle.Shestko, Matt.Brooks |
|
||||
| Security Cascades | security@cascadestucson.com | Business Standard | Convert to shared | TBD |
|
||||
| Training | Training@cascadestucson.com | Business Standard | Convert to shared | TBD |
|
||||
| Nurse | nurse@cascadestucson.com | Exchange Online Essentials | Convert to shared | Lois.Lane, Karen.Rossini, britney.thompson |
|
||||
| medtech | medtech@cascadestucson.com | Exchange Online Essentials | Convert to shared | TBD |
|
||||
| transportation | transportation@cascadestucson.com | Exchange Online Essentials | Convert to shared | Richard.Adams, Julian.Crim, Christopher.Holick |
|
||||
| AppleID | Kitchenipad@cascadestucson.com | Unlicensed | Keep as-is | Device account. Alias: ipad@ |
|
||||
|
||||
#### Courtesy Patrol Shared Mailbox (NEW)
|
||||
- Create: **courtesypatrol@cascadestucson.com** as shared mailbox
|
||||
- Members: Sebastian.Leon, Sheldon.Gardfrey
|
||||
|
||||
### License Plan After Cleanup
|
||||
|
||||
#### Full Business Standard License (own mailbox + Office apps)
|
||||
Staff with `first.last@cascadestucson.com` personal mailboxes:
|
||||
| Employee | UPN |
|
||||
|----------|-----|
|
||||
| Howard Dax | dax.howard@ |
|
||||
| Meredith Kuhn | meredith.kuhn@ |
|
||||
| John Trozzi | john.trozzi@ |
|
||||
| Megan Hiatt | megan.hiatt@ |
|
||||
| Crystal Rodriguez | crystal.rodriguez@ |
|
||||
| Tamra Matthews | tamra.matthews@ |
|
||||
| Lois Lane | lois.lane@ |
|
||||
| Christina DuPras | christina.dupras@ |
|
||||
| Christine Nyanzunda | christine.nyanzunda@ |
|
||||
| Susan Hicks | susan.hicks@ |
|
||||
| Ashley Jensen | ashley.jensen@ |
|
||||
| Veronica Feller | veronica.feller@ |
|
||||
| JD Martin | jd.martin@ |
|
||||
| Alyssa Brooks | alyssa.brooks@ |
|
||||
| Matt Brooks | matthew.brooks@ |
|
||||
| Ramon Castaneda | ramon.castaneda@ |
|
||||
| Sharon Edwards | sharon.edwards@ |
|
||||
| Britney Thompson | britney.thompson@ |
|
||||
| Shelby Trozzi | shelby.trozzi@ |
|
||||
| Karen Rossini | karen.rossini@ |
|
||||
| Guadalupe Sanchez | lupe.sanchez@ |
|
||||
| Lauren Hasselman | lauren.hasselman@ |
|
||||
| Allison Reibschied | allison.reibschied@ |
|
||||
**Total: 23 licenses**
|
||||
|
||||
#### No License — Shared Mailbox Access Only (browser via SSO)
|
||||
AD account + Entra sync, no M365 license. Access shared mailboxes via outlook.office.com.
|
||||
| Employee | Position | Shared Mailbox Access |
|
||||
|----------|----------|----------------------|
|
||||
| Sebastian Leon | Courtesy Patrol | Frontdesk@, Courtesypatrol@ |
|
||||
| Sheldon Gardfrey | Courtesy Patrol | Frontdesk@, Courtesypatrol@ |
|
||||
| Cathy Kingston | Receptionist | Frontdesk@ |
|
||||
| Shontiel Nunn | Receptionist | Frontdesk@ |
|
||||
| Kyla Quick Tiffany | Receptionist | Frontdesk@ |
|
||||
| Ray Rai | Courtesy Patrol | Frontdesk@ |
|
||||
| Richard Adams | Driver | Transportation@ |
|
||||
| Julian Crim | Driver | Transportation@ |
|
||||
| Christopher Holick | Driver | Transportation@ |
|
||||
| Michelle Shestko | MC Receptionist | Memcarereceptionist@ |
|
||||
**Total: 10 users, 0 licenses**
|
||||
|
||||
#### License Savings
|
||||
- Current: 34 Business Standard (all allocated)
|
||||
- After cleanup: 23 Business Standard needed
|
||||
- **11 licenses freed** (~$137.50/month saved)
|
||||
|
||||
#### External guest accounts
|
||||
|
||||
| Display Name | Source | Notes |
|
||||
|---|---|---|
|
||||
| a.r.jensen018 | a.r.jensen018@gmail.com | Ashley Jensen's personal? |
|
||||
| Debora Morris | deboram@teepasnow.com | External partner |
|
||||
| duprasc2002 | duprasc2002@yahoo.com | Christina DuPras personal? Created 2026-03-04 |
|
||||
| howaed | howaed@azcomputerguru.com | **Typo** of howard — delete |
|
||||
| howard | howard@azcomputerguru.com | Howard (MSP) external account |
|
||||
| karenrossini7 | karenrossini7@gmail.com | Karen Rossini's personal? |
|
||||
|
||||
#### Blocked / former employee accounts in M365
|
||||
|
||||
| Display Name | UPN | Sign-in Blocked | Notes |
|
||||
|---|---|---|---|
|
||||
| Jeff Bristol | jeff.bristol@cascadestucson.com | Yes | Former employee — unlicensed, shared mailbox exists |
|
||||
| Nela Durut-Azizi | nela.durut-azizi@cascadestucson.com | Yes | Former employee — unlicensed, shared mailbox exists |
|
||||
| Stephanie Devin | Stephanie.Devin@cascadestucson.com | Yes | Former? Unlicensed, blocked |
|
||||
|
||||
#### Tenant admin
|
||||
|
||||
| Display Name | UPN | License | Notes |
|
||||
|---|---|---|---|
|
||||
| cascadestucson.com (Sandra Fish) | admin@NETORGFT4257522.onmicrosoft.com | **Unlicensed** (P2 removed) | **BLOCKED** — Former director. Global admin revoked, sign-in blocked 2026-04-14. Delete when ready. |
|
||||
|
||||
## Shared Mailboxes
|
||||
|
||||
| Name | Email | Notes |
|
||||
|---|---|---|
|
||||
| Anna Pitzlin | anna.pitzlin@cascadestucson.com | **Former employee** — was forwarded to Meredith, HR says DELETE |
|
||||
| Fax Cascades | fax@cascadestucson.com | Fax-to-email service |
|
||||
| Jeff Bristol | jeff.bristol@cascadestucson.com | **Former employee** — sign-in blocked, keep for mail forwarding? |
|
||||
| Nela Durut-Azizi | nela.durut-azizi@cascadestucson.com | **Former employee** — was forwarded to Meredith, HR says DELETE |
|
||||
|
||||
## Exchange Online
|
||||
- Mail Domain(s): cascadestucson.com
|
||||
- MX Record Points To: TBD (check DNS)
|
||||
- SPF Record: TBD
|
||||
- DKIM Enabled: TBD
|
||||
- DMARC Policy: TBD
|
||||
- Distribution Groups: TBD (6 groups shown in tenant summary)
|
||||
- Mail Flow Rules: TBD
|
||||
|
||||
## Entra ID (Azure AD)
|
||||
- Hybrid Joined: **No** — DirSync not enabled on any account — **PLANNED: Entra Connect install on CS-SERVER**
|
||||
- Azure AD Connect Server: None (planned: CS-SERVER)
|
||||
- MFA Enforced: TBD
|
||||
- Conditional Access Policies: TBD
|
||||
- Total Users: 51 (24 licensed individual, 12 generic/role, 6 external guests, 4 blocked/former, 1 admin, 4 shared mailboxes)
|
||||
- Total Devices: 88
|
||||
|
||||
## Entra Connect — SSO Setup Plan
|
||||
|
||||
### What It Does
|
||||
Syncs AD accounts to M365/Entra ID. Users log into Windows with their AD account and Office/Edge/Outlook auto-sign-in with their M365 identity. Single sign-on, one password.
|
||||
|
||||
### Prerequisites (MUST complete before install)
|
||||
1. **AD account cleanup** — all the renames, deletions, and duplicate fixes MUST be done first. Entra Connect syncs what's in AD, so AD must be clean.
|
||||
- [ ] Rename Tamra.Johnson → Tamra.Matthews
|
||||
- [ ] Rename Alyssa.Shestko → Alyssa.Brooks + delete lowercase duplicate `alyssa.brooks`
|
||||
- [ ] Rename strozzi → Shelby.Trozzi (match M365 UPN)
|
||||
- [ ] Fix Christopher.Holik → Christopher.Holick (HR spelling)
|
||||
- [ ] Create account for Kyla Quick Tiffany (Resident Services Receptionist)
|
||||
- [ ] Delete confirmed former employees (Anna.Pitzlin, Nela.Durut-Azizi, Jodi.Ramstack, Monica.Ramirez)
|
||||
- [ ] Disable/delete non-current accounts (Haris.Durut, Nuria.Diaz, Cathy.Reece, Kelly.Wallace, Isabella.Islas, ann.dery, alyssa.brooks lowercase)
|
||||
- [ ] Fix Matt.Brooks vs matthew.brooks@ UPN mismatch
|
||||
2. **UPN suffix** — Add `cascadestucson.com` as UPN suffix in AD so AD usernames match M365 emails
|
||||
3. **M365 role-based accounts** — Convert to shared mailboxes BEFORE sync to avoid sync conflicts
|
||||
4. **Kristiana Dowse** — Delete from M365 before sync
|
||||
5. **Verify CS-SERVER meets requirements** — Server 2016+, .NET 4.7.2+, SQL Express (installs with Entra Connect)
|
||||
|
||||
### Install Steps
|
||||
1. Add UPN suffix `cascadestucson.com` to AD (AD Domains and Trusts)
|
||||
2. Update all synced users' UPN to `firstname.lastname@cascadestucson.com`
|
||||
3. Download Entra Connect from Entra admin center
|
||||
4. Install on CS-SERVER
|
||||
5. Choose **Password Hash Sync** (simplest, most reliable)
|
||||
6. Scope sync to `OU=Departments` only (exclude service accounts, shared accounts, computers)
|
||||
7. Enable **Seamless SSO**
|
||||
8. Test with one user before full sync
|
||||
|
||||
### What Gets Synced
|
||||
- All user accounts in OU=Departments → Entra ID
|
||||
- Passwords hash-synced (user keeps same password for AD + M365)
|
||||
- NOT synced: computer accounts, service accounts, shared/generic accounts (Culinary, Receptionist, saleshare, directoryshare)
|
||||
- **All synced users get Entra ID accounts** but NOT all get licenses
|
||||
- Licensed users (23): personal mailbox + Office apps
|
||||
- Unlicensed users (10): SSO sign-in to shared mailboxes via browser only — no Office install, no personal mailbox
|
||||
|
||||
### What Changes for Users
|
||||
- Log into Windows → Office, Outlook, Edge, OneDrive auto-sign-in
|
||||
- One password for everything (change in AD, M365 follows)
|
||||
- MFA can be enforced via Entra Conditional Access after sync
|
||||
|
||||
### Risks
|
||||
- If AD is dirty (duplicates, mismatches), sync will create duplicate M365 accounts or fail
|
||||
- Shared/generic accounts (Culinary, Receptionist) should NOT sync — exclude from scope
|
||||
- Must coordinate: once sync is on, AD becomes the source of truth for identity
|
||||
|
||||
## Issues Found
|
||||
|
||||
1. **0 licenses available** — Business Standard is 34/34. Cannot add new users without purchasing more.
|
||||
2. **Tamra Johnson → Matthews name mismatch** — M365 updated to married name, AD still says Johnson. Update AD to match.
|
||||
3. **13 AD users have no M365 account** — May not need email (hourly staff?) but verify onsite.
|
||||
4. **12 generic/role-based M365 accounts eating licenses** — accounting@, frontdesk@, hr@, etc. each consume a Business Standard license ($12.50/mo). Should convert to shared mailboxes (free) if nobody logs into them directly.
|
||||
5. **"howaed" external guest** — Typo duplicate of howard. Delete.
|
||||
6. **3 former employee shared mailboxes** — Anna Pitzlin, Jeff Bristol, Nela Durut-Azizi. Decide: keep for mail history, forward, or delete.
|
||||
7. **Sandra Fish is global admin** — Previous owner/manager. Verify she should still have admin access.
|
||||
8. **cara.lespron@ alias on Howard's mailbox** — Former employee's mailbox was repurposed. Remove alias if no longer needed.
|
||||
9. **Kristiana Dowse** — Licensed in M365 but not in AD. Verify: current employee or former?
|
||||
10. **nick pavloff** — Created 2026-03-07 (yesterday). New hire — needs AD account.
|
||||
11. **sysadmin has no mailbox license** — Only Power Automate Free. May need Exchange if used for email.
|
||||
12. **No Microsoft BAA signed** — M365 email may contain PHI (resident data). HIPAA §164.308(b)(1) requires a Business Associate Agreement with Microsoft. Sign via M365 Admin Center → Settings → Org Settings → Security & Privacy → HIPAA BAA.
|
||||
13. **No MFA enabled** — No Security Defaults or Conditional Access configured. HIPAA §164.312(d) requires person authentication. Enable Security Defaults at minimum (free).
|
||||
|
||||
## Notes
|
||||
|
||||
- Previous MSP/admin created many role-based accounts as regular licensed users instead of shared mailboxes. This wastes licenses.
|
||||
- No Entra Connect / hybrid join — AD and M365 are completely separate identity systems. Users have different passwords for each.
|
||||
- Shared workstation plan (GPO 6) needs: reception shared mailbox created, tenant domain is cascadestucson.com.
|
||||
89
clients/cascades-tucson/docs/cloud/p2-staff-candidates.md
Normal file
89
clients/cascades-tucson/docs/cloud/p2-staff-candidates.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Staff Entra P2 Candidates — Cascades
|
||||
|
||||
**Status:** Documentation only — no license purchase or policy activation yet. Awaiting full list from John Trozzi.
|
||||
**Last updated:** 2026-04-18 (Howard)
|
||||
**Related (different population):** `docs/cloud/caregiver-m365-p2-rollout.md` — caregiver phone rollout.
|
||||
|
||||
## Why this list is separate
|
||||
|
||||
Two different problems both use P2 features, and conflating them makes the license math fuzzy:
|
||||
|
||||
- **Caregiver rollout** (covered elsewhere): ~39 hourly staff, shared Android phones, goal is location-locked mobile access during shifts.
|
||||
- **This list** — office staff whose risk is:
|
||||
- Receives / sends PHI (new resident intake forms, doctor-supplied medical info)
|
||||
- Works from home or checks email on a personal phone, which is where we need either Conditional Access compliance enforcement or just a targeted location restriction
|
||||
- Or — should be restricted to in-building sign-in only
|
||||
|
||||
The Conditional Access policies will likely differ between the two groups (office staff need "work from home or from trusted device with compliance", caregivers need strict "on-prem network + managed shared phone only"), so tracking them separately keeps the policy design clean.
|
||||
|
||||
## Criteria (from Howard → leadership email, 2026-04-16)
|
||||
|
||||
A staff member needs P2 if they match one or more:
|
||||
1. Signs in on a phone or tablet at Cascades (skip-MFA-in-building story)
|
||||
2. Should only sign in from the building (enforce location restriction)
|
||||
3. Handles sensitive / medical information via email (PHI — need to enforce encryption + DLP policies that P2-tier features back)
|
||||
|
||||
## Candidates confirmed so far
|
||||
|
||||
### From Crystal Rodriguez (2026-04-16 reply)
|
||||
|
||||
| Name | Role | Reason P2 is needed | Notes |
|
||||
|---|---|---|---|
|
||||
| Megan Hiatt | Sales Director | Handles new-resident intake forms (PHI from doctors); works from home; email on personal cell | Already a protected user for anti-impersonation |
|
||||
| Crystal Rodriguez | Sales Associate | Same as Megan — intake forms, home + cell access | Already a protected user |
|
||||
| Tamra Matthews | Move-In Coordinator | Same — intake forms | **Leaving in June 2026** — license can be re-harvested on exit. Value of buying P2 for ~2 months is a call for Meredith (short-term HIPAA coverage vs. one-off cost). |
|
||||
|
||||
### Awaiting from John Trozzi
|
||||
|
||||
Per his 2026-04-17 email: "I will gather this information for you tomorrow." Expected additions likely include:
|
||||
- Meredith Kuhn (Executive Director — CEO-equivalent, highest impersonation / PHI risk)
|
||||
- Ashley Jensen (Assistant Executive Director)
|
||||
- John Trozzi himself (Facilities/Maintenance Director — judgment call on PHI exposure)
|
||||
- Lois Lane (Health Services Director — clinical data)
|
||||
- Karen Rossini (Health Services Manager — clinical data)
|
||||
- Britney Thompson (Memory Care Nurse — clinical data)
|
||||
- Shelby Trozzi (Memory Care Director — clinical data)
|
||||
- Christina DuPras (Resident Services Director)
|
||||
- Christine Nyanzunda (Memory Care Admin Assistant)
|
||||
- Susan Hicks (Life Enrichment Director — activity records may include PHI-adjacent data)
|
||||
- Sharon Edwards (Life Enrichment Assistant)
|
||||
|
||||
Don't presume — wait for John's actual reply before buying licenses.
|
||||
|
||||
## Decision still open (from Howard's 2026-04-16 email to leadership)
|
||||
|
||||
> "Do you want all staff restricted to signing in only from the building, or just certain roles/users (like front desk, kitchen, clinical)?"
|
||||
|
||||
No answer yet. This decision directly changes the license count and the CA policy design:
|
||||
- If **all staff restricted to building-only** → every AD-synced user needs P2 and a matching CA policy. Larger spend.
|
||||
- If **only some restricted** → P2 only for those users; cheaper, but requires ongoing judgment on who gets which policy.
|
||||
|
||||
## Intersection with other rollouts
|
||||
|
||||
- **Anti-impersonation protection** (`docs/cloud/m365-impersonation-protection.md`) — same top-tier users are the protected users there. Keep the lists in sync.
|
||||
- **Business Premium upgrade** (`docs/proposals/m365-premium-upgrade.md`) — Business Premium bundles P2-equivalent CA features, so if we go Premium tenant-wide, standalone P2 purchases go away. Default recommendation: **bundle everything into Business Premium**, only buy standalone P2 if budget forces staying on Business Standard for some users.
|
||||
- **Caregiver rollout** (`docs/cloud/caregiver-m365-p2-rollout.md`) — ~39 additional licenses. Combined target ~61 Premium licenses for the whole org.
|
||||
|
||||
## Rough license math (staff side only)
|
||||
|
||||
| Scenario | Qty | Notes |
|
||||
|---|---|---|
|
||||
| Confirmed today (Crystal, Megan, Tamra-through-June) | 3 | Crystal's reply |
|
||||
| Likely additions from John + Meredith (guessed) | ~5–8 | Wait for actual reply |
|
||||
| All staff (if "restrict everyone" decision) | ~23 | Equals the full post-cleanup licensed-user count from `docs/cloud/m365.md` |
|
||||
|
||||
## Action items
|
||||
|
||||
- [ ] Follow up with John Trozzi on the gathering — he owes us the list
|
||||
- [ ] Push Meredith for the "restrict everyone or just some" decision
|
||||
- [ ] When list is final, decide: standalone P2 add-on OR move those users to Business Premium OR move the whole tenant to Business Premium (recommended)
|
||||
- [ ] Build CA policy `CSC - Office Staff PHI Access` separate from the caregiver mobile policy
|
||||
- [ ] Remember to REMOVE Tamra's license + CA exclusion on her departure date (June 2026)
|
||||
|
||||
## Related docs
|
||||
|
||||
- `docs/cloud/m365.md`
|
||||
- `docs/cloud/m365-impersonation-protection.md`
|
||||
- `docs/cloud/caregiver-m365-p2-rollout.md`
|
||||
- `docs/proposals/m365-premium-upgrade.md`
|
||||
- `docs/security/hipaa.md`
|
||||
276
clients/cascades-tucson/docs/issues/audit-findings-2026-03-20.md
Normal file
276
clients/cascades-tucson/docs/issues/audit-findings-2026-03-20.md
Normal file
@@ -0,0 +1,276 @@
|
||||
# Cascades Master Issue Tracker
|
||||
|
||||
Combined from fleet audit (2026-03-20) and all prior issue log entries.
|
||||
|
||||
## Work Log
|
||||
|
||||
### 2026-03-26
|
||||
- [x] MAINTENANCE-PC: Uninstalled OneDrive (corrupt Telemetry.dll causing entry point error on boot, user doesn't use it)
|
||||
|
||||
### 2026-03-25
|
||||
- [x] MAINTENANCE-PC: Disabled Wi-Fi power saving + Fast Startup (was dropping Wi-Fi after idle)
|
||||
|
||||
### 2026-03-21
|
||||
- [x] Enabled AD Recycle Bin
|
||||
- [x] Set MachineAccountQuota = 0
|
||||
- [x] Set RestrictAnonymous = 1 on CS-SERVER
|
||||
- [x] Ran stale printer port cleanup on all machines
|
||||
|
||||
### 2026-03-20 (evening)
|
||||
- [x] Ran audits on all 19 machines, built full documentation
|
||||
- [x] Pro key applied: ANN-PC, DESKTOP-DLTAGOI, MAINTENANCE-PC, MDIRECTOR-PC
|
||||
- [x] RDP disabled: ASSISTMAN-PC, DESKTOP-U2DHAP0
|
||||
- [x] AutoPatch + Win 11 upgrade tasks pushed to 15 machines (overnight, stops 5AM)
|
||||
- **Skipped:** CS-SERVER (server), RECEPTIONIST-PC (front desk), MEMRECEPT-PC (front desk + ancient hw)
|
||||
- After Win 11 upgrade completes on LAPTOP-DRQ5L558 and LAPTOP-E0STJJE8, push Pro key
|
||||
|
||||
---
|
||||
|
||||
## CRITICAL
|
||||
|
||||
- [ ] **1. No backup — anywhere**
|
||||
- CS-SERVER has no backup. It is the ONLY DC. If it dies, everything is gone.
|
||||
- Synology ABB blocked (ext4, needs Btrfs) — use Windows Server Backup to Synology SMB share instead
|
||||
- No M365 backup either
|
||||
- HIPAA §164.308(a)(7)
|
||||
|
||||
- [ ] **2. CS-SERVER hardware — 2009 Dell R610, extreme failure risk**
|
||||
- 16+ years old. Single server runs: DC, DNS, DHCP, File Server, Hyper-V (VoIP), RDS, IIS, NPS
|
||||
- No second DC — if hardware fails, AD, DNS, shares, phones ALL go down
|
||||
- Plan: migrate to new hardware, add second DC
|
||||
|
||||
- [ ] **3. Windows Updates — 6 machines critically behind**
|
||||
- [~] DESKTOP-LPOPV30 — 13 months behind — AutoPatch running overnight
|
||||
- [~] LAPTOP2 — 8 months — AutoPatch running overnight
|
||||
- [~] CRYSTAL-PC — 5 months — AutoPatch running overnight
|
||||
- [ ] MEMRECEPT-PC — 4 months — skipped (front desk, ancient hw)
|
||||
- [~] ASSISTMAN-PC — 3 months — AutoPatch running overnight
|
||||
- [~] DESKTOP-KQSL232 — 3 months — AutoPatch running overnight
|
||||
- RECEPTIONIST-PC also skipped — needs update run scheduled
|
||||
|
||||
- [x] **4. Windows Home → Pro upgrades** *(2026-03-20)*
|
||||
- [x] ANN-PC, DESKTOP-DLTAGOI, MAINTENANCE-PC, MDIRECTOR-PC — done via changepk
|
||||
- [ ] LAPTOP-DRQ5L558, LAPTOP-E0STJJE8 — pending Win 11 upgrade first
|
||||
- [ ] MEMRECEPT-PC — replace machine instead
|
||||
|
||||
- [ ] **5. Shared accounts with NO PASSWORD accessing PHI**
|
||||
- [ ] NURSESTATION-PC: "Nurses" — accesses ALIS (medical records)
|
||||
- [ ] MEMRECEPT-PC: "memfrtdesk" — MemCare front desk
|
||||
- [ ] RECEPTIONIST-PC: "Front Desk" — mapped drives to CS-SERVER
|
||||
- [ ] DESKTOP-KQSL232: Lois Lane — PasswordRequired=False
|
||||
- Also: AD shared accounts (Culinary, Receptionist, saleshare, directoryshare) need replacement — Phase 5
|
||||
- HIPAA §164.312(a)(2)(i)
|
||||
|
||||
- [ ] **6. No audit logging**
|
||||
- CS-SERVER: Object Access auditing completely disabled — cannot track PHI access
|
||||
- Synology NAS: stores PHI with no access auditing (ext4 can't support it) — migrate to CS-SERVER NTFS
|
||||
- HIPAA §164.312(b)
|
||||
|
||||
- [ ] **7. Expired SSL certificate on CS-SERVER (2025-04-02)**
|
||||
- Self-signed cert expired ~1 year ago, causing Schannel TLS errors
|
||||
|
||||
- [ ] **8. Floating firewall rule #4 passes ALL IPv4 traffic**
|
||||
- Breaks room-to-room VLAN isolation — residents can reach staff VLAN, servers, other rooms
|
||||
- Planned: Phase 1.3 — replace with scoped rules
|
||||
- HIPAA §164.312(e)(1)
|
||||
|
||||
## HIGH
|
||||
|
||||
- [ ] **9. Remove non-IT staff from Domain Admins**
|
||||
- [ ] Meredith.Kuhn — never logged in, never set password
|
||||
- [ ] John.Trozzi — never logged in, never set password
|
||||
|
||||
- [ ] **10. AD password issues**
|
||||
- [ ] 23 accounts never set a password (null PasswordLastSet)
|
||||
- [ ] 10 accounts with PasswordNeverExpires (Lois.Lane, strozzi, Culinary, Receptionist, howard, directoryshare, etc.)
|
||||
- [ ] Password min length only 7 — increase to 12 in Default Domain Policy
|
||||
- [ ] krbtgt password 569 days old (last set 2024-08-28) — rotate
|
||||
|
||||
- [ ] **11. No screen lock on ANY machine**
|
||||
- Zero machines have inactivity timeout or screensaver lock
|
||||
- Staff walk away from ALIS sessions, shared drives, email — all open
|
||||
- Push via GPO (domain) or registry (non-domain)
|
||||
|
||||
- [ ] **12. BitLocker broken/missing fleet-wide**
|
||||
- [ ] Fix protection OFF (encrypted but no protectors): ACCT2-PC, LAPTOP2, RECEPTIONIST-PC
|
||||
- [ ] Enable on remaining 13 machines (requires Pro — do after upgrades)
|
||||
- Only 2 of 18 working correctly (DESKTOP-LPOPV30, DESKTOP-U2DHAP0)
|
||||
|
||||
- [ ] **13. No LAPS — same local admin password on every machine**
|
||||
- Compromise one = compromise all. Deploy Windows LAPS.
|
||||
|
||||
- [ ] **14. Share permissions wide open on CS-SERVER**
|
||||
- [ ] Culinary: Everyone=FullControl → SG-Culinary-RW
|
||||
- [ ] directoryshare: Everyone=FullControl → SG-Directory-RW
|
||||
- [ ] Roaming: Domain Users=FullControl → restrict
|
||||
- [ ] Shares (parent): Everyone=FullControl NTFS → restrict
|
||||
- Security groups already designed — apply during Phase 2
|
||||
|
||||
- [ ] **15. M365 — no MFA, no BAA signed**
|
||||
- [ ] Enable Security Defaults (MFA) in Entra ID — free, 5 minutes
|
||||
- [ ] Sign Microsoft HIPAA BAA in M365 Admin Center
|
||||
- [ ] Verify BAA with ALIS (go-alis.com) — ask management
|
||||
- HIPAA §164.312(d) and §164.308(b)(1)
|
||||
|
||||
- [ ] **16. M365 licenses full (34/34) — 12 role accounts wasting licenses**
|
||||
- Convert role-based accounts to shared mailboxes (~$150/mo savings)
|
||||
- Frees licenses for actual employees
|
||||
- Delete: Kristiana Dowse (HR confirmed), "howaed" typo guest account
|
||||
- Delete shared mailboxes: Anna Pitzlin, Nela Durut-Azizi (HR confirmed OK)
|
||||
- Sandra Fish still global admin — create break-glass admin, remove her access
|
||||
|
||||
- [ ] **17. QuickBooks installed on Domain Controller**
|
||||
- QB Pro 2024 running on CS-SERVER with DB listener on port 6600
|
||||
- Should be on dedicated workstation or VM — increases DC attack surface
|
||||
|
||||
- [ ] **18. Account lockout was disabled (fixed threshold, but GPO not fully deployed)**
|
||||
- Default Domain Policy: 5 attempts / 30 min (fixed 2026-03-09)
|
||||
- But most PCs aren't domain-joined so policy doesn't apply to them yet
|
||||
|
||||
- [x] **19. RDP without NLA** *(2026-03-20)*
|
||||
- [x] ASSISTMAN-PC — disabled
|
||||
- [x] DESKTOP-U2DHAP0 — disabled
|
||||
|
||||
- [ ] **20. TightVNC on MEMRECEPT-PC + old MSP remote access tools everywhere**
|
||||
- [ ] TightVNC on MEMRECEPT-PC — unauthorized remote access, no-password machine
|
||||
- [ ] Splashtop Streamer — ALL 19 machines
|
||||
- [ ] Datto RMM — CS-SERVER at minimum
|
||||
- [ ] N-able Take Control — some machines
|
||||
- [ ] RemotePC — ASSISTMAN-PC, CHEF-PC, DESKTOP-U2DHAP0
|
||||
- [ ] TeamViewer — ANN-PC
|
||||
- [ ] GoTo Opener — ANN-PC, MDIRECTOR-PC, DESKTOP-H6QHRR7
|
||||
|
||||
- [ ] **21. AV conflicts on multiple machines**
|
||||
- [ ] RECEPTIONIST-PC: Bitdefender + Datto AV both running
|
||||
- [ ] LAPTOP-E0STJJE8: McAfee LiveSafe + Datto AV
|
||||
- [ ] MDIRECTOR-PC: COMODO AV disabled (stale, remove)
|
||||
- [ ] CHEF-PC: Norton Security Scan (bloatware)
|
||||
|
||||
- [ ] **22. RDS licensing expired ~17 months ago**
|
||||
- RDS roles installed (Connection Broker, Session Host, Web Access) but no CALs
|
||||
- Decide: purchase CALs or remove RDS roles
|
||||
|
||||
## MEDIUM
|
||||
|
||||
- [ ] **23. Most PCs not domain-joined (15 of 18)**
|
||||
- Only 3 joined: ACCT2-PC, CRYSTAL-PC, DESKTOP-H6QHRR7
|
||||
- No GPOs apply to the other 15 (password policy, screen lock, BitLocker, drive maps)
|
||||
- Domain join planned Phase 3, needs Pro on all machines first
|
||||
|
||||
- [ ] **24. Network — machines on wrong subnets**
|
||||
- LAPTOP-DRQ5L558 on Guest WiFi (10.0.50.x) — no internal access at all
|
||||
- Many machines on old LAN (192.168.2-3.x) instead of INTERNAL (10.0.20.x)
|
||||
- Most non-domain machines DNS points to pfSense (192.168.0.1) not CS-SERVER — adds latency for AD lookups
|
||||
|
||||
- [ ] **25. AD OU cleanup — 13 junk root-level OUs**
|
||||
- 10 duplicate department OUs + Managment (misspelled) + MemCare + Sales
|
||||
- 20 accounts in CN=Users need placement
|
||||
- Scripts ready: phase2-ou-cleanup.ps1, phase2-ad-setup.ps1
|
||||
|
||||
- [ ] **26. Delete confirmed former employee AD accounts**
|
||||
- Disabled: Anna.Pitzlin, Nela.Durut-Azizi, Jodi.Ramstack, Monica.Ramirez, Jeff.Bristol
|
||||
- Enabled but gone: Haris.Durut, Nuria.Diaz, Cathy.Reece, Kelly.Wallace, Isabella.Islas, ann.dery, alyssa.brooks (duplicate)
|
||||
- Lupe.Sanchez — possible duplicate of Guadalupe.Sanchez (verify onsite)
|
||||
|
||||
- [ ] **27. AD ↔ M365 identity issues**
|
||||
- Tamra.Johnson AD account needs rename to Tamra.Matthews (M365 already correct)
|
||||
- nick pavloff has M365 but no AD account
|
||||
- AD and M365 fully separate (no Entra Connect) — evaluate after Phase 3
|
||||
- 13 AD users have no M365 account (hourly staff — determine if they need email)
|
||||
|
||||
- [ ] **28. Hardware problems**
|
||||
- [ ] MEMRECEPT-PC: Pentium E5500, 6GB RAM, 100Mbps NIC — replace entirely
|
||||
- [ ] MDIRECTOR-PC: only 3.9 GB RAM — upgrade or replace
|
||||
- [ ] MAINTENANCE-PC: disk 85% full (34.6 GB free) — clean up
|
||||
- [ ] ASSISTMAN-PC: 7 local admin accounts — clean up to 3
|
||||
|
||||
- [ ] **29. Kitchen iPads not isolated**
|
||||
- 9 iPads on INTERNAL VLAN with full access to staff resources
|
||||
- Food service only, NOT medical — restrict to kitchen thermal printers only
|
||||
- Needs firewall rules restricting iPad MACs to printer IPs + internet
|
||||
|
||||
- [ ] **30. 9 offline UniFi APs — coverage gaps**
|
||||
- APs on floors 1-4 offline, some on wrong IP ranges (192.168.6-7.x)
|
||||
- Need physical visit to check power, cables, re-adopt
|
||||
|
||||
- [ ] **31. Printer issues**
|
||||
- [ ] 206 Health Services Brother printer drops WiFi (192.168.1.138) — wire it or fix signal
|
||||
- [ ] Brother printer 192.168.2.53 dual-connected (WiFi + ethernet, ARP flapping) — disable one
|
||||
- [ ] Bizhub C368 location and status unknown — find it onsite
|
||||
- [ ] Room 405 long print lag — investigate onsite
|
||||
|
||||
- [ ] **32. LDAP Channel Binding not configured on CS-SERVER**
|
||||
|
||||
- [ ] **33. Stale DNS records**
|
||||
- 192.168.2.59 and 192.168.0.5 in GC (old DCs?)
|
||||
- DESKTOP-1ISF081 has AAAA but no A record
|
||||
|
||||
- [ ] **34. UniFi VLAN 10 "CSC Internal Network" mismatch**
|
||||
- UniFi has VLAN 10 but pfSense uses VLAN 20 for INTERNAL — VLAN 10 may be orphaned
|
||||
|
||||
- [ ] **35. Room 339 pfSense interface possibly disabled**
|
||||
- Missing `<enable>` tag — verify if room is occupied
|
||||
|
||||
- [ ] **36. SSH on pfSense — verify hardening**
|
||||
- Confirm key-based auth only, restricted to management VLAN
|
||||
|
||||
- [ ] **37. Synology shares still mapped directly from MDIRECTOR-PC**
|
||||
- H: \\cascadesds\homes, M: \\cascadesds\Management, P: \\cascadesds\Public
|
||||
- Should point to CS-SERVER after migration
|
||||
|
||||
- [ ] **38. Lauren Hasselman needs Sales share access**
|
||||
- Replaced Jeff Bristol as Business Office Director, permissions not granted
|
||||
|
||||
## LOW
|
||||
|
||||
- [ ] **39. Remove stale user profiles from workstations**
|
||||
- DESKTOP-LPOPV30: Haris Durut, Jodi Ramstack, Nela
|
||||
- NURSESTATION-PC: Adella Clark (2021), April Hughes (2020)
|
||||
- MAINTENANCE-PC: nick (2024-08), John Trozzi (disabled)
|
||||
- ASSISTMAN-PC: Cecil Rinker, "DO NOT USE"
|
||||
|
||||
- [ ] **40. CS-SERVER cleanup**
|
||||
- [ ] Remove AutomationManagerAgent orphan service (file not found)
|
||||
- [ ] Delete "Synology Sync machine" VM (off, not needed)
|
||||
- [ ] Remove unused DHCP role
|
||||
- [ ] Decide on Power Options GPO (unlinked) — keep or delete
|
||||
- [ ] Remove 3 empty GPOs (CopyRoomPrinter, Nurses-Kiosk, MemCareMedTechPrinter) — if not already deleted
|
||||
|
||||
- [ ] **41. GPOs not deployed yet (Phase 2.5-2.6)**
|
||||
- CSC - Drive Mappings, CSC - Printer Deployment, CSC - Security Baseline, CSC - Windows Update, CSC - Folder Redirection, CSC - Shared Workstation
|
||||
- Blocked on: domain join (Phase 3)
|
||||
|
||||
- [ ] **42. RMM documentation missing**
|
||||
- rmm/rmm.md is blank — document agent counts, monitoring, patch policies
|
||||
|
||||
## COMPLETED
|
||||
|
||||
- [x] RDP disabled on ASSISTMAN-PC + DESKTOP-U2DHAP0 *(2026-03-20)*
|
||||
- [x] Pro key applied: ANN-PC, DESKTOP-DLTAGOI, MAINTENANCE-PC, MDIRECTOR-PC *(2026-03-20)*
|
||||
- [x] Orphan printer ports cleaned on all machines *(2026-03-21)*
|
||||
- [x] AD Recycle Bin enabled *(2026-03-21)*
|
||||
- [x] MachineAccountQuota set to 0 *(2026-03-21)*
|
||||
- [x] RestrictAnonymous set to 1 *(2026-03-21)*
|
||||
- [x] Guest WiFi isolated to VLAN 50 *(2026-03-06)*
|
||||
- [x] DNS scavenging enabled, stale records cleaned *(2026-03-06)*
|
||||
- [x] Reverse DNS zones created *(2026-03-06)*
|
||||
- [x] Room 218 DHCP scope fixed *(2026-03-07)*
|
||||
- [x] Room 130 disabled firewall rule deleted *(2026-03-07)*
|
||||
- [x] CS-SERVER timezone fixed to Arizona *(2026-03-07)*
|
||||
- [x] LG TV ARP flapping fixed (ethernet disabled) *(2026-03-07)*
|
||||
- [x] Account lockout set to 5/30 *(2026-03-09)*
|
||||
- [x] Monica.Ramirez removed from Domain Admins *(2026-03-09)*
|
||||
- [x] 3 empty GPOs reviewed (CopyRoomPrinter, Nurses-Kiosk, MemCareMedTechPrinter) *(2026-03-07)*
|
||||
|
||||
## Known Issues / Workarounds
|
||||
|
||||
- **Older DirecTV boxes cannot connect to VLAN networks (CSCNet)**
|
||||
- Must first join CSC ENT (non-VLAN), receive a software update, then they can join CSCNet
|
||||
- Affects resident room DirecTV boxes — discovered 2026-03-22
|
||||
|
||||
- **Synology NAS is ext4 — cannot use Active Backup for Business**
|
||||
- Use Windows Server Backup to Synology SMB share instead
|
||||
- Cannot convert without wiping volume
|
||||
|
||||
- **changepk.exe fails on Win 10 Home with Pro for Workstations key (error 0x80070490)**
|
||||
- Must upgrade to Win 11 first, then apply key — or use key during ISO setup
|
||||
618
clients/cascades-tucson/docs/issues/log.md
Normal file
618
clients/cascades-tucson/docs/issues/log.md
Normal file
@@ -0,0 +1,618 @@
|
||||
# Issue Log
|
||||
|
||||
Record past issues and their resolutions here. This helps the AI learn from historical
|
||||
troubleshooting and avoid repeating failed approaches.
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - CS-SERVER on 16-Year-Old Dell R610 — Imminent Hardware Failure Risk
|
||||
- **Reported By:** AI audit of server systeminfo
|
||||
- **Severity:** Critical
|
||||
- **Symptoms:** CS-SERVER (192.168.2.254) is the PRIMARY DOMAIN CONTROLLER for cascades.local running on a Dell PowerEdge R610 (~2009 vintage). This single server hosts AD DS, DNS, DHCP, File Server, Hyper-V, RDS, IIS, and NPS. If this hardware fails — and at 16+ years old it is statistically overdue — ALL services go down simultaneously with NO backup and NO second domain controller.
|
||||
- **Root Cause:** Legacy hardware never replaced. No redundancy or DR plan implemented.
|
||||
- **Resolution:** OPEN — Priority actions:
|
||||
1. IMMEDIATE: Configure Synology Active Backup for Business to back up C: and D: nightly
|
||||
2. URGENT: Deploy a second domain controller (VM on Synology, or new hardware, or Azure AD DS)
|
||||
3. Plan full server migration to modern hardware (Dell PowerEdge T350/R350 or similar)
|
||||
4. Separate roles across multiple servers/VMs to reduce blast radius
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - No Backup Solution for Any System
|
||||
- **Reported By:** AI audit
|
||||
- **Severity:** Critical
|
||||
- **Symptoms:** No backup exists for CS-SERVER, workstations, or M365 data. The only DC has no backup. File shares on D: (1.09TB, ~470GB used) are unprotected. Ransomware, hardware failure, or accidental deletion = permanent data loss.
|
||||
- **Root Cause:** Backup solution never implemented.
|
||||
- **Resolution:** PLANNED — **Migration Phase 0.1 + Phase 4.4**
|
||||
1. Synology Active Backup for Business (free) → back up CS-SERVER C: and D: to Synology NAS (Phase 0)
|
||||
2. Configure Hyper Backup on Synology → replicate to Backblaze B2 or Wasabi for offsite copy (Phase 4)
|
||||
3. Add M365 backup (Datto SaaS Protection, Veeam, or Acronis) (future)
|
||||
- **Time to Resolve:** Phase 0 (Day 1 evening)
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - Single Domain Controller — No AD Redundancy
|
||||
- **Reported By:** AI audit of server roles
|
||||
- **Severity:** Critical
|
||||
- **Symptoms:** CS-SERVER is the only domain controller for cascades.local. No secondary DC exists. AD DS, DNS for domain resolution, and DHCP (Windows) all depend on this single machine.
|
||||
- **Root Cause:** Second DC was never deployed.
|
||||
- **Resolution:** OPEN — Deploy a second DC. Options:
|
||||
1. VM on Synology (if it supports VMs) running Server 2019/2022 as DC
|
||||
2. New physical server (budget permitting)
|
||||
3. Azure AD DS or a cloud-hosted DC with site-to-site VPN
|
||||
- **Time to Resolve:** Pending — DC promotion takes ~1 hour once hardware/VM is ready
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - DHCP Conflict Check (pfSense + Windows DHCP)
|
||||
- **Reported By:** AI audit of pfSense config + server roles
|
||||
- **Severity:** ~~Medium~~ **RESOLVED**
|
||||
- **Symptoms:** Both pfSense and CS-SERVER have DHCP server roles installed.
|
||||
- **Root Cause:** Windows DHCP role is installed but has ZERO scopes configured. pfSense handles all DHCP for all VLANs. No conflict.
|
||||
- **Resolution:** RESOLVED — `Get-DhcpServerv4Scope` returned no results. pfSense is the sole DHCP server. Windows DHCP role could optionally be uninstalled to reduce confusion.
|
||||
- **Time to Resolve:** Resolved 2026-03-04
|
||||
- **Lessons Learned:** Role installed ≠ role active. Always verify scopes.
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - CS-QB VoIP VM Running on Failing Hardware
|
||||
- **Reported By:** AI audit of Hyper-V VMs
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** CS-QB VM (VoIP server, 2.35 GB RAM, IP 192.168.2.228) runs on CS-SERVER. VoIP is not MSP-managed, but the VM infrastructure IS. If CS-SERVER hardware fails, the phone system goes down with it.
|
||||
- **Root Cause:** VoIP VM placed on the only server, which is on 16-year-old hardware.
|
||||
- **Resolution:** OPEN — When CS-SERVER is migrated to new hardware, ensure CS-QB VM is migrated or relocated. Coordinate with VoIP provider since they require static IPs.
|
||||
- **Time to Resolve:** Pending — tied to server migration project
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - Synology Sync Machine VM is Powered Off
|
||||
- **Reported By:** AI audit of Hyper-V VMs
|
||||
- **Severity:** ~~Low~~ **RESOLVED**
|
||||
- **Symptoms:** A VM called "Synology Sync machine" exists on CS-SERVER but is powered off.
|
||||
- **Root Cause:** VM was set up "just in case" but was never used.
|
||||
- **Resolution:** RESOLVED — Confirmed by Howard: VM does nothing, safe to delete. Scheduled for deletion in **Migration Phase 5.2**.
|
||||
- **Time to Resolve:** Resolved 2026-03-04 (deletion in Phase 5)
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - CS-SERVER Timezone Mismatch with pfSense
|
||||
- **Reported By:** AI audit
|
||||
- **Severity:** ~~Low~~ **RESOLVED**
|
||||
- **Symptoms:** CS-SERVER is set to Pacific Time (UTC-8, observes DST). pfSense is set to America/Phoenix (UTC-7, does NOT observe DST). During DST (March-November), these are the same time. Outside DST, they differ by 1 hour. This can cause Kerberos authentication issues, log correlation problems, and GPO scheduling mismatches.
|
||||
- **Root Cause:** Inconsistent timezone configuration.
|
||||
- **Resolution:** RESOLVED 2026-03-07 — Set CS-SERVER to `(UTC-07:00) Arizona` via `Set-TimeZone -Id "US Mountain Standard Time"`.
|
||||
- **Time to Resolve:** Resolved 2026-03-07
|
||||
- **Lessons Learned:** Arizona does not observe DST — use "US Mountain Standard Time" not "Mountain Standard Time".
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - Floating Firewall Rule #4 Passes ALL IPv4 Traffic
|
||||
- **Reported By:** AI audit of pfSense config
|
||||
- **Severity:** High
|
||||
- **Symptoms:** Floating rule #4 (PASS, any interface, IPv4, any source, any destination) overrides per-interface rules. Breaks room-to-room isolation. Residents can potentially reach staff VLAN (10.0.20.0/24), management interfaces, VoIP phones, and other rooms.
|
||||
- **Root Cause:** Overly permissive floating rule — likely added as a quick fix or during initial setup and never scoped down.
|
||||
- **Resolution:** PLANNED — **Migration Phase 1.3.** Disable floating rule #4, replace with: ResidentsGroup → ! RFC1918 (rooms internet only). Replace INTERNAL rules with scoped AD/SMB/Print/ICMP allows. See `migration/phase1-network.md`.
|
||||
- **Time to Resolve:** Phase 1 (Day 1 evening)
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - 9 Offline Access Points
|
||||
- **Reported By:** AI audit of UniFi AP data
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** 9 APs showing offline in UniFi controller. Coverage gaps on floors 1-4.
|
||||
- **Affected APs:**
|
||||
- 108 (192.168.6.127) — wrong IP range, was mesh uplink
|
||||
- 121 (192.168.2.184) — mesh uplink
|
||||
- 128 (192.168.2.95) — no uplink detected
|
||||
- 204 (192.168.7.243) — wrong IP range, no uplink
|
||||
- 335 (192.168.2.206) — no uplink
|
||||
- 406 (192.168.2.4) — no uplink
|
||||
- 441 (192.168.2.200) — no uplink
|
||||
- 450 (192.168.6.207) — wrong IP range, no uplink
|
||||
- 4th Floor Atrium (192.168.3.28) — no uplink
|
||||
- **Root Cause:** Unknown — could be power loss, cable failure, or adoption issues. APs 108, 204, and 450 have IPs in 192.168.6.x/7.x which are outside the LAN DHCP range (192.168.2.x-3.x), suggesting they may have been misconfigured or adopted to wrong network.
|
||||
- **Resolution:** OPEN — Visit each AP physically. Check PoE power, cable, and switch port status. Re-adopt APs with wrong IPs. Prioritize 4th Floor Atrium (common area coverage).
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - Room 218 DHCP Scope Misconfigured (Single IP)
|
||||
- **Reported By:** AI audit of pfSense config
|
||||
- **Severity:** ~~Medium~~ **RESOLVED**
|
||||
- **Symptoms:** Room 218 DHCP scope range is 10.2.18.2 to 10.2.18.2. Only 1 IP can be leased. Any second device in the room will fail to get an address.
|
||||
- **Root Cause:** Typo or error in pfSense DHCP configuration. End of range should be 10.2.18.14 (matching the /28 pattern used by all other rooms).
|
||||
- **Resolution:** RESOLVED 2026-03-07 — Range end changed to 10.2.18.14.
|
||||
- **Time to Resolve:** Resolved 2026-03-07
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - Room 339 Interface Possibly Disabled
|
||||
- **Reported By:** AI audit of pfSense config
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** Room 339 VLAN interface (igc1.339, opt129) is missing the `<enable>` tag in the pfSense config. Room may have no network connectivity.
|
||||
- **Root Cause:** Unknown — may be intentional (vacant room) or a config oversight.
|
||||
- **Resolution:** OPEN — Verify if room 339 is occupied. If yes, enable the interface in pfSense under Interfaces > Room339. If intentionally disabled, document the reason.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - 206 Health Services Printer Drops WiFi
|
||||
- **Reported By:** Staff / printer doc
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** Brother MFC-L8900CDW at 192.168.1.138 will not stay connected to wireless. Repeated disconnections.
|
||||
- **Root Cause:** Likely combination of: Brother deep sleep mode dropping WiFi, possible weak signal from nearest AP, and/or DHCP lease issues. IP is in 192.168.1.x range (valid within /22 LAN but unusual compared to most devices on 192.168.2.x-3.x).
|
||||
- **Resolution:** OPEN — Recommended fix priority:
|
||||
1. Wire the printer (run ethernet to nearest switch port)
|
||||
2. If wiring not possible: set DHCP reservation, disable deep sleep on printer, verify AP signal strength in room 206
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - Bizhub C368 Location and Status Unknown
|
||||
- **Reported By:** AI audit of printer inventory
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** A Bizhub C368 is listed in the printer inventory but has no IP address, no location, and no status documented. Since printers are rentals, this unit needs to be accounted for.
|
||||
- **Root Cause:** Incomplete documentation.
|
||||
- **Resolution:** OPEN — Locate the Bizhub C368 physically. Document its IP, location, and connection type. Verify it's on the rental tracking list.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - Room 130 Disabled Firewall Rule
|
||||
- **Reported By:** AI audit of pfSense config
|
||||
- **Severity:** ~~Low~~ **RESOLVED**
|
||||
- **Symptoms:** Room 130 has a disabled TCP PASS rule in pfSense. Dead rules add clutter and confusion to the firewall config.
|
||||
- **Root Cause:** Likely a test rule that was disabled and never removed.
|
||||
- **Resolution:** RESOLVED 2026-03-07 — Disabled rule deleted from Room130 interface.
|
||||
- **Time to Resolve:** Resolved 2026-03-07
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - SSH Enabled on pfSense — Verify Hardening
|
||||
- **Reported By:** AI audit of pfSense config
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** SSH is enabled on pfSense. Not inherently a problem but should be hardened.
|
||||
- **Root Cause:** N/A — feature is intentionally enabled for remote management.
|
||||
- **Resolution:** OPEN — Verify: key-based auth only (no password auth), SSH access restricted to management VLAN or VPN only, not exposed on WAN.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-04 - RMM Data Not Documented
|
||||
- **Reported By:** AI audit
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** The RMM documentation is blank. No visibility into what devices are monitored, what alerts are configured, or what patching policies are in place.
|
||||
- **Root Cause:** Documentation gap.
|
||||
- **Resolution:** OPEN — Fill in rmm/rmm.md with the RMM product, agent counts, monitoring policies, and patch schedule.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - No Group Policy Configured
|
||||
- **Reported By:** AI audit of AD
|
||||
- **Severity:** High
|
||||
- **Symptoms:** `gpresult /r` shows no RSoP data on CRYSTAL-PC. No GPOs are linked to any OU. No password policy, no account lockout policy, no security baselines, no drive mappings — only Windows defaults apply.
|
||||
- **Root Cause:** GPOs were never created or configured.
|
||||
- **Resolution:** PLANNED — **Migration Phase 2.5 + 3.2.** Create 4 GPOs (Security Baseline, Drive Mappings, Printer Deployment, Windows Update). Link after first successful domain join. See `migration/phase2-server-prep.md`.
|
||||
- **Time to Resolve:** Phase 2-3 (Day 2-3)
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - RDS Licensing Not Configured — Compliance Risk
|
||||
- **Reported By:** AI audit of CS-SERVER
|
||||
- **Severity:** High
|
||||
- **Symptoms:** `Get-RDLicenseConfiguration` returns Mode=NotConfigured, no license servers. RDS roles (Connection Broker, Session Host, Web Access) are installed. Server was installed 8/4/2024 — the 120-day grace period expired ~17 months ago.
|
||||
- **Root Cause:** RDS CALs were never purchased or configured.
|
||||
- **Resolution:** PLANNED — **Migration Phase 5.4.** Check if anyone uses RDS. If yes → purchase CALs. If no → uninstall RDS role.
|
||||
- **Time to Resolve:** Phase 5 (Day 4)
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - Only 6 Computers Domain-Joined (4+ Staff PCs Missing)
|
||||
- **Reported By:** AI audit of AD computers
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** `Get-ADComputer` returns only 6 objects (CS-SERVER, CS-QB, CRYSTAL-PC, ACCT2-PC, DESKTOP-H6QHRR7, DESKTOP-1ISF081). Known staff PCs SALES4-PC, CHEF-PC, MDIRECTOR-PC, and DESKTOP-KQSL232 are NOT in AD. These machines are on the network but not domain-joined.
|
||||
- **Root Cause:** PCs were likely set up as workgroup machines and never joined to the domain.
|
||||
- **Resolution:** PLANNED — **Migration Phase 3.** Join in order: DESKTOP-KQSL232 → CHEF-PC → SALES4-PC → MDIRECTOR-PC. See `migration/phase3-domain-join.md` and scripts.
|
||||
- **Time to Resolve:** Phase 3 (Day 3)
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - Shared/Generic AD Accounts in Use
|
||||
- **Reported By:** AI audit of AD users
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** Three shared/generic accounts exist and are enabled: Culinary, Receptionist, saleshare. Shared accounts cannot be audited to a specific person — if something is deleted or accessed inappropriately, there's no way to trace who did it.
|
||||
- **Root Cause:** Created for convenience instead of individual accounts.
|
||||
- **Resolution:** PLANNED — **Migration Phase 5.3.** Replace with individual user accounts + security group membership.
|
||||
- **Time to Resolve:** Phase 5 (Day 4)
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - 5 Stale Disabled AD Accounts
|
||||
- **Reported By:** AI audit of AD users
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** 5 disabled user accounts (Anna.Pitzlin, Nela.Durut-Azizi, Jodi.Ramstack, Monica.Ramirez, Jeff.Bristol) are still in AD. Disabled accounts with remaining permissions or group memberships can be a security risk if re-enabled.
|
||||
- **Root Cause:** Former employees disabled but not removed.
|
||||
- **Resolution:** PLANNED — **Migration Phase 2.2.** Delete after client confirmation. See `migration/scripts/phase2-ad-setup.ps1` ($DeleteStaleAccounts flag).
|
||||
- **Time to Resolve:** Phase 2 (Day 2)
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - QuickBooks Pro 2024 Installed on Domain Controller
|
||||
- **Reported By:** AI audit of installed software
|
||||
- **Severity:** High
|
||||
- **Symptoms:** QuickBooks Pro 2024 (v34.0) is installed directly on CS-SERVER, the primary domain controller. QuickBooks Database Server is listening on port 6600. Business applications should never run on a DC — they increase attack surface, consume resources needed for AD services, and complicate server migration.
|
||||
- **Root Cause:** QuickBooks was installed on the only available server rather than a dedicated workstation or VM.
|
||||
- **Resolution:** OPEN — Migrate QuickBooks to a dedicated workstation or VM. The QuickBooks database files on D:\Shares can still be accessed via network share. QuickBooks Desktop can run in multi-user mode with the database on a file share.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - Stale DNS Records in cascades.local Zone
|
||||
- **Reported By:** AI audit of Windows DNS
|
||||
- **Severity:** ~~Medium~~ **RESOLVED**
|
||||
- **Symptoms:** Multiple DNS A records in the cascades.local zone point to incorrect or outdated IPs:
|
||||
- cascades.local @ → 192.168.0.5 and 192.168.2.59 (DC is actually at 192.168.2.254)
|
||||
- CRYSTAL-PC → 192.168.5.115 (should be 10.0.20.205)
|
||||
- CS-QB → 192.168.5.29 (should be 192.168.2.228)
|
||||
- DESKTOP-1ISF081 → 192.168.5.30 (192.168.5.x is not a documented subnet)
|
||||
- DomainDnsZones/ForestDnsZones → 192.168.0.5 and 192.168.2.59
|
||||
- **Root Cause:** Dynamic DNS registrations from old IPs were never cleaned up. DNS scavenging was not configured.
|
||||
- **Resolution:** RESOLVED 2026-03-06 — All stale records removed. Correct @ record added (192.168.2.254). DomainDnsZones/ForestDnsZones fixed. DNS scavenging enabled (7-day interval). First scavenge available 3/13/2026.
|
||||
- **Time to Resolve:** Resolved 2026-03-06
|
||||
- **Lessons Learned:** Enable DNS scavenging on all AD-integrated zones. Set aging on zone + server-level scavenging.
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - No Reverse DNS Lookup Zones
|
||||
- **Reported By:** AI audit of Windows DNS
|
||||
- **Severity:** ~~Low~~ **RESOLVED**
|
||||
- **Symptoms:** No reverse lookup zones exist for production subnets (192.168.0.0/22, 10.0.20.0/24). Only auto-created placeholder zones (0, 127, 255). PTR lookups will fail for all internal hosts.
|
||||
- **Root Cause:** Reverse zones were never created.
|
||||
- **Resolution:** RESOLVED 2026-03-06 — 5 reverse lookup zones created: 0.168.192, 1.168.192, 2.168.192, 3.168.192.in-addr.arpa + 20.0.10.in-addr.arpa.
|
||||
- **Time to Resolve:** Resolved 2026-03-06
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - Guest WiFi on Same Network as Servers — No Isolation
|
||||
- **Reported By:** AI audit of UniFi WiFi config
|
||||
- **Severity:** ~~High~~ **RESOLVED**
|
||||
- **Symptoms:** The "Guest" SSID is mapped to the Native Network (Default LAN, 192.168.0.0/22). Guest users land on the same L2/L3 network as CS-SERVER (DC, 192.168.2.254), Synology NAS (192.168.0.120), pfSense management (192.168.0.1), and all LAN infrastructure.
|
||||
- **Root Cause:** Guest SSID was configured on the default/native network instead of an isolated VLAN.
|
||||
- **Resolution:** RESOLVED 2026-03-06 — Guest VLAN 50 created (10.0.50.0/24, igc1.50 GUEST interface). DHCP scope 10.0.50.50-239. Four firewall rules (block LAN, block 10.x, block 172.x, pass internet). Guest SSID reassigned to VLAN 50 in UniFi. **Needs onsite test to confirm isolation.**
|
||||
- **Time to Resolve:** Resolved 2026-03-06 (pending onsite verification)
|
||||
- **Lessons Learned:** Always isolate guest WiFi on a dedicated VLAN with explicit deny rules to RFC1918.
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-05 - UniFi VLAN 10 "CSC Internal Network" Mismatch
|
||||
- **Reported By:** AI audit of UniFi WiFi config
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** UniFi defines "CSC Internal Network" as VLAN 10, but pfSense has the INTERNAL staff interface on VLAN 20 (igc1.20, 10.0.20.0/24). UniFi also has "Internal" on VLAN 20 (correct). VLAN 10 may be orphaned or cause confusion.
|
||||
- **Root Cause:** Likely a leftover from initial setup or a mislabeled network.
|
||||
- **Resolution:** PLANNED — **Migration Phase 1.5.** Verify unused, delete from UniFi.
|
||||
- **Time to Resolve:** Phase 1 (Day 1 evening)
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-07 - Non-IT Staff in Domain Admins Group
|
||||
- **Reported By:** AD export analysis (2026-03-07)
|
||||
- **Severity:** High
|
||||
- **Symptoms:** Domain Admins group contains 5 members. Meredith.Kuhn (administrative staff) and John.Trozzi (maintenance) are Domain Admins. Monica.Ramirez (DISABLED account) is still in Domain Admins. Non-IT users with DA privileges can accidentally or intentionally modify AD, GPOs, DNS, or any domain-joined system.
|
||||
- **Root Cause:** Overly permissive group membership, likely set up for convenience.
|
||||
- **Resolution:** PLANNED — Phase 2.2. Remove Monica.Ramirez, Meredith.Kuhn, and John.Trozzi from Domain Admins. Only Administrator and sysadmin should remain.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-07 - 3 Undocumented GPOs Found (Dec 2025)
|
||||
- **Reported By:** AD export analysis (2026-03-07)
|
||||
- **Severity:** ~~Medium~~ **REVIEWED**
|
||||
- **Symptoms:** Three GPOs exist that were not previously documented: CopyRoomPrinter (Dec 10, 2025), Nurses-Kiosk (Dec 15, 2025), MemCareMedTechPrinter (Dec 11, 2025). Unknown who created them, what settings they contain, and whether they are linked to any OU.
|
||||
- **Root Cause:** Created by previous MSP or sysadmin account, not documented.
|
||||
- **Resolution:** REVIEWED 2026-03-07 — GPO report exported and analyzed. **All 3 GPOs are completely empty** — no computer or user configuration settings defined, not linked to any OU. Safe to delete with zero impact. Delete during Phase 2.2 AD cleanup.
|
||||
- **Time to Resolve:** Reviewed 2026-03-07, deletion pending Phase 2.2
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-07 - Account Lockout Policy Disabled (Default Domain Policy)
|
||||
- **Reported By:** GPO report analysis (2026-03-07)
|
||||
- **Severity:** High
|
||||
- **Symptoms:** Default Domain Policy has account lockout threshold set to 0 (disabled). This means unlimited failed password attempts are allowed with no lockout, enabling brute-force attacks against any AD account.
|
||||
- **Root Cause:** Default Domain Policy was never hardened — only basic password complexity was configured.
|
||||
- **Resolution:** PLANNED — Set account lockout threshold to 5 invalid attempts, lockout duration 30 minutes, reset counter after 30 minutes. Will be applied via the planned "CSC - Security Baseline" GPO in Phase 2.6.
|
||||
- **Time to Resolve:** Pending Phase 2.6
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-07 - Synology NAS Uses ext4 — Active Backup for Business Blocked
|
||||
- **Reported By:** Backup setup attempt (2026-03-07)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** Synology Active Backup for Business requires Btrfs filesystem. Synology Volume 1 is formatted as ext4. Cannot convert without wiping the volume.
|
||||
- **Root Cause:** NAS was set up with ext4 (older default) rather than Btrfs.
|
||||
- **Resolution:** PLANNED — Use Windows Server Backup on CS-SERVER to back up to a Synology SMB share instead. Alternative: Veeam Backup Free Edition.
|
||||
- **Time to Resolve:** Pending — next session
|
||||
- **Lessons Learned:** Always verify NAS filesystem before planning backup solutions. ABB requires Btrfs.
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-07 - ARP Flapping: LG TV Dual-Connected (WiFi + Ethernet)
|
||||
- **Reported By:** ARP log analysis
|
||||
- **Severity:** ~~High~~ **RESOLVED**
|
||||
- **Symptoms:** 192.168.2.148 and 192.168.2.152 flapping every 30-60 seconds between MACs `58:96:0a:c6:1e:49` (ethernet) and `e0:85:4d:4d:f0:3e` (WiFi). Hundreds of ARP "moved from" entries daily. Constant since at least Feb 8.
|
||||
- **Root Cause:** LG webOS TV connected via both ethernet (1st Floor USW Port 18) and WiFi (CSC ENT, 5 GHz) simultaneously. Both interfaces claimed the same IP, causing pfSense ARP table to flip between MACs.
|
||||
- **Resolution:** RESOLVED 2026-03-07 — Disabled ethernet port (1st Floor USW Port 18) in UniFi. TV now WiFi-only. DHCP reservation recommended for WiFi MAC `e0:85:4d:4d:f0:3e` at 192.168.2.148.
|
||||
- **Time to Resolve:** Resolved 2026-03-07
|
||||
- **Lessons Learned:** Check for dual-homed devices (WiFi + ethernet) when ARP flapping is detected. Smart TVs often auto-connect to both.
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-07 - ARP Flapping: Brother Printer at 192.168.2.53 Dual-Connected
|
||||
- **Reported By:** ARP log analysis
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** 192.168.2.53 flapping between MACs `c8:a3:e8:a2:dd:9e` (ethernet, MemCare switch Port 3) and `80:3f:5d:72:7b:ee` (WiFi, CSC ENT 2.4 GHz). Hostname BRWC8A3E8A2DD9E confirms Brother printer.
|
||||
- **Root Cause:** Brother printer connected via both ethernet and WiFi simultaneously, same as the LG TV issue.
|
||||
- **Resolution:** OPEN — Needs onsite visit to determine whether to keep WiFi or ethernet connection. Disable the other.
|
||||
- **Time to Resolve:** Pending onsite visit
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-07 - Minor ARP Flapping in Resident Rooms (307, 130) and iPhone MAC Randomization
|
||||
- **Reported By:** ARP log analysis
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** Occasional ARP flapping: Room 307 (10.3.7.7, evenings), Room 130 (10.1.30.8, Feb 22 only), and 192.168.3.115 (iPhone, ~6 AM daily). Room 130 and 307 devices no longer on network. iPhone flapping caused by iOS private MAC randomization.
|
||||
- **Root Cause:** Room conflicts likely transient DHCP collisions from resident devices. iPhone conflict is normal iOS behavior.
|
||||
- **Resolution:** No action required. Room 307 noted for onsite check. Room 130 devices gone. iPhone MAC randomization is cosmetic.
|
||||
- **Time to Resolve:** N/A
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-07 - AD OU Structure: 13 Junk Root-Level OUs + CN=Users Misplacement
|
||||
- **Reported By:** AD export analysis (2026-03-07)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** 10 duplicate department OUs exist at root level AND under Departments OU. 3 additional empty OUs (Managment [misspelled], MemCare, Sales) at root. 20 user accounts sitting in the default CN=Users container instead of proper department OUs. 5 computers in default CN=Computers instead of a Workstations OU.
|
||||
- **Root Cause:** Previous admin created OUs at root level, then also under Departments. Accounts were created in the default container and never moved.
|
||||
- **Resolution:** PLANNED — Phase 2.1. Scripts created:
|
||||
1. `phase2-ou-cleanup.ps1` — Audit root OUs (confirm empty), delete 13 root-level OUs, delete/disable stale accounts in CN=Users, flag Lupe.Sanchez for review
|
||||
2. `phase2-ad-setup.ps1` — Create Workstations OU, move 4 staff PCs from CN=Computers
|
||||
- **Time to Resolve:** Pending — run on CS-SERVER via ScreenConnect
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-07 - Lupe.Sanchez: Possible Duplicate of Guadalupe.Sanchez
|
||||
- **Reported By:** AD export analysis (2026-03-07)
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** Lupe.Sanchez exists in CN=Users (enabled). Guadalupe.Sanchez already exists in Departments\Housekeeping. "Lupe" is a common nickname for "Guadalupe". One account may be a duplicate.
|
||||
- **Root Cause:** Unknown — may have been created by different admins at different times.
|
||||
- **Resolution:** OPEN — Flag for client review onsite. Check which account is actively used, delete the duplicate.
|
||||
- **Time to Resolve:** Pending onsite visit
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - M365 Licenses Fully Allocated (0 Available)
|
||||
- **Reported By:** M365 admin portal audit (2026-03-08)
|
||||
- **Severity:** High
|
||||
- **Symptoms:** Microsoft 365 Business Standard is 34/34 with 0 available. Cannot add new users (e.g., nick pavloff, new hire created 2026-03-07) without purchasing additional licenses.
|
||||
- **Root Cause:** 12 generic/role-based accounts (accounting@, frontdesk@, hr@, security@, memcarereceptionist@, boadmin@, accountingassistant@, Training@, etc.) each consume a full Business Standard license ($12.50/mo) instead of being shared mailboxes (free).
|
||||
- **Resolution:** PLANNED — Convert role-based accounts to shared mailboxes in Exchange Online. This frees up ~12 licenses (~$150/mo savings). Shared mailboxes don't require a license and still receive/send email. Users access them via permissions instead of logging in directly.
|
||||
- **Time to Resolve:** Pending — next M365 cleanup session
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - 12 Role-Based M365 Accounts Wasting Licenses
|
||||
- **Reported By:** M365 user export analysis (2026-03-08)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** 12 generic/role-based accounts are set up as regular licensed users instead of shared mailboxes: accounting@, accountingassistant@, boadmin@, frontdesk@, hr@, memcarereceptionist@, security@, Training@, Kitchenipad@, medtech@, nurse@, transportation@. Each consumes a Business Standard or Exchange Online Essentials license.
|
||||
- **Root Cause:** Previous admin created role accounts as regular users rather than shared mailboxes.
|
||||
- **Resolution:** PLANNED — For each: convert to shared mailbox (`Set-Mailbox -Type Shared`), remove license, grant FullAccess permission to appropriate users. No data loss — mailbox contents are preserved during conversion.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - AD ↔ M365 Identity Mismatch: Tamra Johnson → Matthews
|
||||
- **Reported By:** M365/AD cross-reference (2026-03-08)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** AD account is Tamra.Johnson. M365 UPN is tamra.matthews@cascadestucson.com (name changed, likely married). The tamra.johnson@ alias still works for email but the display name and UPN are mismatched between AD and M365.
|
||||
- **Root Cause:** Name change updated in M365 but not in AD.
|
||||
- **Resolution:** PLANNED — Update AD: rename Tamra.Johnson to Tamra.Matthews (Set-ADUser, Rename-ADObject). Coordinate timing — may affect drive mappings, profile path, etc. if already domain-joined.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - 13 AD Users Have No M365 Account
|
||||
- **Reported By:** M365/AD cross-reference (2026-03-08)
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** 13 AD user accounts have no matching M365 account. These users cannot receive email at cascadestucson.com.
|
||||
- **Root Cause:** Hourly/floor staff (front desk, courtesy patrol, transportation) given AD accounts but not M365 licenses.
|
||||
- **Resolution:** CONFIRMED 2026-03-10 — HR verified all are current employees. Roles: Front Desk/Courtesy Patrol (Sebastian.Leon, Sheldon.Gardfrey, Cathy.Kingston, Ray.Rai), MC Front Desk (Michelle.Shestko), Transportation (Richard.Adams, Julian.Crim, Christopher.Holik), Housekeeping (Guadalupe.Sanchez — already has M365 as lupe.sanchez@). Shontiel.Nunn transferring soon. Alyssa.Brooks already has M365. Still need to determine if remaining users need email.
|
||||
- **Time to Resolve:** Pending — determine email needs, free licenses via role account cleanup first
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - nick pavloff: New M365 User, No AD Account
|
||||
- **Reported By:** M365 user export (2026-03-08)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** nick.pavloff@cascadestucson.com was created 2026-03-07 with a Business Standard license. No matching AD account exists. User cannot log into domain-joined PCs or access file shares.
|
||||
- **Root Cause:** New hire added to M365 but AD account not yet created.
|
||||
- **Resolution:** PLANNED — Create AD account (Nick.Pavloff) in appropriate department OU. Determine department and group membership. Add to domain join list if they have a dedicated PC.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - Kristiana Dowse: M365 Licensed, Not in AD
|
||||
- **Reported By:** M365 user export (2026-03-08)
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** kristiana.dowse@cascadestucson.com has a Business Standard license (created 2022-03-02, password never changed from default). No matching AD account exists. Unknown if current employee or former.
|
||||
- **Root Cause:** Former employee whose M365 was never cleaned up.
|
||||
- **Resolution:** CONFIRMED 2026-03-10 — HR confirmed DELETE. Block sign-in, remove license, delete account. Frees 1 Business Standard license.
|
||||
- **Time to Resolve:** Pending — next M365 cleanup session
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - Sandra Fish Still Global Admin on M365 Tenant
|
||||
- **Reported By:** M365 admin portal audit (2026-03-08)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** admin@NETORGFT4257522.onmicrosoft.com (Sandra Fish) holds the Entra ID P2 license and appears to be the original/primary global admin. Sandra Fish is listed as previous owner/manager.
|
||||
- **Root Cause:** Tenant was created under Sandra Fish's account and admin access was never transitioned.
|
||||
- **Resolution:** OPEN — Verify with Howard: should Sandra Fish retain global admin? If she is no longer involved, create a new break-glass admin account, transfer global admin, and downgrade or remove her access.
|
||||
- **Time to Resolve:** Pending client discussion
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - 3 Former Employee Shared Mailboxes Still Active
|
||||
- **Reported By:** M365 admin portal (2026-03-08)
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** Shared mailboxes exist for Anna Pitzlin, Jeff Bristol, and Nela Durut-Azizi — all confirmed former employees. Jeff Bristol and Nela Durut-Azizi have sign-in blocked. Anna Pitzlin's is unlicensed.
|
||||
- **Root Cause:** Accounts were converted to shared mailboxes (or created as such) but never cleaned up.
|
||||
- **Resolution:** CONFIRMED 2026-03-10 — HR says Anna and Nela were forwarded to Meredith but can now be deleted. Jeff Bristol still pending (Lauren Hasselman replaced him — may need forwarding).
|
||||
- **Time to Resolve:** Pending — next M365 cleanup session
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - "howaed" Typo Guest Account in M365
|
||||
- **Reported By:** M365 user export (2026-03-08)
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** External guest account howaed@azcomputerguru.com exists alongside the correct howard@azcomputerguru.com. The "howaed" account is a typo.
|
||||
- **Root Cause:** Typo when inviting external guest.
|
||||
- **Resolution:** PLANNED — Delete the howaed@azcomputerguru.com guest account from Entra ID.
|
||||
- **Time to Resolve:** Quick fix — next M365 session
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-08 - AD and M365 Are Completely Separate Identity Systems
|
||||
- **Reported By:** M365/AD cross-reference (2026-03-08)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** DirSync/Entra Connect is not configured. AD accounts and M365 accounts are completely independent — users have different passwords, no SSO, and no automatic provisioning. Changes in one system (name changes, new hires, terminations) must be manually replicated to the other.
|
||||
- **Root Cause:** Entra Connect was never set up.
|
||||
- **Resolution:** OPEN — Evaluate Entra Connect for hybrid identity. Consider: does the environment benefit from SSO? With only 6 domain-joined PCs currently, the value is limited. Revisit after Phase 3 domain joins bring more PCs online. For now, document the manual mapping in `cloud/m365.md`.
|
||||
- **Time to Resolve:** Pending — evaluate after Phase 3
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-10 - Synology NAS Stores PHI Without Audit Controls
|
||||
- **Reported By:** HIPAA compliance review (2026-03-10)
|
||||
- **Severity:** Critical
|
||||
- **Symptoms:** Synology NAS (cascadesDS, 192.168.0.120) stores PHI (resident/facility data). Filesystem is ext4 — cannot enable Windows audit logging. Access via SMB but no read/write audit trail. HIPAA §164.312(b) requires audit controls on PHI storage.
|
||||
- **Root Cause:** Synology was never designed with compliance in mind. ext4 cannot support NTFS audit logging.
|
||||
- **Resolution:** PLANNED — Migration Phase 4: Move all Synology shares to CS-SERVER NTFS volumes. Enable Advanced Audit Logging on PHI shares. Retire Synology from PHI scope (becomes backup target only).
|
||||
- **Time to Resolve:** Phase 4
|
||||
- **Lessons Learned:** PHI storage must support audit logging. NTFS + AD group permissions provide compliance-grade access control.
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-10 - No Microsoft BAA Signed for M365
|
||||
- **Reported By:** HIPAA compliance review (2026-03-10)
|
||||
- **Severity:** High
|
||||
- **Symptoms:** M365 email (cascadestucson.com) may contain PHI in messages and attachments. No Business Associate Agreement (BAA) has been signed with Microsoft. HIPAA §164.308(b)(1) requires BAA with all business associates who handle PHI.
|
||||
- **Root Cause:** BAA never signed by previous MSP or management.
|
||||
- **Resolution:** PLANNED — Sign Microsoft HIPAA BAA via M365 Admin Center → Settings → Org Settings → Security & Privacy. Also verify BAA exists with ALIS (go-alis.com).
|
||||
- **Time to Resolve:** Quick — can be done in M365 admin portal
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-10 - No MFA Enabled on M365
|
||||
- **Reported By:** HIPAA compliance review (2026-03-10)
|
||||
- **Severity:** High
|
||||
- **Symptoms:** No MFA (Security Defaults or Conditional Access) configured on M365 tenant. Staff accounts that access ALIS and email with PHI are protected only by passwords. HIPAA §164.312(d) requires person authentication controls.
|
||||
- **Root Cause:** MFA never enabled by previous MSP.
|
||||
- **Resolution:** PLANNED — Enable Security Defaults in Entra ID (free). All users will be prompted to set up MFA on next login.
|
||||
- **Time to Resolve:** Quick — 5 minutes to enable, users set up on next login
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-10 - Kitchen iPads and Thermal Printers Not Inventoried or Isolated
|
||||
- **Reported By:** HIPAA compliance review (2026-03-10)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** 9 kitchen iPads are on INTERNAL VLAN (10.0.20.x) with full access to staff resources. They are food-service only (NOT medical — used for taking food orders). Kitchen thermal receipt printers exist but are not inventoried (count, IP, model unknown). iPads should be restricted to kitchen printers only.
|
||||
- **Root Cause:** Kitchen operations not segmented from staff network.
|
||||
- **Resolution:** PLANNED — Phase 1.1b:
|
||||
1. Onsite: inventory kitchen thermal printers (count, model, IP, MAC, connection type)
|
||||
2. Create firewall rules restricting kitchen iPad MACs to kitchen printer IPs only
|
||||
3. Block iPad access to servers, NAS, and staff resources
|
||||
4. Allow internet (80/443) for app updates
|
||||
- **Time to Resolve:** Pending onsite visit
|
||||
- **Lessons Learned:** Non-PHI devices should still be isolated to prevent lateral movement into PHI networks.
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-10 - ALIS BAA Status Unknown
|
||||
- **Reported By:** HIPAA compliance review (2026-03-10)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** Nurses and medtechs access clinical records via ALIS (go-alis.com) through web browsers. ALIS is a cloud SaaS handling PHI. HIPAA §164.308(b)(1) requires a BAA with ALIS as a business associate. Unknown if Cascades has a signed BAA with ALIS.
|
||||
- **Root Cause:** Documentation gap — BAA status never verified.
|
||||
- **Resolution:** OPEN — Ask management if a BAA exists with ALIS. If not, one must be executed before continuing to use the service.
|
||||
- **Time to Resolve:** Pending management verification
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-19 - Lauren Hasselman Needs Sales Share Access
|
||||
- **Reported By:** Howard
|
||||
- **Severity:** Low
|
||||
- **Symptoms:** Lauren Hasselman (Business Office Director) does not have access to the Sales share on CS-SERVER.
|
||||
- **Root Cause:** Permissions not granted when Lauren replaced Jeff Bristol.
|
||||
- **Resolution:** OPEN — Grant Lauren access to \\CS-SERVER\Sales share. Add her AD account to the appropriate security group or add NTFS permissions directly.
|
||||
- **Time to Resolve:** Pending
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
### 2026-03-19 - Long Print Lag in Room 405
|
||||
- **Reported By:** Howard (staff report)
|
||||
- **Severity:** Medium
|
||||
- **Symptoms:** Resident room 405 experiencing long delays when printing. Specific printer unknown — likely a resident room printer.
|
||||
- **Root Cause:** Unknown — could be WiFi signal, printer sleep mode, DNS resolution delay, or network path issue through per-room VLAN routing.
|
||||
- **Resolution:** OPEN — Investigate onsite:
|
||||
1. Identify which printer room 405 is printing to
|
||||
2. Check network path (VLAN 10.4.5.0/28 → printer IP)
|
||||
3. Test ping/latency from room AP to printer
|
||||
4. Check printer sleep/power save settings
|
||||
5. Verify DNS resolution if printing by hostname
|
||||
- **Time to Resolve:** Pending onsite visit
|
||||
- **Lessons Learned:** N/A
|
||||
|
||||
---
|
||||
|
||||
<!-- Add new issues above this line, newest first -->
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user