WRKLOG-2026-06-08

Summary

Sunday. Massive productivity session. CLAUDE.md review and correction (7 fixes). 13-week PeopleSoft timesheet backfill (520 hours, Mar 09 – Jun 05) with scalable partial architecture. Three P1 investigations launched: spam bypass (SCL 9 SFV:SKA override — user safe sender list), Intune hybrid domain join cert auth failure (forget/rejoin pattern), and rsyslog centralized collector (CHLXSYSLOG01 Debian 13, first login, ASA syslog config). Fixed build-antora-page.sh nested include resolution — PDFs went from 172K to 1.8MB with full content. rsyslog-ops command reference created in d001 with ISO 8601 + MSWinEventLog parsing. API rate limits reference created. Project audit revealed P0/P1/P2 trackers 47 days stale.

URGENT - All Domains

Carryover Backlog (CRITICAL)

Task Details Origin Days Status

MSCHAPv2 Migration Report

Report due. 6-sheet Standard Report (exec summary, trend, waves, device detail, stale, policy match). Sheet 6 added 05-14: policy match by protocol for removal planning + anonymous identity validation. Migration window 2026-05-04 to 2026-05-30. ~6,227 devices, 5 waves.

2026-04-17

57

P0 - DUE — run report this week

Abnormal Security — ✅ COMPLETE

CR-2026-05-07-abnormal-read-write. CAB approved 2026-05-12. Implemented successfully 2026-05-13. Read/write enabled for pilot group. Post-deployment validation pending.

2026-05-07

37

✅ IMPLEMENTED — post-validation pending

SIEM QRadar → Sentinel Migration

Lead role. Monad console error RESOLVED 2026-05-12 — secrets configured in CHLA production tenant. ISE secure syslog integration in progress — cert imported, remote logging target configured, streaming errors under investigation. Blocking: DCR not created (Rule ID + Stream Name). Azure private network policy unresolved. Victor + Mauricio action.

2026-04-10

64

P0 - ACTIVE — ISE syslog + DCR blocking

Monad Pipeline Evaluation

Sentinel output connector. Console error resolved. 3 of 6 values configured. Remaining: Endpoint URL (have it), Rule ID + Stream Name (need DCR). ISE Remote Logging Target configured 2026-05-18 — TLS cert imported, secure syslog target created. Streaming errors in Monad console under investigation.

2026-03-11

94

P0 - ACTIVE — ISE integration in progress

Guest Redirect ACL

Guest redirect ACL work needed. Related to Mandiant remediation findings.

2026-05-12

32

P0 - TODO

ISE Patch 10 (CVE-2026-20147 CVSS 9.9)

ISE 3.2 Patch 10. Supersedes Patch 9. 61 days on a CVSS 9.9 — schedule maintenance window. Write CR if needed.

2026-03-12

93

P0 - OVERDUE — schedule immediately

k3s NAT verification

NAT rule 170 for 10.42.0.0/16 pod network - test internet connectivity. 64 days — test this week or defer to Q3.

2026-03-09

96

P0 - BLOCKING — TRIAGE: schedule or defer

Wazuh indexer recovery

Restart pod after NAT confirmed working - SIEM visibility blocked. Blocked by k3s NAT — cannot proceed until above resolved.

2026-03-09

96

P0 - Blocked by k3s

Strongline Gateway VLAN fix

8 devices in wrong identity group (David Rukiza assigned)

2026-03-16

89

P0 - TODO

TCP Clocks deployment

ISE identity group validation, query outputs, comms with team. Active d001 data Apr 22-23.

2026-04-22

52

P0 - ACTIVE

IoT Dr. Kim — recurring

Sleep study devices (Apr 15-16), watches recurrence (Apr 22). 5 incident versions in d001. Validate iPSK enrollment.

2026-04-15

59

P0 - RECURRING

Murus Portae (WAF) — Phase 0

FMC cert expired, ACP returns zero rules. d001: zone map, architecture D2, FMC API reference, ops script.

2026-04-16

58

P0 - INVESTIGATING

Vocera EAP-TLS Supplicant Fix

~10 phones failing 802.1X, missing supplicant config. 61 days — schedule with clinical engineering team.

2026-03-12

93

P1 - TODO — schedule

ISE MnT Messaging Service

Enable "Use ISE Messaging Service for UDP syslogs delivery". 61 days — low risk, schedule with ISE Patch 10 maintenance window.

2026-03-12

93

P2 - BUNDLE with Patch 10

Professional backlog remains critical. Check Days column for priorities.

BLOCKERS — Fix Immediately

Task Details Origin Days Impact

Z Fold 7 Termux

gopass and SSH not working

2026-03-10

58

BLOCKER — Cannot access passwords on mobile

gopass v3 organization

Inconsistent structure, poor key-value usage

2026-03-20

48

Inefficient password management, no aggregation

Git history scrub — sensitive personal terms

Plaintext references to personal legal matters in committed worklogs (WRKLOG-2026-03-14, WRKLOG-2026-04-18). Forward-fixed but old commits still contain strings. Requires git filter-repo + force-push. See runbook below.

2026-04-22

15

SECURITY — sensitive terms in public git history

Runbook: Git History Scrub (d000 Personal Terms)

Problem: Two committed worklogs contained plaintext references to personal legal matters. The files have been edited (forward-fix), but git history retains the original text in prior commits.

Affected commits: Any commit touching these files:

# Identify affected commits
git log --oneline -- \
  docs/modules/ROOT/pages/2026/03/WRKLOG-2026-03-14.adoc \
  docs/modules/ROOT/pages/2026/04/WRKLOG-2026-04-18.adoc

Scrub procedure:

# 1. BEFORE: Full backup of the repo
cp -a ~/atelier/_bibliotheca/domus-captures ~/atelier/_bibliotheca/domus-captures.bak

# 2. Install git-filter-repo (if not present)
# Arch: pacman -S git-filter-repo
# pip: pip install git-filter-repo

# 3. Create expressions file for replacement
cat > /tmp/scrub-expressions.txt << 'EXPR'
regex:(?i)divorce==[REDACTED]
regex:(?i)dissolutio(?!n\.adoc\.age)==[REDACTED-LEGAL]
regex:(?i)iliana==[REDACTED-NAME]
regex:(?i)angulo-arreola==[REDACTED-NAME]
regex:legal-divorce-notes\.age==legal-notes.age
regex:1099-NEC-iliana==1099-NEC
EXPR

# 4. Verify before (dry run — count matches in history)
git log -p --all -S 'divorce' -- '*.adoc' | grep -c 'divorce' || echo "0 matches"
git log -p --all -S 'iliana' -- '*.adoc' | grep -c 'iliana' || echo "0 matches"

# 5. Run filter-repo (DESTRUCTIVE — rewrites all commit hashes)
git filter-repo --replace-text /tmp/scrub-expressions.txt --force

# 6. Verify after
git log -p --all -S 'divorce' -- '*.adoc' | grep -c 'divorce' || echo "0 matches — CLEAN"
git log -p --all -S 'iliana' -- '*.adoc' | grep -c 'iliana' || echo "0 matches — CLEAN"

# 7. Re-add remotes (filter-repo removes them)
git remote add origin git@github.com:<user>/domus-captures.git
# Add any other remotes (Gitea, etc.)

# 8. Force-push to all remotes (DESTRUCTIVE — overwrites remote history)
git remote | xargs -I{} git push {} main --force

# 9. Clean up
rm /tmp/scrub-expressions.txt
rm -rf ~/atelier/_bibliotheca/domus-captures.bak  # only after verifying

Post-scrub checklist:

  • Backup created before running

  • git filter-repo installed

  • Expressions file reviewed — no false positives (e.g., Don Quijote "Angulo el Malo" is in segunda-parte/texto/texto-011.adoc — the regex targets angulo-arreola specifically to avoid this)

  • Dry-run counts match expectations

  • Filter-repo executed

  • Post-scrub verification shows 0 matches

  • Remotes re-added

  • Force-pushed to all remotes

  • Cloudflare Pages rebuild verified

  • Local clones on other machines re-cloned or git fetch --all && git reset --hard origin/main

  • Backup removed

URGENT - Requires Immediate Action

Item Details Deadline Status Impact

Housing Search

Granada Hills area - apartments/rooms

TBD

In Progress

Quality of life, commute

2025 Tax — IRS Transcript Review

MFJ filed 2026-04-22. Pull IRS Return Transcript to verify contents. Consult attorney re: Form 8857 (Innocent Spouse Relief). Details in encrypted case file.

Before attorney meeting

In Progress

Financial — liability exposure. See encrypted D000 case file.

Rack Relocation

Physical move of server rack. CR written: CR-2026-04-18 (pending in infra-ops). Borg backup completed. VM XML dumps, switch save, shutdown/startup procedure documented.

TBD

Pending

Infrastructure downtime — all services offline during move

D000 Legal Planning

Encrypted D000 case file. Open: dissolutio-open. Close: dissolutio-close. 19 partials + assembler. PDF build for attorney handoff. Critical deadline: Jan 2029.

Before Jan 2029

Active — escalating

Life transition — see case file for details

Credit Report Review

Pull reports from all 3 bureaus via annualcreditreport.com. Verify no unknown joint accounts or debts. Credentials in gopass: v3/personal/finance/credit/annual_credit_report

TBD

In Progress

Financial discovery — FL-142 preparation

Gopass Security Audit

Rotate passwords on shared/known accounts. Add 2FA backup codes to v3/personal/recovery/. Create missing government entries (IRS, SSA, VA, DMV). Add last_login field to active entries.

TBD

Pending

Digital security — pre-filing preparation

Subscription Audit

Download 3 months bank/CC statements (Chase, NFCU, USAA). Identify all recurring charges. Cancel unnecessary. Document active subscriptions for FL-150.

TBD

Pending

Financial — expense documentation

401(k) Enrollment

Enroll in CHLA 401(k) immediately. Post-separation contributions are 100% separate property. Reduces gross income for support calculations. Max 2026: $23,500/yr.

In progress (started 5/4)

In Progress

Financial — support calculation + retirement

URGENT — Performance Review Certifications

Certification Provider Deadline Status Impact

CISSP

ISC² — Certified Information Systems Security Professional

July 12, 2026

ACTIVE — Week 2 of 10 (Project)

Required for performance review. 10-week accelerated plan.

RHCSA 9

Red Hat Certified System Administrator

Q3 2026

ACTIVE — 21-phase curriculum (Project)

After CISSP. Required for performance review.

CISSP: 41 days remaining (exam July 12). Domain 1 study in progress. Schedule exam today (06-01).

Early Morning - 5:30am

Regex Training (CRITICAL CARRYOVER)

  • Session 3 - Character classes, word boundaries

  • Practice drills from regex-mastery curriculum

  • Status: 52 days carried over (since 2026-03-16) — CRITICAL

Regex training continues to slip. This is the foundation for all CLI mastery.

Daily Notes

Encrypted File Placement (2026-06-08 session captures)

File Location Content

intune-cert-commands-2026-06-08.adoc.age

data/d001/investigations/2026-06-08-intune-cert-auth/

P1 Intune hybrid join cert investigation — client/GPO/SCEP/PKCS/ISE commands

rsyslog-commands.adoc.age

data/d001/projects/siem-qradar-to-sentinel/scripts/

CHLXSYSLOG01 operational command reference — health checks, live dashboards, parsing

rsyslog-commands-test.adoc.age

data/d001/projects/siem-qradar-to-sentinel/scripts/

First login session capture — system recon, disk, network, listeners

syslog-2026-06-08.adoc.age

data/d001/projects/siem-qradar-to-sentinel/

Full session: Monad API discovery, ASA logging config (FP-2140 + 5515), rsyslog Debian server

Decrypt any file for reference
decrypt-file data/d001/investigations/2026-06-08-intune-cert-auth/intune-cert-commands-2026-06-08.adoc.age
decrypt-file data/d001/projects/siem-qradar-to-sentinel/scripts/rsyslog-commands.adoc.age
decrypt-file data/d001/projects/siem-qradar-to-sentinel/scripts/rsyslog-commands-test.adoc.age
decrypt-file data/d001/projects/siem-qradar-to-sentinel/syslog-2026-06-08.adoc.age

Triage Status

Item Status Destination

⚡ CHARGE TIME IN PEOPLESOFT — Monday critical

❌ not started

PeopleSoft → submit hours before EOD

Install BYOD P12 cert on ZFold7 (9C:83:06:CE:89:46)

🟡 cert issued, needs P12 bundle transfer + install on device

Phase 8: BYOD Certs

Fix dsec embedded quotes in vault unseal keys

❌ not started

dsec edit d000 dev/vault — remove wrapping double quotes

Rejoin AD from ISE GUI

❌ not started

Phase 6 — DOMUS_AD join point

Fix NAS SSH config (adminerosado → evanusmodestus + IdentitiesOnly)

❌ not started

~/.ssh/config line 245

Fix WLC SSH config (add PubkeyAuthentication no)

❌ not started

~/.ssh/config — add Host 9800-wlc-01 block

Add NTP rule to vyos-02 (same as vyos-01 rule 45)

❌ not started

configure → set firewall ipv4 name MGMT_LOCAL rule 45

Add kvm-01 NAS mounts to /etc/fstab

❌ not started

10.50.1.70:/volume1/isos → /mnt/nas/isos

Secondary NAS mount found unsynced — resync failed

❌ blocked

Investigate mount/NFS state, attempt manual resync

Generalize build-antora-page.sh for HTML output

❌ not started

scripts/build-antora-page.sh

Explore AsciiDoc CSV tables (csv format option)

❌ not started

codex/documentation/asciidoc.adoc or discoveries/

Printer unreachable — iPSK auth + VLAN filtering

❌ blocked

Depends on ISE rotation completing

CLAUDE.md review — updated (this session)

✅ done

STD-024, file naming, skeleton, Makefile, invariants fixed

P1: Spam bypass — SCL 9 delivered to inbox (SFV:SKA)

🟡 investigation file created, commands ready

spam-bypass-investigation.adoc — run Phase 1 on work machine

P1: Intune hybrid join cert auth failure

🟡 investigation file created, bulk ISE queries ready

intune-cert-investigation.adoc — Anthony Martinez assisting

rsyslog CHLXSYSLOG01 — first login, ASA syslog config

🟡 server online, Windows logs arriving, ASA logs starting

rsyslog-asa-troubleshooting.adoc + d001 rsyslog-ops.adoc.age

PeopleSoft 13-week timesheet backfill

✅ done

13 partials in peoplesoft-codes/, wired to PRJ page

build-antora-page.sh nested include fix

✅ done

Recursive resolution, PDFs 172K → 2.2MB

API rate limits reference

✅ done

d001/api/max-api-calls.adoc.age

Project audit (CHLA + personal)

✅ done

P0/P1/P2 47 days stale, 6 missing projects, refresh needed

Linux Remediation — reuse Shahab model for enterprise scale

🟡 inventory found, summary built

d001/linux-research/ + domus-ise-linux + enterprise-linux-802.1x + scripts/

NEW: iTrack → Jira (Atlassian) migration

🟡 announced — team must become proficient

New project — needs codes.adoc entry, d001 scaffolding

Ad-Hoc Requests

Ad-Hoc Requests

Capture walk-ups, Teams pings, and unplanned work here.

Linux Remediation — Enterprise Deployment Model

Executive Summary

The enterprise Linux remediation effort can leverage a proven 6-phase deployment model already validated with Dr. Shahab Asgharzadeh’s workstation (Spatial Biology & Genomics Core). The workflow, scripts, ISE policies, and troubleshooting runbooks are complete and documented across 4 repositories. This is not a greenfield build — it’s a scale-out of a working implementation.

Proven Deployment: Dr. Shahab (Jan 2026)
Field Value

Subject

Dr. Shahab Asgharzadeh — TSRI SBG

Date

2026-01-26

Deployment Record

DEPLOY-2026-01-26-shahab-linux-workstation.adoc

Auth Method

EAP-TLS (certificate-based 802.1X)

AD Integration

SSSD domain join

Cert Source

Enterprise CA via cert enrollment

Result

Successful — wired 802.1X, AD login, dACL enforcement

The 6-Phase Model
Phase Description Deliverable Status

0: Prerequisites

OS baseline, package install, network access

endpoint/phase-0-prereqs.adoc

✅ Proven

1: AD Validation

Verify AD reachability, DNS, Kerberos, LDAP

endpoint/phase-1-ad-validation.adoc

✅ Proven

2: Domain Join

SSSD configuration, realm join, PAM integration

endpoint/phase-2-domain-join.adoc

✅ Proven

3: Certificate Ops

CA trust import, client cert enrollment, chain validation

endpoint/phase-3-certificate-ops.adoc

✅ Proven

4: 802.1X Config

NetworkManager nmcli EAP-TLS profile, wired and/or wireless

endpoint/phase-4-dot1x-config.adoc

✅ Proven

5: Security Hardening

UFW, dACL enforcement, privilege separation

endpoint/phase-5-security-hardening.adoc

✅ Proven

6: Validation

End-to-end auth test, ISE verification, DataConnect confirmation

endpoint/phase-6-validation.adoc

✅ Proven

Supporting Assets — Already Built
Scripts (ready to use)
Script Purpose

scripts/ise-batch-onboard.sh

Batch onboard MACs to ISE identity groups from file

scripts/ise-check-macs.sh

Validate MAC addresses against ISE (ERS + DataConnect)

scripts/ise-endpoint-create.sh

Create single endpoint in ISE via ERS API

scripts/ise-endpoint-get.sh

Query endpoint details from ISE

scripts/ise-endpoint-move.sh

Move endpoint between identity groups

scripts/ise-group-list.sh

List all ISE endpoint identity groups

scripts/ise-policy-discover.sh

Discover ISE policy sets and auth rules

SQL Queries (DataConnect — inventory & validation)
Query Purpose

sql/linux-inventory-summary.sql

All Linux endpoints — count, profile, auth status

sql/linux-inventory-ise-profiler.sql

ISE profiler-detected Linux devices

sql/linux-inventory-ise-radius.sql

Linux devices with RADIUS auth history

sql/linux-inventory-ise-unknown.sql

Unidentified Linux endpoints (remediation targets)

Documentation Repositories
Repository Content Size

domus-ise-linux

Full NetworkManager wired/wireless 802.1X config, cert enrollment, troubleshooting

12 pages (34KB+ each)

enterprise-linux-802.1x

Deployment checklist, CLI reference, validation runbook, prerequisites

4 deployment pages + runbooks

domus-linux-ops

nmcli reference, AD domain join runbook, cert operations

General Linux ops

d001/projects/linux-research/

Shahab-specific playbook, deployment guide, status tracking, team docs

30+ files (encrypted)

ISE Team Documentation (encrypted in d001)
File Content

team/phase-1-ise-gui.adoc

ISE policy set creation — authN/authZ rules for Linux

team/phase-4-dot1x-client.adoc

Client-side config handoff for endpoint team

team/phase-5-validation.adoc

ISE-side validation steps

team/phase-6-hardening.adoc

Switch port config, dACL, monitor mode → closed mode

team/switch-config.adoc

IOS-XE switch port templates for 802.1X

team/communication-log.adoc

Project communication history

team/troubleshooting.adoc

ISE-side troubleshooting (Live Log, policy trace)

team/rollback.adoc

Rollback procedures for failed deployments

Appendices (encrypted in d001)
File Content

endpoint/appendix-checklist.adoc

Pre-deployment checklist per device

endpoint/appendix-commands.adoc

CLI quick reference for field engineers

endpoint/appendix-files.adoc

Config file locations and templates

endpoint/appendix-risks.adoc

Risk register — known failure modes and mitigations

endpoint/emergency.adoc

Emergency disconnect / bypass procedures

endpoint/rollback.adoc

Client-side rollback (remove 802.1X, restore open access)

endpoint/troubleshoot-eaptls.adoc

EAP-TLS handshake failures, cert chain issues

endpoint/troubleshoot-ad-login.adoc

AD/SSSD login failures post-domain-join

endpoint/troubleshoot-dacl.adoc

dACL not applied, wrong VLAN, access denied

Scaling Strategy
Step Action

1. Inventory

Run sql/linux-inventory-summary.sql via DataConnect — total Linux endpoints, profiled vs unknown

2. Prioritize

Group by department, criticality, network zone. Start with research labs (Shahab model fits directly)

3. Batch onboard

ise-batch-onboard.sh with MAC file per department — stage in ISE before touching endpoints

4. Deploy per phase

Follow 6-phase model per device. Field engineer uses appendix-commands.adoc as CLI cheat sheet

5. Validate

ise-check-macs.sh + DataConnect query confirms each device passes EAP-TLS

6. Harden

Switch from monitor mode to closed mode per switch port. team/switch-config.adoc has templates

Known Blocker

nmcli certificate "password required" prompt — documented during Shahab deployment. Workaround exists in endpoint/phase-4-dot1x-config.adoc. This is the P0 item that’s been open 72+ days. Must be resolved before scaling beyond individual deployments.

Access Commands
Decrypt the full project (on your workstation)
d001 open linux-research
Run the inventory query
dsource d001 dev/network/ise
dc-run-sql data/d001/projects/linux-research/sql/linux-inventory-summary.sql
Build the deployment guide as PDF
# After decrypting
bat data/d001/projects/linux-research/linux-eaptls-deployment-guide.adoc

Investigation: Intune Auto-Enroll — Cert-Based WiFi Auth Failure

Incident Summary
Field Value

Date Reported

2026-06-08

Symptom

Intune auto-enrolled devices fail WiFi auth. Forget + rejoin fixes it.

Scope

Hybrid Azure AD joined devices (GPO + Intune)

Blamed System

ISE (unconfirmed — ISE does NOT push certs, it validates them)

Working Hypothesis

Cert delivery timing or GPO/Intune WiFi profile conflict

Key Fact

Forget + rejoin fixes it → ISE policy is correct. The client is presenting the wrong cert or no cert.

Talking Points
  • ISE does NOT push certificates to endpoints — it validates what the supplicant presents

  • "Forget + rejoin fixes it" proves ISE policy works — same device, same policy, passes after reconnect

  • Hybrid domain join = TWO cert sources (GPO AD CS + Intune SCEP/PKCS) — supplicant must choose correctly

  • Root cause is on the client side: cert store, WiFi profile config, or GPO/Intune conflict


Part 1: Client-Side Investigation (run on affected device)

Phase 1: Certificate Store Audit
Machine Personal Store
All certs in machine store
Get-ChildItem Cert:\LocalMachine\My | Format-Table Subject, Issuer, NotBefore, NotAfter, Thumbprint, HasPrivateKey -AutoSize
Client auth certs only (what the supplicant will consider for 802.1X)
Get-ChildItem Cert:\LocalMachine\My | Where-Object {
    $_.EnhancedKeyUsageList.ObjectId -contains "1.3.6.1.5.5.7.3.2"
} | Format-List Subject, Issuer, NotBefore, NotAfter, Thumbprint, SerialNumber, @{N='EKU';E={($_.EnhancedKeyUsageList.FriendlyName) -join ", "}}, @{N='Template';E={($_.Extensions | Where-Object {$_.Oid.FriendlyName -eq 'Certificate Template Information'}).Format(0)}}
Expired certs in machine store
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.NotAfter -lt (Get-Date) } | Format-Table Subject, Issuer, NotAfter, Thumbprint -AutoSize
User Personal Store
All certs in user store
Get-ChildItem Cert:\CurrentUser\My | Format-Table Subject, Issuer, NotBefore, NotAfter, Thumbprint, HasPrivateKey -AutoSize
Client auth certs only — user store
Get-ChildItem Cert:\CurrentUser\My | Where-Object {
    $_.EnhancedKeyUsageList.ObjectId -contains "1.3.6.1.5.5.7.3.2"
} | Format-List Subject, Issuer, NotBefore, NotAfter, Thumbprint, SerialNumber, @{N='EKU';E={($_.EnhancedKeyUsageList.FriendlyName) -join ", "}}
GPO vs Intune Cert — Which CA Issued Each?
Group all client auth certs by issuer — instant GPO vs Intune view
@("Cert:\CurrentUser\My", "Cert:\LocalMachine\My") | ForEach-Object {
    $store = $_
    Get-ChildItem $store | Where-Object {
        $_.EnhancedKeyUsageList.ObjectId -contains "1.3.6.1.5.5.7.3.2"
    } | Select-Object @{N='Store';E={$store}}, Subject, Issuer, NotAfter, @{N='DaysLeft';E={($_.NotAfter - (Get-Date)).Days}}, Thumbprint
} | Format-Table -AutoSize
Chain validation — does each cert chain to a trusted root?
Get-ChildItem Cert:\LocalMachine\My | Where-Object {
    $_.EnhancedKeyUsageList.ObjectId -contains "1.3.6.1.5.5.7.3.2"
} | ForEach-Object {
    $chain = New-Object Security.Cryptography.X509Certificates.X509Chain
    $built = $chain.Build($_)
    [PSCustomObject]@{
        Subject = $_.Subject
        Issuer = $_.Issuer
        ChainValid = $built
        ChainStatus = if($built){"OK"}else{($chain.ChainStatus.StatusInformation) -join "; "}
        ChainLength = $chain.ChainElements.Count
    }
} | Format-Table -AutoSize
Trusted Root & Intermediate CA Stores
Trusted roots — is the issuing CA trusted?
Get-ChildItem Cert:\LocalMachine\Root | Where-Object {
    $_.Subject -match "CHLA|Intune|SCEP|ISE|DigiCert|Enterprise"
} | Format-Table Subject, NotAfter, Thumbprint -AutoSize
Intermediate CAs
Get-ChildItem Cert:\LocalMachine\CA | Where-Object {
    $_.Subject -match "CHLA|Intune|SCEP|ISE|Enterprise"
} | Format-Table Subject, Issuer, NotAfter, Thumbprint -AutoSize

Phase 2: WiFi Profile Inspection (netsh — no GUI)
List and Inspect
List all WiFi profiles
netsh wlan show profiles
CHLA-Staff — full config including cert selection
netsh wlan show profile name="CHLA-Staff" key=clear
CHLA_Remote — full config
netsh wlan show profile name="CHLA_Remote" key=clear
Current connection status — what profile is active NOW?
netsh wlan show interfaces
Show wlan xml profile information
foreach ($p in "CHLA_Staff","CHLA-Remote") {
  netsh wlan export profile name="$p" folder=$env:TEMP key=clear > $null

  $f = Get-ChildItem $env:TEMP "Wi-Fi-$p*.xml" |
       Sort-Object LastWriteTime -Descending |
       Select-Object -First 1

  yq -o=json '.' $f.FullName |
    jq '
      def norm:
        walk(
          if type == "object" then
            with_entries(select(.key | startswith("+@") | not)) |
            if has("+content") and (keys | length == 1)
              then .["+content"]
              else .
            end
          else .
          end
        );

      norm
    '

  Remove-Item $f.FullName
}
output
{
  "+p_xml": "version=\"1.0\"",
  "WLANProfile": {
    "name": "CHLA_Staff",
    "SSIDConfig": {
      "SSID": {
        "hex": "43484C415F5374616666",
        "name": "CHLA_Staff"
      },
      "nonBroadcast": "false"
    },
    "connectionType": "ESS",
    "connectionMode": "auto",
    "autoSwitch": "true",
    "MSM": {
      "security": {
        "authEncryption": {
          "authentication": "WPA2",
          "encryption": "AES",
          "useOneX": "true"
        },
        "PMKCacheMode": "enabled",
        "PMKCacheTTL": "720",
        "PMKCacheSize": "128",
        "preAuthThrottle": "3",
        "OneX": {
          "heldPeriod": "1",
          "authPeriod": "30",
          "startPeriod": "5",
          "maxStart": "5",
          "maxAuthFailures": "5",
          "authMode": "machineOrUser",
          "EAPConfig": {
            "EapHostConfig": {
              "EapMethod": {
                "Type": "55",
                "VendorId": "0",
                "VendorType": "0",
                "AuthorId": "311"
              },
              "Config": {
                "EapTeap": {
                  "ServerValidation": {
                    "TrustedRootCAHash": [
                      "32 eb 83 1e da 15 9 8f fc fb 8f 30 33 4e bf 71 ac 43 ac db fe a8 48 59 d4 ef 74 f8 1 0 4f b4",
                      "d0 38 9b 27 d7 26 97 7f 2f c0 8a 7e af 71 8a bb 5b 9a a6 ac 2f fb 8e e8 68 a8 17 58 5e 29 35 f",
                      "cb 3c cb b7 60 31 e5 e0 13 8f 8d d3 9a 23 f9 de 47 ff c3 5e 43 c1 14 4c ea 27 d4 6a 5a b1 cb 5f",
                      "c0 6e 30 7f 7c fc 1d 32 fa 72 a4 c0 33 c8 7b 90 1 9a f2 16 f0 77 5d 64 97 8a 2e ca 6c 8a 23 e"
                    ],
                    "DisablePrompt": "false",
                    "DownloadTrustedServerRoot": "false"
                  },
                  "Phase2Authentication": {
                    "InnerMethodConfig": [
                      {
                        "EapHostConfig": {
                          "EapMethod": {
                            "Type": "13",
                            "VendorId": "0",
                            "VendorType": "0",
                            "AuthorId": "0"
                          },
                          "Config": {
                            "Eap": {
                              "Type": "13",
                              "EapType": {
                                "CredentialsSource": {
                                  "CertificateStore": {
                                    "SimpleCertSelection": "true"
                                  }
                                },
                                "ServerValidation": {
                                  "DisableUserPromptForServerValidation": "false",
                                  "ServerNames": null,
                                  "TrustedRootCA": [
                                    "1d 6d 28 88 a1 8f 32 96 77 b6 0f a8 31 74 74 c1 69 bc e7 95",
                                    "71 59 9a 14 19 84 7d b0 6b b5 99 36 17 44 0c 06 4e a8 c3 23",
                                    "df 3c 24 f9 bf d6 66 76 1b 26 80 73 fe 06 d1 cc 8d 4f 82 a4",
                                    "8b 3c 5b 9b 86 7d 4b e4 6d 1c b5 a0 1d 45 d6 7d c8 e9 40 82"
                                  ]
                                },
                                "DifferentUsername": "false",
                                "PerformServerValidation": "true",
                                "AcceptServerName": "false",
                                "TLSExtensions": {
                                  "FilteringInfo": {
                                    "ClientAuthEKUList": {}
                                  }
                                }
                              }
                            }
                          }
                        }
                      },
                      {
                        "EapHostConfig": {
                          "EapMethod": {
                            "Type": "13",
                            "VendorId": "0",
                            "VendorType": "0",
                            "AuthorId": "0"
                          },
                          "Config": {
                            "Eap": {
                              "Type": "13",
                              "EapType": {
                                "CredentialsSource": {
                                  "CertificateStore": {
                                    "SimpleCertSelection": "true"
                                  }
                                },
                                "ServerValidation": {
                                  "DisableUserPromptForServerValidation": "false",
                                  "ServerNames": null,
                                  "TrustedRootCA": [
                                    "1d 6d 28 88 a1 8f 32 96 77 b6 0f a8 31 74 74 c1 69 bc e7 95",
                                    "71 59 9a 14 19 84 7d b0 6b b5 99 36 17 44 0c 06 4e a8 c3 23",
                                    "df 3c 24 f9 bf d6 66 76 1b 26 80 73 fe 06 d1 cc 8d 4f 82 a4",
                                    "8b 3c 5b 9b 86 7d 4b e4 6d 1c b5 a0 1d 45 d6 7d c8 e9 40 82"
                                  ]
                                },
                                "DifferentUsername": "false",
                                "PerformServerValidation": "true",
                                "AcceptServerName": "false",
                                "TLSExtensions": {
                                  "FilteringInfo": {
                                    "ClientAuthEKUList": {}
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    ]
                  },
                  "Phase1Identity": {
                    "IdentityPrivacy": "true",
                    "AnonymousIdentity": "anonymous"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
{
  "+p_xml": "version=\"1.0\"",
  "WLANProfile": {
    "name": "CHLA-Remote",
    "SSIDConfig": {
      "SSID": {
        "hex": "43484C412D52656D6F7465",
        "name": "CHLA-Remote"
      },
      "nonBroadcast": "false"
    },
    "connectionType": "ESS",
    "connectionMode": "auto",
    "autoSwitch": "true",
    "MSM": {
      "security": {
        "authEncryption": {
          "authentication": "WPA2",
          "encryption": "AES",
          "useOneX": "true"
        },
        "PMKCacheMode": "enabled",
        "PMKCacheTTL": "720",
        "PMKCacheSize": "128",
        "preAuthThrottle": "3",
        "OneX": {
          "cacheUserData": "false",
          "heldPeriod": "1",
          "authPeriod": "30",
          "startPeriod": "5",
          "maxStart": "5",
          "maxAuthFailures": "5",
          "authMode": "machineOrUser",
          "EAPConfig": {
            "EapHostConfig": {
              "EapMethod": {
                "Type": "55",
                "VendorId": "0",
                "VendorType": "0",
                "AuthorId": "311"
              },
              "Config": {
                "EapTeap": {
                  "ServerValidation": {
                    "TrustedRootCAHash": [
                      "32 eb 83 1e da 15 9 8f fc fb 8f 30 33 4e bf 71 ac 43 ac db fe a8 48 59 d4 ef 74 f8 1 0 4f b4",
                      "d0 38 9b 27 d7 26 97 7f 2f c0 8a 7e af 71 8a bb 5b 9a a6 ac 2f fb 8e e8 68 a8 17 58 5e 29 35 f",
                      "cb 3c cb b7 60 31 e5 e0 13 8f 8d d3 9a 23 f9 de 47 ff c3 5e 43 c1 14 4c ea 27 d4 6a 5a b1 cb 5f",
                      "c0 6e 30 7f 7c fc 1d 32 fa 72 a4 c0 33 c8 7b 90 1 9a f2 16 f0 77 5d 64 97 8a 2e ca 6c 8a 23 e"
                    ],
                    "DisablePrompt": "false",
                    "DownloadTrustedServerRoot": "false"
                  },
                  "Phase2Authentication": {
                    "InnerMethodConfig": [
                      {
                        "EapHostConfig": {
                          "EapMethod": {
                            "Type": "13",
                            "VendorId": "0",
                            "VendorType": "0",
                            "AuthorId": "0"
                          },
                          "Config": {
                            "Eap": {
                              "Type": "13",
                              "EapType": {
                                "CredentialsSource": {
                                  "CertificateStore": {
                                    "SimpleCertSelection": "true"
                                  }
                                },
                                "ServerValidation": {
                                  "DisableUserPromptForServerValidation": "false",
                                  "ServerNames": null,
                                  "TrustedRootCA": [
                                    "1d 6d 28 88 a1 8f 32 96 77 b6 0f a8 31 74 74 c1 69 bc e7 95",
                                    "71 59 9a 14 19 84 7d b0 6b b5 99 36 17 44 0c 06 4e a8 c3 23",
                                    "df 3c 24 f9 bf d6 66 76 1b 26 80 73 fe 06 d1 cc 8d 4f 82 a4",
                                    "8b 3c 5b 9b 86 7d 4b e4 6d 1c b5 a0 1d 45 d6 7d c8 e9 40 82"
                                  ]
                                },
                                "DifferentUsername": "false",
                                "PerformServerValidation": "true",
                                "AcceptServerName": "false",
                                "TLSExtensions": {
                                  "FilteringInfo": {
                                    "ClientAuthEKUList": {}
                                  }
                                }
                              }
                            }
                          }
                        }
                      },
                      {
                        "EapHostConfig": {
                          "EapMethod": {
                            "Type": "13",
                            "VendorId": "0",
                            "VendorType": "0",
                            "AuthorId": "0"
                          },
                          "Config": {
                            "Eap": {
                              "Type": "13",
                              "EapType": {
                                "CredentialsSource": {
                                  "CertificateStore": {
                                    "SimpleCertSelection": "true"
                                  }
                                },
                                "ServerValidation": {
                                  "DisableUserPromptForServerValidation": "false",
                                  "ServerNames": null,
                                  "TrustedRootCA": [
                                    "1d 6d 28 88 a1 8f 32 96 77 b6 0f a8 31 74 74 c1 69 bc e7 95",
                                    "71 59 9a 14 19 84 7d b0 6b b5 99 36 17 44 0c 06 4e a8 c3 23",
                                    "df 3c 24 f9 bf d6 66 76 1b 26 80 73 fe 06 d1 cc 8d 4f 82 a4",
                                    "8b 3c 5b 9b 86 7d 4b e4 6d 1c b5 a0 1d 45 d6 7d c8 e9 40 82"
                                  ]
                                },
                                "DifferentUsername": "false",
                                "PerformServerValidation": "true",
                                "AcceptServerName": "false",
                                "TLSExtensions": {
                                  "FilteringInfo": {
                                    "ClientAuthEKUList": {}
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    ]
                  },
                  "Phase1Identity": {
                    "IdentityPrivacy": "true",
                    "AnonymousIdentity": "anonymous"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
Dump of both wireless profiles
$profiles = foreach ($p in "CHLA_Staff","CHLA-Remote") {
  netsh wlan export profile name="$p" folder=$env:TEMP key=clear > $null
  $f = Get-ChildItem $env:TEMP "Wi-Fi-$p*.xml" | sort LastWriteTime -desc | select -f 1
  yq -o=json '.' $f.FullName
  Remove-Item $f.FullName
}

$profiles | jq -s '
  def norm:
    walk(
      if type == "object" then
        with_entries(select(.key | startswith("+@") | not)) |
        if has("+content") and (keys | length == 1)
          then .["+content"]
          else .
        end
      else .
      end
    );

  map(norm | .WLANProfile)
' | Set-Clipboard
output
[
  {
    "name": "CHLA_Staff",
    "SSIDConfig": {
      "SSID": {
        "hex": "43484C415F5374616666",
        "name": "CHLA_Staff"
      },
      "nonBroadcast": "false"
    },
    "connectionType": "ESS",
    "connectionMode": "auto",
    "autoSwitch": "true",
    "MSM": {
      "security": {
        "authEncryption": {
          "authentication": "WPA2",
          "encryption": "AES",
          "useOneX": "true"
        },
        "PMKCacheMode": "enabled",
        "PMKCacheTTL": "720",
        "PMKCacheSize": "128",
        "preAuthThrottle": "3",
        "OneX": {
          "heldPeriod": "1",
          "authPeriod": "30",
          "startPeriod": "5",
          "maxStart": "5",
          "maxAuthFailures": "5",
          "authMode": "machineOrUser",
          "EAPConfig": {
            "EapHostConfig": {
              "EapMethod": {
                "Type": "55",
                "VendorId": "0",
                "VendorType": "0",
                "AuthorId": "311"
              },
              "Config": {
                "EapTeap": {
                  "ServerValidation": {
                    "TrustedRootCAHash": [
                      "32 eb 83 1e da 15 9 8f fc fb 8f 30 33 4e bf 71 ac 43 ac db fe a8 48 59 d4 ef 74 f8 1 0 4f b4",
                      "d0 38 9b 27 d7 26 97 7f 2f c0 8a 7e af 71 8a bb 5b 9a a6 ac 2f fb 8e e8 68 a8 17 58 5e 29 35 f",
                      "cb 3c cb b7 60 31 e5 e0 13 8f 8d d3 9a 23 f9 de 47 ff c3 5e 43 c1 14 4c ea 27 d4 6a 5a b1 cb 5f",
                      "c0 6e 30 7f 7c fc 1d 32 fa 72 a4 c0 33 c8 7b 90 1 9a f2 16 f0 77 5d 64 97 8a 2e ca 6c 8a 23 e"
                    ],
                    "DisablePrompt": "false",
                    "DownloadTrustedServerRoot": "false"
                  },
                  "Phase2Authentication": {
                    "InnerMethodConfig": [
                      {
                        "EapHostConfig": {
                          "EapMethod": {
                            "Type": "13",
                            "VendorId": "0",
                            "VendorType": "0",
                            "AuthorId": "0"
                          },
                          "Config": {
                            "Eap": {
                              "Type": "13",
                              "EapType": {
                                "CredentialsSource": {
                                  "CertificateStore": {
                                    "SimpleCertSelection": "true"
                                  }
                                },
                                "ServerValidation": {
                                  "DisableUserPromptForServerValidation": "false",
                                  "ServerNames": null,
                                  "TrustedRootCA": [
                                    "1d 6d 28 88 a1 8f 32 96 77 b6 0f a8 31 74 74 c1 69 bc e7 95",
                                    "71 59 9a 14 19 84 7d b0 6b b5 99 36 17 44 0c 06 4e a8 c3 23",
                                    "df 3c 24 f9 bf d6 66 76 1b 26 80 73 fe 06 d1 cc 8d 4f 82 a4",
                                    "8b 3c 5b 9b 86 7d 4b e4 6d 1c b5 a0 1d 45 d6 7d c8 e9 40 82"
                                  ]
                                },
                                "DifferentUsername": "false",
                                "PerformServerValidation": "true",
                                "AcceptServerName": "false",
                                "TLSExtensions": {
                                  "FilteringInfo": {
                                    "ClientAuthEKUList": {}
                                  }
                                }
                              }
                            }
                          }
                        }
                      },
                      {
                        "EapHostConfig": {
                          "EapMethod": {
                            "Type": "13",
                            "VendorId": "0",
                            "VendorType": "0",
                            "AuthorId": "0"
                          },
                          "Config": {
                            "Eap": {
                              "Type": "13",
                              "EapType": {
                                "CredentialsSource": {
                                  "CertificateStore": {
                                    "SimpleCertSelection": "true"
                                  }
                                },
                                "ServerValidation": {
                                  "DisableUserPromptForServerValidation": "false",
                                  "ServerNames": null,
                                  "TrustedRootCA": [
                                    "1d 6d 28 88 a1 8f 32 96 77 b6 0f a8 31 74 74 c1 69 bc e7 95",
                                    "71 59 9a 14 19 84 7d b0 6b b5 99 36 17 44 0c 06 4e a8 c3 23",
                                    "df 3c 24 f9 bf d6 66 76 1b 26 80 73 fe 06 d1 cc 8d 4f 82 a4",
                                    "8b 3c 5b 9b 86 7d 4b e4 6d 1c b5 a0 1d 45 d6 7d c8 e9 40 82"
                                  ]
                                },
                                "DifferentUsername": "false",
                                "PerformServerValidation": "true",
                                "AcceptServerName": "false",
                                "TLSExtensions": {
                                  "FilteringInfo": {
                                    "ClientAuthEKUList": {}
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    ]
                  },
                  "Phase1Identity": {
                    "IdentityPrivacy": "true",
                    "AnonymousIdentity": "anonymous"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  {
    "name": "CHLA-Remote",
    "SSIDConfig": {
      "SSID": {
        "hex": "43484C412D52656D6F7465",
        "name": "CHLA-Remote"
      },
      "nonBroadcast": "false"
    },
    "connectionType": "ESS",
    "connectionMode": "auto",
    "autoSwitch": "true",
    "MSM": {
      "security": {
        "authEncryption": {
          "authentication": "WPA2",
          "encryption": "AES",
          "useOneX": "true"
        },
        "PMKCacheMode": "enabled",
        "PMKCacheTTL": "720",
        "PMKCacheSize": "128",
        "preAuthThrottle": "3",
        "OneX": {
          "cacheUserData": "false",
          "heldPeriod": "1",
          "authPeriod": "30",
          "startPeriod": "5",
          "maxStart": "5",
          "maxAuthFailures": "5",
          "authMode": "machineOrUser",
          "EAPConfig": {
            "EapHostConfig": {
              "EapMethod": {
                "Type": "55",
                "VendorId": "0",
                "VendorType": "0",
                "AuthorId": "311"
              },
              "Config": {
                "EapTeap": {
                  "ServerValidation": {
                    "TrustedRootCAHash": [
                      "32 eb 83 1e da 15 9 8f fc fb 8f 30 33 4e bf 71 ac 43 ac db fe a8 48 59 d4 ef 74 f8 1 0 4f b4",
                      "d0 38 9b 27 d7 26 97 7f 2f c0 8a 7e af 71 8a bb 5b 9a a6 ac 2f fb 8e e8 68 a8 17 58 5e 29 35 f",
                      "cb 3c cb b7 60 31 e5 e0 13 8f 8d d3 9a 23 f9 de 47 ff c3 5e 43 c1 14 4c ea 27 d4 6a 5a b1 cb 5f",
                      "c0 6e 30 7f 7c fc 1d 32 fa 72 a4 c0 33 c8 7b 90 1 9a f2 16 f0 77 5d 64 97 8a 2e ca 6c 8a 23 e"
                    ],
                    "DisablePrompt": "false",
                    "DownloadTrustedServerRoot": "false"
                  },
                  "Phase2Authentication": {
                    "InnerMethodConfig": [
                      {
                        "EapHostConfig": {
                          "EapMethod": {
                            "Type": "13",
                            "VendorId": "0",
                            "VendorType": "0",
                            "AuthorId": "0"
                          },
                          "Config": {
                            "Eap": {
                              "Type": "13",
                              "EapType": {
                                "CredentialsSource": {
                                  "CertificateStore": {
                                    "SimpleCertSelection": "true"
                                  }
                                },
                                "ServerValidation": {
                                  "DisableUserPromptForServerValidation": "false",
                                  "ServerNames": null,
                                  "TrustedRootCA": [
                                    "1d 6d 28 88 a1 8f 32 96 77 b6 0f a8 31 74 74 c1 69 bc e7 95",
                                    "71 59 9a 14 19 84 7d b0 6b b5 99 36 17 44 0c 06 4e a8 c3 23",
                                    "df 3c 24 f9 bf d6 66 76 1b 26 80 73 fe 06 d1 cc 8d 4f 82 a4",
                                    "8b 3c 5b 9b 86 7d 4b e4 6d 1c b5 a0 1d 45 d6 7d c8 e9 40 82"
                                  ]
                                },
                                "DifferentUsername": "false",
                                "PerformServerValidation": "true",
                                "AcceptServerName": "false",
                                "TLSExtensions": {
                                  "FilteringInfo": {
                                    "ClientAuthEKUList": {}
                                  }
                                }
                              }
                            }
                          }
                        }
                      },
                      {
                        "EapHostConfig": {
                          "EapMethod": {
                            "Type": "13",
                            "VendorId": "0",
                            "VendorType": "0",
                            "AuthorId": "0"
                          },
                          "Config": {
                            "Eap": {
                              "Type": "13",
                              "EapType": {
                                "CredentialsSource": {
                                  "CertificateStore": {
                                    "SimpleCertSelection": "true"
                                  }
                                },
                                "ServerValidation": {
                                  "DisableUserPromptForServerValidation": "false",
                                  "ServerNames": null,
                                  "TrustedRootCA": [
                                    "1d 6d 28 88 a1 8f 32 96 77 b6 0f a8 31 74 74 c1 69 bc e7 95",
                                    "71 59 9a 14 19 84 7d b0 6b b5 99 36 17 44 0c 06 4e a8 c3 23",
                                    "df 3c 24 f9 bf d6 66 76 1b 26 80 73 fe 06 d1 cc 8d 4f 82 a4",
                                    "8b 3c 5b 9b 86 7d 4b e4 6d 1c b5 a0 1d 45 d6 7d c8 e9 40 82"
                                  ]
                                },
                                "DifferentUsername": "false",
                                "PerformServerValidation": "true",
                                "AcceptServerName": "false",
                                "TLSExtensions": {
                                  "FilteringInfo": {
                                    "ClientAuthEKUList": {}
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    ]
                  },
                  "Phase1Identity": {
                    "IdentityPrivacy": "true",
                    "AnonymousIdentity": "anonymous"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
]
Export Profiles as XML
Export for analysis
mkdir C:\temp -ErrorAction SilentlyContinue
netsh wlan export profile name="CHLA-Staff" folder=C:\temp key=clear
netsh wlan export profile name="CHLA_Remote" folder=C:\temp key=clear
dir C:\temp\*CHLA*
Parse WiFi Profile XML — EAP Configuration
Extract key fields from CHLA-Staff profile
[xml]$profile = Get-Content "C:\temp\Wi-Fi-CHLA-Staff.xml"

Write-Host "=== Connection Settings ==="
Write-Host "SSID:       $($profile.WLANProfile.SSIDConfig.SSID.name)"
Write-Host "Auth:       $($profile.WLANProfile.MSM.security.authEncryption.authentication)"
Write-Host "Encryption: $($profile.WLANProfile.MSM.security.authEncryption.encryption)"
Write-Host "802.1X:     $($profile.WLANProfile.MSM.security.OneX.authMode)"

$eapType = $profile.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig.EapMethod.Type.'#text'
Write-Host "EAP Type:   $eapType (13=TLS, 25=PEAP, 21=TTLS)"

Write-Host "`n=== Certificate Config ==="
$profile.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig | Select-Xml -XPath "//*[local-name()='ServerValidation']" | ForEach-Object { $_.Node.OuterXml }
$profile.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig | Select-Xml -XPath "//*[local-name()='TLSExtensions']" | ForEach-Object { $_.Node.OuterXml }
Diff CHLA-Staff vs CHLA_Remote — find differences
Compare-Object (Get-Content "C:\temp\Wi-Fi-CHLA-Staff.xml") (Get-Content "C:\temp\Wi-Fi-CHLA_Remote.xml")
Profile Source — GPO or Intune?
Check if WiFi profile came from GPO
Get-ChildItem "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Wireless\GPTWirelessPolicy" -Recurse -ErrorAction SilentlyContinue | Format-List
Check if WiFi profile came from Intune/MDM
Get-ChildItem "HKLM:\SOFTWARE\Microsoft\WlanSvc\Profiles" -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
    $props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
    if($props) { [PSCustomObject]@{Path=$_.PSPath; Props=($props.PSObject.Properties | Where-Object {$_.Name -notmatch 'PS'} | ForEach-Object {"$($_.Name)=$($_.Value)"}) -join "; "} }
} | Format-List
Device registration status — hybrid join confirmed?
dsregcmd /status | Select-String -Pattern "AzureAd|Domain|MDM|Tenant|Device"

Part 2: GPO Analysis

Phase 3: GPO 802.1X & Wireless Policy
Which GPOs apply to this computer?
gpresult /r /scope:computer
Filter for wireless/802.1X/cert GPOs
gpresult /r /scope:computer 2>$null | Select-String -Pattern "wireless|wifi|wlan|802|dot1x|certificate|CHLA" -CaseSensitive:$false
Export full GPO report as XML for parsing
gpresult /x C:\temp\gpo-report.xml /f
Parse GPO XML — find wireless/802.1X settings
[xml]$gpo = Get-Content "C:\temp\gpo-report.xml"
$gpo.Rsop.ComputerResults.ExtensionData | ForEach-Object {
    $_.Extension | Select-Xml -XPath "//*[local-name()='WLanPolicy' or local-name()='WiredPolicy' or local-name()='Dot3' or local-name()='Wireless']" | ForEach-Object {
        Write-Host "=== Found 802.1X/Wireless GPO Setting ==="
        $_.Node.OuterXml
    }
}
GPO wireless policy from registry — raw
# Wireless 802.1X GPO settings
Get-ChildItem "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Wireless\GPTWirelessPolicy" -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
    Write-Host "=== $($_.PSPath) ==="
    Get-ItemProperty $_.PSPath | Format-List
}
Wired 802.1X GPO settings
Get-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WiredL2\GP_Policy" -ErrorAction SilentlyContinue | Format-List
Is GPO pushing a specific cert thumbprint for 802.1X?
Get-ChildItem "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Wireless" -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
    $props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
    $props.PSObject.Properties | Where-Object { $_.Value -match '[A-Fa-f0-9]{40}' } | ForEach-Object {
        Write-Host "THUMBPRINT FOUND: $($_.Name) = $($_.Value)"
    }
}
Wired 802.1X service status
Get-Service dot3svc | Format-List Name, Status, StartType
netsh lan show profiles
netsh lan show profile name="*" | Select-String -Pattern "Name|EAP|Certificate|Auth"
Phase 3.5: AD CS Autoenrollment — GPO Cert Delivery
Check autoenroll GPO setting
gpresult /r /scope:computer | Select-String -Pattern "autoenroll|certificate" -CaseSensitive:$false
Certificate enrollment events (last 24h)
Get-WinEvent -FilterHashtable @{
    LogName='Application'
    ProviderName='Microsoft-Windows-CertificateServicesClient-AutoEnrollment'
    StartTime=(Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue | Format-Table TimeCreated, Id, Message -Wrap
What cert templates are configured?
certutil -template | Select-String "WiFi|Computer|Machine|Workstation|802|CHLA"

Part 3: Intune / MDM Investigation

Phase 4: Intune Certificate Delivery
Is Intune managing this device?
dsregcmd /status | Select-String "MDM"
Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Enrollments" -ErrorAction SilentlyContinue | ForEach-Object {
    Get-ItemProperty $_.PSPath | Select-Object ProviderID, EnrollmentState, UPN
} | Format-Table -AutoSize
Intune management extension logs — cert events
Get-Content "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log" -Tail 500 | Select-String -Pattern "SCEP|certificate|pkcs|enroll|WiFi|wireless"
SCEP enrollment events (Intune cert delivery)
Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin'
    StartTime=(Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue | Where-Object {
    $_.Message -match "SCEP|certificate|pkcs|enroll"
} | Format-Table TimeCreated, Id, @{N='Message';E={$_.Message.Substring(0,[Math]::Min(200,$_.Message.Length))}} -Wrap
Check Intune cert delivery order — did WiFi connect BEFORE cert arrived?
Get-Content "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log" -Tail 500 | Select-String -Pattern "profile|cert|connect" | Select-Object -First 30
Intune ClientCertCheck process — is it running?
Get-Process -Name ClientCertCheck -ErrorAction SilentlyContinue | Format-Table Id, ProcessName, StartTime -AutoSize
Get-WinEvent -FilterHashtable @{LogName='Application'; StartTime=(Get-Date).AddDays(-1)} -ErrorAction SilentlyContinue | Where-Object { $_.Message -match "ClientCertCheck" } | Format-Table TimeCreated, Message -Wrap
Intune-Pushed WiFi Profiles — Event Viewer
MDM WiFi profile deployment events — CHLA-Staff and CHLA-Remote
Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin'
    StartTime=(Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue | Where-Object {
    $_.Message -match "WiFi|WLAN|CHLA-Staff|CHLA.Remote|CHLA_Remote|wireless|profile"
} | Format-Table TimeCreated, Id, @{N='Message';E={$_.Message.Substring(0,[Math]::Min(250,$_.Message.Length))}} -Wrap
MDM policy application events — did Intune push the profile successfully?
Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin'
    StartTime=(Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue | Where-Object {
    $_.Id -in @(800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815)
} | Select-Object TimeCreated, Id, @{N='Message';E={$_.Message.Substring(0,[Math]::Min(250,$_.Message.Length))}} | Format-Table -Wrap
OMA-DM WiFi CSP — Intune uses this to push WiFi profiles
# Registry path where Intune WiFi profiles land
Get-ChildItem "HKLM:\SOFTWARE\Microsoft\WlanSvc\Profiles\*" -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
    $xml = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).ProfileXml
    if($xml -match "CHLA") {
        Write-Host "=== $($_.PSPath) ==="
        # Parse the XML to extract SSID and auth settings
        [xml]$p = $xml
        Write-Host "SSID:    $($p.WLANProfile.SSIDConfig.SSID.name)"
        Write-Host "Auth:    $($p.WLANProfile.MSM.security.authEncryption.authentication)"
        Write-Host "EAP:     $($p.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig.EapMethod.Type.'#text')"
        Write-Host "Source:  MDM/Intune"
        Write-Host ""
    }
}
Compare: GPO-pushed vs Intune-pushed WiFi profiles side by side
Write-Host "=== GPO WiFi Profiles ==="
Get-ChildItem "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Wireless\GPTWirelessPolicy" -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
    $props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
    if($props.ProfileName) { Write-Host "  GPO: $($props.ProfileName)" }
}

Write-Host "`n=== Intune/MDM WiFi Profiles ==="
netsh wlan show profiles | Select-String "CHLA" | ForEach-Object {
    $name = ($_ -split ":\s+")[1].Trim()
    $detail = netsh wlan show profile name="$name" | Select-String "Applied From"
    Write-Host "  $name — $detail"
}

Write-Host "`n=== All Profile Sources ==="
netsh wlan show profiles | Select-String "All User" | ForEach-Object {
    $name = ($_ -split ":\s+")[1].Trim()
    Write-Host "  $name"
}
WLAN-AutoConfig events for CHLA-Staff and CHLA-Remote specifically
Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-WLAN-AutoConfig/Operational'
    StartTime=(Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue | Where-Object {
    $_.Message -match "CHLA-Staff|CHLA.Remote|CHLA_Remote"
} | Format-Table TimeCreated, Id, @{N='Message';E={$_.Message.Substring(0,[Math]::Min(250,$_.Message.Length))}} -Wrap
Network Profile events — connection attempts per SSID
Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-WLAN-AutoConfig/Operational'
    Id=@(8001,8002,8003,8004,11001,11002,11004,11005,11010,11011)
    StartTime=(Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue | Select-Object TimeCreated, Id, @{N='Event';E={
    switch($_.Id){
        8001{"Connected"}; 8002{"Connect failed"}; 8003{"Disconnected"}; 8004{"Profile changed"}
        11001{"Auth started"}; 11002{"Auth succeeded"}; 11004{"Auth failed"}; 11005{"Auth rejected"}
        11010{"Cert selected"}; 11011{"Cert rejected"}
    }
}}, @{N='Detail';E={$_.Message.Substring(0,[Math]::Min(150,$_.Message.Length))}} | Format-Table -Wrap

Part 4: Supplicant Event Logs

Phase 5: What the Supplicant Actually Did
Wireless 802.1X authentication events (last 24h)
Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-WLAN-AutoConfig/Operational'
    StartTime=(Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue | Where-Object {
    $_.Message -match "802\.1X|EAP|certificate|authentication|CHLA"
} | Format-Table TimeCreated, Id, @{N='Message';E={$_.Message.Substring(0,[Math]::Min(200,$_.Message.Length))}} -Wrap
Wired 802.1X events (if applicable)
Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-Wired-AutoConfig/Operational'
    StartTime=(Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue | Where-Object {
    $_.Message -match "802\.1X|EAP|certificate|authentication"
} | Format-Table TimeCreated, Id, @{N='Message';E={$_.Message.Substring(0,[Math]::Min(200,$_.Message.Length))}} -Wrap
EAP method events — which cert was selected?
Get-WinEvent -FilterHashtable @{
    LogName='Microsoft-Windows-EapHost/Operational'
    StartTime=(Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue | Format-Table TimeCreated, Id, @{N='Message';E={$_.Message.Substring(0,[Math]::Min(200,$_.Message.Length))}} -Wrap

Part 5: Control Comparison

Phase 6: Working Machine vs Affected Machine — Side by Side
Run this on BOTH machines — your working one and Anthony’s affected one
$hostname = $env:COMPUTERNAME
Write-Host "=== $hostname — Certificate & WiFi Audit ==="

Write-Host "`n--- Client Auth Certs (Machine Store) ---"
Get-ChildItem Cert:\LocalMachine\My | Where-Object {
    $_.EnhancedKeyUsageList.ObjectId -contains "1.3.6.1.5.5.7.3.2"
} | Select-Object Subject, Issuer, NotAfter, @{N='Days';E={($_.NotAfter-(Get-Date)).Days}}, Thumbprint | Format-Table -AutoSize

Write-Host "`n--- Client Auth Certs (User Store) ---"
Get-ChildItem Cert:\CurrentUser\My | Where-Object {
    $_.EnhancedKeyUsageList.ObjectId -contains "1.3.6.1.5.5.7.3.2"
} | Select-Object Subject, Issuer, NotAfter, @{N='Days';E={($_.NotAfter-(Get-Date)).Days}}, Thumbprint | Format-Table -AutoSize

Write-Host "`n--- WiFi Profiles ---"
netsh wlan show profiles | Select-String "All User|CHLA"

Write-Host "`n--- Current Connection ---"
netsh wlan show interfaces | Select-String "Name|State|SSID|Auth|Profile"

Write-Host "`n--- Device Registration ---"
dsregcmd /status | Select-String "AzureAd|Domain|MDM|Device"

Write-Host "`n--- GPO Wireless Policy ---"
gpresult /r /scope:computer 2>$null | Select-String "wireless|wifi|802|dot1x|cert" -CaseSensitive:$false

Write-Host "`n--- Last 5 WLAN-AutoConfig Events ---"
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-WLAN-AutoConfig/Operational'} -MaxEvents 5 -ErrorAction SilentlyContinue | Select-Object TimeCreated, @{N='Msg';E={$_.Message.Substring(0,[Math]::Min(120,$_.Message.Length))}} | Format-Table -Wrap

Write-Host "`n--- Cert Autoenroll (last event) ---"
Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='Microsoft-Windows-CertificateServicesClient-AutoEnrollment'} -MaxEvents 1 -ErrorAction SilentlyContinue | Select-Object TimeCreated, Message | Format-List

The diff between the two outputs proves where the problem is. ISE sees the same policy for both machines — if one works and one doesn’t, the difference is on the client.


Part 6: ISE Validation (Supporting Evidence — Not Root Cause)

ISE does not push certs. ISE validates what the supplicant presents. These queries prove ISE is working correctly.
Phase 7: ISE — What Does ISE See?
Prerequisites — load ISE credentials + dc_query function
# Load credentials (d001 at work, d000 at home lab)
dsource d001 dev/network/ise       # WORK
# dsource d000 dev/network/ise     # HOME LAB

# Verify credentials loaded (safe — no values shown)
env | grep ISE_ | awk -F= '{printf "%-25s %s\n", $1, (length($2) > 0 ? "SET (" length($2) " chars)" : "EMPTY")}'

# REQUIRED: dc_query is NOT auto-loaded — copy-paste this function into your terminal
# Source: data/shared/partials/ise-dataconnect/helpers.adoc
dc_query() {
  local sql="$1"
  ~/atelier/_projects/personal/netapi/.venv/bin/python -c "
import oracledb, os, json, ssl
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
conn = oracledb.connect(
    user=os.environ['ISE_DATACONNECT_USER'],
    password=os.environ['ISE_DATACONNECT_PASS'],
    dsn=os.environ['ISE_DATACONNECT_DSN'],
    ssl_context=ssl_context,
    ssl_server_dn_match=False)
cursor = conn.cursor()
cursor.execute('''${sql}''')
columns = [col[0] for col in cursor.description]
rows = [dict(zip(columns, row)) for row in cursor.fetchall()]
print(json.dumps(rows, indent=2, default=str))
conn.close()
"
}

# Verify function loaded
type dc_query 2>&1 | grep -E "function|not found"

# Quick connectivity test
dc_query "SELECT COUNT(*) AS total FROM radius_authentications" | jq '.[0].TOTAL'
Also available: dc-run-sql for .sql files (no function needed)
bash data/shared/scripts/dc-run-sql.sh <file.sql>
bash data/shared/scripts/dc-run-sql.sh <file.sql> auto   # auto-save to output/
Table 1. Known gotchas (battle-tested)
Error Fix

ORA-01722: invalid number

Don’t use FAILED > 0. Use failure_reason IS NOT NULL

DPY-3022 timezone error

Never SELECT * from endpoints_data. Select specific columns via JOIN.

DPY-6006 connection error

DSN must use FQDN, not IP. Oracle TLS validates hostname.

dc_query: not found

Function not auto-loaded. Copy-paste from data/shared/partials/ise-dataconnect/helpers.adoc

PASSED values

String type: 'Pass' and 'Fail' (capital P/F, not boolean)

Time intervals

Use SYSTIMESTAMP - INTERVAL '7' DAY (Oracle syntax, not CURRENT_TIMESTAMP - 7 DAYS)

Recent EAP-TLS failures — the failure reason proves client-side issue
dc_query "
SELECT TIMESTAMP_TIMEZONE, CALLING_STATION_ID, USERNAME,
       AUTHENTICATION_METHOD, AUTHENTICATION_PROTOCOL,
       PASSED, FAILURE_REASON, POLICY_SET_NAME,
       ENDPOINT_PROFILE, NAS_IP_ADDRESS
FROM radius_authentications
WHERE PASSED = 'Fail'
  AND AUTHENTICATION_PROTOCOL LIKE '%EAP-TLS%'
ORDER BY TIMESTAMP_TIMEZONE DESC
FETCH FIRST 25 ROWS ONLY
" | jq -r '.[] | "\(.TIMESTAMP_TIMEZONE)  \(.CALLING_STATION_ID)  \(.FAILURE_REASON)"' | column -t
ISE failure codes — what they mean
12516 — Expired client cert           → Intune/GPO not renewing
12514 — Identity mismatch             → WiFi profile CN ≠ cert CN
12308 — Cert not in trust store       → ISE needs CA cert imported
12500 — Chain incomplete              → Client not sending intermediate
12520 — Generic handshake fail        → Supplicant not presenting cert
No failure in ISE                     → Device never reached RADIUS
Specific device — fail then pass pattern (proves forget/rejoin)
# Substitute MAC from failures above
dc_query "
SELECT TIMESTAMP_TIMEZONE, CALLING_STATION_ID, USERNAME,
       AUTHENTICATION_METHOD, AUTHENTICATION_PROTOCOL,
       PASSED, FAILURE_REASON
FROM radius_authentications
WHERE CALLING_STATION_ID = '<MAC_ADDRESS>'
ORDER BY TIMESTAMP_TIMEZONE DESC
FETCH FIRST 20 ROWS ONLY
" | jq -r '.[] | "\(.TIMESTAMP_TIMEZONE)  \(.PASSED)  \(.AUTHENTICATION_PROTOCOL)  \(.FAILURE_REASON)"' | column -t
Phase 7.5: ISE Bulk — Scope the Problem
Total affected devices (last 30 days)
dc_query "
SELECT COUNT(DISTINCT CALLING_STATION_ID) AS AFFECTED_DEVICES,
       COUNT(*) AS TOTAL_FAILURES,
       MIN(TIMESTAMP_TIMEZONE) AS FIRST_OCCURRENCE,
       MAX(TIMESTAMP_TIMEZONE) AS LATEST
FROM radius_authentications
WHERE PASSED = 'Fail'
  AND AUTHENTICATION_PROTOCOL LIKE '%EAP-TLS%'
  AND TIMESTAMP_TIMEZONE > SYSTIMESTAMP - INTERVAL '30' DAY
" | jq '.'
Failures grouped by reason — which cert issue is most common?
dc_query "
SELECT FAILURE_REASON, COUNT(*) AS FAIL_COUNT,
       MIN(TIMESTAMP_TIMEZONE) AS FIRST_SEEN,
       MAX(TIMESTAMP_TIMEZONE) AS LAST_SEEN
FROM radius_authentications
WHERE PASSED = 'Fail'
  AND AUTHENTICATION_PROTOCOL LIKE '%EAP-TLS%'
  AND TIMESTAMP_TIMEZONE > SYSTIMESTAMP - INTERVAL '7' DAY
GROUP BY FAILURE_REASON
ORDER BY FAIL_COUNT DESC
" | jq -r '.[] | "\(.FAIL_COUNT)\t\(.FAILURE_REASON)\t\(.FIRST_SEEN)\t\(.LAST_SEEN)"' | column -t -s $'\t'
All affected MACs — export for Anthony
dc_query "
SELECT CALLING_STATION_ID AS MAC,
       COUNT(*) AS FAIL_COUNT,
       MAX(TIMESTAMP_TIMEZONE) AS LAST_FAIL,
       MAX(FAILURE_REASON) AS REASON,
       MAX(USERNAME) AS USERNAME
FROM radius_authentications
WHERE PASSED = 'Fail'
  AND AUTHENTICATION_PROTOCOL LIKE '%EAP-TLS%'
  AND TIMESTAMP_TIMEZONE > SYSTIMESTAMP - INTERVAL '7' DAY
GROUP BY CALLING_STATION_ID
ORDER BY FAIL_COUNT DESC
" | tee /tmp/intune-cert-failures.json | jq -r '.[] | "\(.MAC)\t\(.FAIL_COUNT)\t\(.LAST_FAIL)\t\(.REASON)"' | column -t -s $'\t'
Devices that failed THEN succeeded (forget/rejoin proof)
dc_query "
SELECT a.CALLING_STATION_ID AS MAC,
       SUM(CASE WHEN a.PASSED = 'Fail' THEN 1 ELSE 0 END) AS FAILS,
       SUM(CASE WHEN a.PASSED = 'Pass' THEN 1 ELSE 0 END) AS PASSES,
       MAX(CASE WHEN a.PASSED = 'Fail' THEN a.TIMESTAMP_TIMEZONE END) AS LAST_FAIL,
       MAX(CASE WHEN a.PASSED = 'Pass' THEN a.TIMESTAMP_TIMEZONE END) AS LAST_PASS
FROM radius_authentications a
WHERE a.AUTHENTICATION_PROTOCOL LIKE '%EAP-TLS%'
  AND a.TIMESTAMP_TIMEZONE > SYSTIMESTAMP - INTERVAL '7' DAY
GROUP BY a.CALLING_STATION_ID
HAVING SUM(CASE WHEN a.PASSED = 'Fail' THEN 1 ELSE 0 END) > 0
   AND SUM(CASE WHEN a.PASSED = 'Pass' THEN 1 ELSE 0 END) > 0
ORDER BY FAILS DESC
" | jq -r '.[] | "\(.MAC)\tFail:\(.FAILS)\tPass:\(.PASSES)\tLastFail:\(.LAST_FAIL)\tLastPass:\(.LAST_PASS)"' | column -t -s $'\t'
Save CSV for Anthony
jq -r '["MAC","FAIL_COUNT","LAST_FAIL","REASON","USERNAME"], (.[] | [.MAC,.FAIL_COUNT,.LAST_FAIL,.REASON,.USERNAME]) | @csv' /tmp/intune-cert-failures.json > /tmp/intune-cert-failures.csv
echo "Saved: /tmp/intune-cert-failures.csv ($(wc -l < /tmp/intune-cert-failures.csv) devices)"
Phase 8: ISE Cert Trust Store
List all trusted certs in ISE — verify Intune/AD CS CA is trusted
curl -sk -u "${ISE_ERS_USER}:${ISE_ERS_PASS}" \
  -H "Accept: application/json" \
  "https://${ISE_PAN_FQDN}:9060/ers/config/trustedcertificate" | \
  jq -r '.SearchResult.resources[] | "\(.id)  \(.name)"'
Search for Intune/SCEP/Enterprise CA specifically
curl -sk -u "${ISE_ERS_USER}:${ISE_ERS_PASS}" \
  -H "Accept: application/json" \
  "https://${ISE_PAN_FQDN}:9060/ers/config/trustedcertificate" | \
  jq -r '.SearchResult.resources[] | select(.name | test("intune|scep|mdm|microsoft|enterprise|chla"; "i")) | "\(.id)  \(.name)"'
MnT active sessions — affected devices currently connected?
mnt "/Session/ActiveList" | \
  xq -r '.activeList.activeSession[] | "\(.calling_station_id)\t\(.user_name)\t\(.nas_ip_address)\t\(.framed_ip_address)"' | \
  column -t -s $'\t'

Root Cause Determination

After Parts 1-6, fill in:

Check Result Implication

How many client auth certs on affected device?

_

If 2+ from different CAs → supplicant picking wrong one

Cert chain valid on affected device?

_

If chain broken → missing intermediate or untrusted root

Any expired certs on affected device?

_

If expired → GPO/Intune not renewing

WiFi profile source (GPO or Intune)?

_

If both → conflict, last write wins

WiFi profile EAP type?

_

Must be 13 (TLS). If 25 (PEAP) → wrong profile

GPO pushing cert thumbprint?

_

If pinned to old thumbprint → new cert won’t match

Intune SCEP logs show cert delivered?

_

If no cert event → Intune not delivering

WLAN-AutoConfig shows cert selection?

_

If "no suitable cert" → wrong store or wrong EKU

ISE failure reason code?

_

12516=expired, 12514=mismatch, 12308=untrusted, none=never reached ISE

Working machine has same cert issuer?

_

Control comparison — must match

Troubleshooting: rsyslog ← ASA Syslog

Context

Pointed ASA to centralized rsyslog collector (Debian server). Just given SSH access. Need to verify logs are arriving, parse correctly, and troubleshoot if not.

Screen Share Layout (tmux)
Set up 3 panes before the call
# Pane 1 (left, large): SSH to CHLXSYSLOG01
ssh erosado@10.248.13.254

# Pane 2 (top right): this file as reference
bat docs/modules/ROOT/partials/worklog/daily-notes/2026-06-08/rsyslog-asa-troubleshooting.adoc

# Pane 3 (bottom right): ISE queries from workstation
dsource d001 dev/network/ise
Phase 0: Login and Reconnaissance
SSH to the Debian rsyslog server
# If hostname is in SSH config:
ssh rsyslog-01

# If not — direct:
ssh <username>@<rsyslog-server-ip>

# If you need to go through a jump host:
ssh -J <jumphost> <username>@<rsyslog-server-ip>
First login — system reconnaissance (clean one-liners)
# System summary — one shot
hostnamectl | awk '/hostname|Operating|Kernel|Virtualization/{print}'

# Who am I and what can I sudo?
id | awk -F'[()]' '{for(i=2;i<=NF;i+=2) printf "%s\n", $i}' | head -5
sudo -l

# Disk — formatted, only what matters
df -h /var /home /boot | awk 'NR==1 || /mapper|sda/{printf "%-45s %5s %5s %4s\n", $1, $2, $4, $5}'

# Log volume
du -sh /var/log 2>/dev/null

# Network — IPs and listeners
ip -br addr | awk '/UP/{print}'
ss -tulnp | awk 'NR==1 || /514|syslog/'
rsyslog status and version
# Is rsyslog running? One-liner status
systemctl is-active rsyslog && echo "PID: $(pgrep rsyslogd)"

# Version — determines config syntax (v8+ uses RainerScript)
/usr/sbin/rsyslogd -v 2>/dev/null || rsyslogd -v

# Config files — what exists?
ls -la /etc/rsyslog.conf /etc/rsyslog.d/

# Full config — strip comments, show only active lines
sudo awk '/^[^#]/ && NF' /etc/rsyslog.conf

# All drop-in configs
for f in /etc/rsyslog.d/*.conf; do echo "=== $f ==="; sudo awk '/^[^#]/ && NF' "$f"; echo; done
What’s already landing in logs?
# Recent syslog entries
sudo tail -50 /var/log/syslog

# Any ASA messages already?
sudo grep -c '%ASA' /var/log/syslog && echo "ASA logs found" || echo "NO ASA logs yet"

# Log rotation config
cat /etc/logrotate.d/rsyslog
Check existing syslog sources — who’s sending to this server?
# Unique source hosts with message counts — dashboard view
sudo awk '{print $4}' /var/log/syslog | sort | uniq -c | sort -rn | head -20

# Source IPs from recent messages
sudo awk '/from /{match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/); if(RSTART) print substr($0,RSTART,RLENGTH)}' /var/log/syslog | sort | uniq -c | sort -rn | head -20
Phase 0.5: Decrypt d001 Design Partial (on YOUR workstation, not the server)
Review the rsyslog collector design from last week
d001 open siem-qradar
bat data/d001/projects/siem-qradar-to-sentinel/partials/rsyslog-central-collector.adoc
Phase 1: Verify ASA Is Sending
On the ASA — confirm logging config
show logging
show logging setting
show running-config logging
Key lines to look for
logging enable
logging timestamp
logging host <interface> <rsyslog-ip> [tcp|udp]/<port>
logging trap <level>         ! informational (6) or debugging (7) for full capture
logging facility <number>    ! default 20 (local4)
Set or fix ASA logging target
logging enable
logging timestamp
logging host management <rsyslog-ip> udp/514
logging trap informational
logging facility 20
Phase 2: Verify rsyslog Is Receiving
Check if syslog is listening on the expected port
ss -ulnp | grep 514
ss -tlnp | grep 514
Check rsyslog config for UDP/TCP input
grep -rn 'imudp\|imtcp\|514' /etc/rsyslog.conf /etc/rsyslog.d/
If UDP input is not enabled — add to rsyslog config
# /etc/rsyslog.conf or /etc/rsyslog.d/00-input.conf
module(load="imudp")
input(type="imudp" port="514")

# For TCP (more reliable):
module(load="imtcp")
input(type="imtcp" port="514")
Restart and verify
sudo systemctl restart rsyslog
sudo systemctl status rsyslog
ss -ulnp | grep 514
Phase 3: Test Connectivity
From rsyslog server — listen raw to confirm packets arriving
# Quick packet capture on port 514
sudo tcpdump -i any port 514 -nn -c 20

# More detail — show payload
sudo tcpdump -i any port 514 -nn -A -c 10
From your workstation — test send
# Send test message to rsyslog
echo "<14>Test from workstation $(date)" | nc -u -w1 <rsyslog-ip> 514
From the ASA — generate a test log
! Generate a syslog event
logging message 199999 level 6
! Or just make a config change and revert — it logs
Phase 4: Check Logs Are Landing
Check rsyslog output — default location
# Default syslog
tail -f /var/log/syslog | grep -i asa

# Or messages
tail -f /var/log/messages | grep -i asa

# If you configured a dedicated ASA log file
tail -f /var/log/asa/asa.log
Check by source IP
grep '<asa-ip>' /var/log/syslog | tail -20
Phase 5: Firewall — Is Traffic Being Blocked?
Check iptables/nftables on rsyslog server
sudo iptables -L -n | grep 514
sudo nft list ruleset | grep 514
Check firewalld (if RHEL/CentOS)
sudo firewall-cmd --list-all | grep 514
# If not open:
sudo firewall-cmd --add-port=514/udp --permanent
sudo firewall-cmd --add-port=514/tcp --permanent
sudo firewall-cmd --reload
Check VyOS/network firewall between ASA and rsyslog
# On VyOS — check if syslog port is allowed between zones
show firewall statistics
Phase 6: ASA-Specific Log Parsing
rsyslog template for ASA logs — separate file per severity
# /etc/rsyslog.d/10-asa.conf
template(name="AsaFile" type="string"
    string="/var/log/asa/%HOSTNAME%/%$YEAR%-%$MONTH%-%$DAY%.log")

if $fromhost-ip == '<asa-ip>' then {
    action(type="omfile" dynaFile="AsaFile")
    stop
}
Parse ASA message IDs (e.g., %ASA-6-302013)
# Count messages by ASA message ID
sudo grep -oP '%ASA-\d-\d+' /var/log/syslog | sort | uniq -c | sort -rn | head -20

# By severity level
sudo awk '/%ASA/{match($0,/%ASA-([0-9])/,a); sev[a[1]]++} END{for(s in sev) printf "Level %s: %d\n", s, sev[s]}' /var/log/syslog | sort
Phase 6.5: Firewall Rule Added — Verify Logs Now Landing

Firewall team added inside rule permitting syslog from ASA to CHLXSYSLOG01. Run these NOW on the Debian server.

FIRST — are packets arriving? (tcpdump)
sudo tcpdump -i any port 514 -nn -c 10
Check syslog immediately
sudo tail -20 /var/log/syslog
Search for ASA messages specifically
sudo grep '%ASA' /var/log/syslog | tail -20
If nothing — check journal for rsyslog errors
sudo journalctl -u rsyslog --since "5 min ago" --no-pager
If tcpdump shows packets but syslog is empty — rsyslog config issue
# Check what rsyslog is doing with incoming UDP
sudo awk '/^[^#]/ && NF' /etc/rsyslog.conf | head -40

# Check if imudp module is loaded
sudo awk '/imudp|imtcp|514/' /etc/rsyslog.conf /etc/rsyslog.d/*.conf 2>/dev/null

# Check rsyslog internal stats
sudo rsyslogd -N1 2>&1 | head -20
If tcpdump shows NOTHING — network still blocked
# What's your IP?
ip -br addr | awk '/UP/{print}'

# Can you reach the ASA from here?
ping -c 2 172.16.57.177 2>/dev/null || echo "Cannot reach internal syslog server"

# Check local firewall on this Debian box
sudo iptables -L -n 2>/dev/null | grep -i '514\|syslog\|ACCEPT\|DROP'
sudo nft list ruleset 2>/dev/null | grep 514
If logs ARE landing — live count
# How many ASA messages right now?
sudo grep -c '%ASA' /var/log/syslog

# Messages per source device
sudo awk '/%ASA/{match($0,/from ([0-9.]+)/,a); if(a[1]) src[a[1]]++} END{for(s in src) printf "%6d %s\n", src[s], s}' /var/log/syslog | sort -rn

# Last 10 messages — formatted
sudo grep '%ASA' /var/log/syslog | tail -10 | awk '{match($0,/%ASA-[0-9]-[0-9]+/); printf "%-18s %-16s\n", $1" "$2" "$3, substr($0,RSTART,RLENGTH)}'

# Live tail — ASA only
sudo tail -f /var/log/syslog | awk '/%ASA/'
Phase 7: Live Monitoring (screen share power moves)
Real-time ASA message ID frequency counter
sudo tail -f /var/log/syslog | awk '/%ASA/{match($0,/%ASA-[0-9]-[0-9]+/); id=substr($0,RSTART,RLENGTH); count[id]++; printf "\r%s: %d  ", id, count[id]}'
Live filtered view — only ASA, clean columns
sudo tail -f /var/log/syslog | awk '/%ASA/{
  match($0,/%ASA-[0-9]-[0-9]+/);
  id=substr($0,RSTART,RLENGTH);
  ts=$1" "$2" "$3;
  printf "%-18s %-16s %s\n", ts, id, substr($0,RSTART+RLENGTH+2,80)
}'
Live source IP tracker — who’s sending right now
sudo tcpdump -i any port 514 -nn -l 2>/dev/null | awk '{
  match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/);
  ip=substr($0,RSTART,RLENGTH);
  count[ip]++;
  printf "\r";
  for(i in count) printf "%s: %d  ", i, count[i]
}'
Snapshot — messages per minute (last 10 minutes)
sudo awk '/%ASA/{print $1, $2, $3}' /var/log/syslog | awk '{print $1, $2, substr($3,1,5)}' | sort | uniq -c | tail -10
Common ASA syslog IDs to watch
%ASA-4-106023  — Deny by ACL (firewall drops)
%ASA-6-302013  — Built TCP connection
%ASA-6-302014  — Teardown TCP connection
%ASA-6-302015  — Built UDP connection
%ASA-6-302016  — Teardown UDP connection
%ASA-4-733100  — Threat detection (scanning, DoS)
%ASA-5-111008  — User executed command (admin activity)
%ASA-6-605005  — Login permitted (admin login)
%ASA-3-710003  — Deny TCP connection (management ACL)
Quick Validation Checklist
Check Command Expected

ASA logging enabled

show logging

Logging: enabled

ASA target configured

show run logging | include host

logging host <intf> <rsyslog-ip>

rsyslog listening

ss -ulnp | grep 514

UDP *:514

Packets arriving

sudo tcpdump -i any port 514 -c 5

Packets from ASA IP

Logs on disk

tail /var/log/syslog | grep <asa-ip>

ASA messages present

Firewall open

sudo iptables -L -n | grep 514

ACCEPT rule for 514

Investigation: Spam Bypass — SCL 9 Delivered to Inbox

Incident Summary
Field Value

Date Reported

2026-06-08

Sender

dccs@dccsconsulting.com

Subject

Nick Mezza, CFO, Healthcare Financial Executive

SCL

9 (definitive spam)

BCL

2 (low bulk)

Expected Action

Quarantine or Junk

Actual Action

Delivered to inbox

Affected

erosado@chla.usc.edu, wcox@chla.usc.edu

Not Affected

csandoval@chla.usc.edu (correctly filtered)

SCL 9 is the highest spam confidence level — Microsoft classifies this as definitive spam. Default EOP behavior at SCL ≥ 6 is to move to Junk. At SCL 9, most orgs quarantine. Delivery to inbox means something is overriding the verdict.

Hypothesis Tree
  1. Per-user safe sender list — user or Outlook rule whitelisted the sender/domain

  2. Transport rule override — Exchange mail flow rule setting SCL to -1 (bypass)

  3. Connection filter IP allow list — sender IP whitelisted at org level

  4. Anti-spam policy scope — affected users not covered by the correct policy

  5. Junk mail disabled — per-mailbox junk email processing turned off

ROOT CAUSE IDENTIFIED: "Allowed by user policy / trusted recipient domain list"

EOP message headers show system override SFV:SKA — message allowed by safe sender/domain list at user level. This means the user (or an admin policy) has whitelisted the sender or the sender’s domain in their junk email configuration. The SCL 9 verdict was correct but overridden at delivery time.

Phase 0: Confirm the Override (run FIRST)
Pull the full anti-spam headers for the delivered message
# Get the message trace ID
$trace = Get-MessageTrace -SenderAddress "dccs@dccsconsulting.com" -RecipientAddress "erosado@chla.usc.edu" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date)
$trace | Format-List MessageTraceId, Received, Status, Subject

# Get detailed events — look for the override
Get-MessageTraceDetail -MessageTraceId $trace.MessageTraceId -RecipientAddress "erosado@chla.usc.edu" | Format-List Date, Event, Action, Detail, Data

# Same for wcox
$trace2 = Get-MessageTrace -SenderAddress "dccs@dccsconsulting.com" -RecipientAddress "wcox@chla.usc.edu" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date)
Get-MessageTraceDetail -MessageTraceId $trace2.MessageTraceId -RecipientAddress "wcox@chla.usc.edu" | Format-List Date, Event, Action, Detail, Data

# Control — csandoval (should show filtered)
$trace3 = Get-MessageTrace -SenderAddress "dccs@dccsconsulting.com" -RecipientAddress "csandoval@chla.usc.edu" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date)
if ($trace3) { Get-MessageTraceDetail -MessageTraceId $trace3.MessageTraceId -RecipientAddress "csandoval@chla.usc.edu" | Format-List Date, Event, Action, Detail, Data }
Phase 1: Per-User Junk Configuration — Safe Sender/Domain Lists
Check junk email settings for all three users
# Connect to Exchange Online (if not already)
Connect-ExchangeOnline

# Affected users — compare settings
Get-MailboxJunkEmailConfiguration "erosado@chla.usc.edu" | Format-List Enabled, TrustedSendersAndDomains, BlockedSendersAndDomains, ContactsTrusted, TrustedListsOnly
Get-MailboxJunkEmailConfiguration "wcox@chla.usc.edu" | Format-List Enabled, TrustedSendersAndDomains, BlockedSendersAndDomains, ContactsTrusted, TrustedListsOnly

# Control — not affected
Get-MailboxJunkEmailConfiguration "csandoval@chla.usc.edu" | Format-List Enabled, TrustedSendersAndDomains, BlockedSendersAndDomains, ContactsTrusted, TrustedListsOnly
What to look for
Enabled: False         ← PROBLEM: junk mail processing disabled entirely
ContactsTrusted: True  ← PROBLEM: all contacts auto-whitelisted
TrustedSendersAndDomains contains "dccsconsulting.com" or "dccs@dccsconsulting.com"
                       ← PROBLEM: sender explicitly whitelisted — THIS IS THE MOST LIKELY CAUSE
Dump the FULL safe sender list for affected users (may be large)
# Full safe sender list — erosado
(Get-MailboxJunkEmailConfiguration "erosado@chla.usc.edu").TrustedSendersAndDomains | Sort-Object

# Full safe sender list — wcox
(Get-MailboxJunkEmailConfiguration "wcox@chla.usc.edu").TrustedSendersAndDomains | Sort-Object

# Search specifically for the offending domain
(Get-MailboxJunkEmailConfiguration "erosado@chla.usc.edu").TrustedSendersAndDomains | Where-Object { $_ -like "*dccsconsulting*" }
(Get-MailboxJunkEmailConfiguration "wcox@chla.usc.edu").TrustedSendersAndDomains | Where-Object { $_ -like "*dccsconsulting*" }

# Control — csandoval should NOT have it
(Get-MailboxJunkEmailConfiguration "csandoval@chla.usc.edu").TrustedSendersAndDomains | Where-Object { $_ -like "*dccsconsulting*" }
Count how many safe senders each user has (scope of the problem)
@("erosado", "wcox", "csandoval") | ForEach-Object {
    $config = Get-MailboxJunkEmailConfiguration "$_@chla.usc.edu"
    [PSCustomObject]@{
        User = $_
        Enabled = $config.Enabled
        ContactsTrusted = $config.ContactsTrusted
        TrustedCount = $config.TrustedSendersAndDomains.Count
        BlockedCount = $config.BlockedSendersAndDomains.Count
    }
} | Format-Table -AutoSize
Check if ANY user org-wide has this domain whitelisted
# WARNING: slow on large orgs — run during off-hours or limit scope
Get-Mailbox -ResultSize Unlimited | ForEach-Object {
    $junk = Get-MailboxJunkEmailConfiguration $_.PrimarySmtpAddress -ErrorAction SilentlyContinue
    if ($junk.TrustedSendersAndDomains -like "*dccsconsulting*") {
        [PSCustomObject]@{
            User = $_.PrimarySmtpAddress
            Match = ($junk.TrustedSendersAndDomains | Where-Object { $_ -like "*dccsconsulting*" })
        }
    }
} | Format-Table -AutoSize
Remove the offending entry from affected users
# Remove specific sender from safe list — erosado
Set-MailboxJunkEmailConfiguration "erosado@chla.usc.edu" -TrustedSendersAndDomains @{Remove="dccs@dccsconsulting.com"}
Set-MailboxJunkEmailConfiguration "erosado@chla.usc.edu" -TrustedSendersAndDomains @{Remove="dccsconsulting.com"}

# Remove specific sender from safe list — wcox
Set-MailboxJunkEmailConfiguration "wcox@chla.usc.edu" -TrustedSendersAndDomains @{Remove="dccs@dccsconsulting.com"}
Set-MailboxJunkEmailConfiguration "wcox@chla.usc.edu" -TrustedSendersAndDomains @{Remove="dccsconsulting.com"}

# Verify removal
(Get-MailboxJunkEmailConfiguration "erosado@chla.usc.edu").TrustedSendersAndDomains | Where-Object { $_ -like "*dccsconsulting*" }
(Get-MailboxJunkEmailConfiguration "wcox@chla.usc.edu").TrustedSendersAndDomains | Where-Object { $_ -like "*dccsconsulting*" }
Phase 1.5: Check Outlook Inbox Rules (users can create forwarding/move rules that bypass junk)
# Check inbox rules for erosado — look for rules moving spam to inbox or auto-forwarding
Get-InboxRule -Mailbox "erosado@chla.usc.edu" | Format-List Name, Enabled, Description, MoveToFolder, ForwardTo, RedirectTo, MarkAsRead, StopProcessingRules

# Check inbox rules for wcox
Get-InboxRule -Mailbox "wcox@chla.usc.edu" | Format-List Name, Enabled, Description, MoveToFolder, ForwardTo, RedirectTo, MarkAsRead, StopProcessingRules

# Look for rules that match the sender domain
Get-InboxRule -Mailbox "erosado@chla.usc.edu" | Where-Object { $_.Description -like "*dccsconsulting*" -or $_.FromAddressContainsWords -like "*dccs*" }
Get-InboxRule -Mailbox "wcox@chla.usc.edu" | Where-Object { $_.Description -like "*dccsconsulting*" -or $_.FromAddressContainsWords -like "*dccs*" }
Phase 1.6: Anti-Spam Policy Override Settings
# Check if policies allow user overrides (safe sender lists)
Get-HostedContentFilterPolicy | Format-List Name, AllowedSenders, AllowedSenderDomains, EnableUserOverrides

# If EnableUserOverrides is True — users CAN whitelist senders that override SCL verdicts
# To PREVENT users from overriding high-confidence spam:
# Set-HostedContentFilterPolicy -Identity "Default" -EnableUserOverrides $false
# WARNING: org-wide impact — discuss with team before applying
Phase 2: Message Trace — What Actually Happened
Trace the specific message for all three recipients
# Trace for affected users
Get-MessageTrace -SenderAddress "dccs@dccsconsulting.com" -RecipientAddress "erosado@chla.usc.edu" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) | Format-List Received, Subject, Status, ToIP, FromIP, Size, MessageTraceId

Get-MessageTrace -SenderAddress "dccs@dccsconsulting.com" -RecipientAddress "wcox@chla.usc.edu" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) | Format-List Received, Subject, Status, ToIP, FromIP, Size, MessageTraceId

# Control — should show FilteredAsSpam or similar
Get-MessageTrace -SenderAddress "dccs@dccsconsulting.com" -RecipientAddress "csandoval@chla.usc.edu" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) | Format-List Received, Subject, Status, ToIP, FromIP, Size, MessageTraceId
Get detailed trace (shows which filter acted)
# Get MessageTraceId from above, then:
$traceId = "<MessageTraceId from erosado trace>"
Get-MessageTraceDetail -MessageTraceId $traceId -RecipientAddress "erosado@chla.usc.edu" | Format-List Date, Event, Action, Detail, Data
Phase 3: Anti-Spam Policy — Which Policy Applies
List all anti-spam policies and their SCL actions
# All content filter policies
Get-HostedContentFilterPolicy | Format-List Name, SpamAction, HighConfidenceSpamAction, BulkSpamAction, BulkThreshold, PhishSpamAction, HighConfidencePhishAction, IsDefault

# All content filter rules (who gets which policy)
Get-HostedContentFilterRule | Format-List Name, HostedContentFilterPolicy, SentTo, SentToMemberOf, RecipientDomainIs, Priority, State
What to look for
HighConfidenceSpamAction: MoveToJmf or Quarantine  ← correct
HighConfidenceSpamAction: NoAction or Redirect      ← PROBLEM

# Check if affected users are excluded from a stricter policy
# or covered by a permissive one
Phase 4: Transport Rules — SCL Override Check
Check for mail flow rules that modify SCL
# Find any rule that sets SCL to -1 (bypass spam filtering)
Get-TransportRule | Where-Object { $_.SetSCL -eq -1 } | Format-List Name, State, Priority, Conditions, FromAddressContainsWords, SenderDomainIs

# Broader — any rule touching SCL
Get-TransportRule | Where-Object { $_.SetSCL -ne $null } | Format-List Name, SetSCL, State, Conditions

# Full dump of all active transport rules (look for sender/domain matches)
Get-TransportRule | Where-Object { $_.State -eq 'Enabled' } | Format-List Name, Priority, Conditions, Actions, SetSCL
Phase 5: Connection Filter — IP Allow List
Check if sender IP is whitelisted at connection level
Get-HostedConnectionFilterPolicy | Format-List Name, IPAllowList, IPBlockList, EnableSafeList
Phase 6: Org-Wide Safe Sender (Tenant Allow/Block List)
Check tenant-level allow entries
# Check if sender or domain is in tenant allow list
Get-TenantAllowBlockListItems -ListType Sender | Where-Object { $_.Value -like "*dccsconsulting*" } | Format-List Value, Action, ExpirationDate, Notes

# Also check URL list (sometimes domains end up here)
Get-TenantAllowBlockListItems -ListType Url | Where-Object { $_.Value -like "*dccsconsulting*" }
Phase 7: Abnormal Security — Did It See This?
Check if Abnormal flagged or missed this message
# In Abnormal Security console:
# Search → dccs@dccsconsulting.com
# Check: Was it analyzed? Was it flagged? Did Abnormal remediate?
# If Abnormal is in read-only mode, it may have detected but not acted.
Root Cause Matrix

After running Phase 1-6, fill in:

Check Result Implication

Junk Enabled (erosado)

_

If False — junk mail disabled, all spam delivers to inbox

Junk Enabled (wcox)

_

Same

Junk Enabled (csandoval)

_

Expected: True (control case)

Safe Sender match

_

If sender/domain in TrustedSendersAndDomains — user override

Transport Rule SCL -1

_

If match — org-level bypass, affects all users in scope

Anti-Spam Policy SCL 9 Action

_

If NoAction — policy misconfigured

Connection Filter IP Allow

_

If sender IP allowed — all messages from that IP bypass spam

Tenant Allow List

_

If sender allowed — explicit org override

Immediate Remediation (pending root cause)
# If junk mail is disabled on affected mailboxes — re-enable:
Set-MailboxJunkEmailConfiguration "erosado@chla.usc.edu" -Enabled $true
Set-MailboxJunkEmailConfiguration "wcox@chla.usc.edu" -Enabled $true

# If sender is in safe sender list — remove:
# (Get specific list first, then remove the entry)

# Block the sender immediately at tenant level:
New-TenantAllowBlockListItems -ListType Sender -Entries "dccs@dccsconsulting.com" -Block -NoExpiration -Notes "SCL 9 spam delivered to inbox — investigation 2026-06-08"

Timesheet: 2026-06-01 — 2026-06-05

Monday 06-01

Project Code Hours Activity Description

Tube System Upgrade

_

3.0

ISE batch onboard script debugging — fixed 7 var++ bugs + local scope. 15 MACs staged for re-run. iTrack 3528165

Abnormal Security (ESA→EOP)

_

2.0

Policy review prep — EOP cmdlet mapping (5 cmdlets), Jihad spreadsheet review, Tyler migration doc review

ISE Policy / Change Management

_

2.5

CR board prep — Guest ACL Hardening + Anonymous Identity Test. CR document review, lab validation planning

CISSP Study / Admin

_

0.5

Exam scheduling coordination

Total

8.0

Tuesday 06-02

Project Code Hours Activity Description

Change Management

_

2.0

CR Board attendance — Guest ACL Hardening (APPROVED), Anonymous Identity Test (APPROVED). Post-approval coordination

Linux Research / Server Deployment

_

2.0

Linux Remediation kickoff meeting + inventory SQL query development (dc-run-sql)

Abnormal Security (ESA→EOP)

_

2.5

DKIM investigation (PowerShell shows disabled), ESA→EOP policy divergence analysis, d001 deliverable

ISE Annual Cert Renewal

_

1.0

Cert renewal meeting — 52 days to expiry, DigiCert CA, CSR generation prep

Spectrum TV/GetWell iPad Refresh

_

0.5

Android handheld scanners — ISE policy scoping for shared device auth (Argam escalation)

Total

8.0

Wednesday 06-03

Project Code Hours Activity Description

Abnormal Security (ESA→EOP)

_

3.0

ESA mail flow policy divergence — full Five Canons analysis. ESA-Bypass skipping blacklist enforcement. EOP anti-spam BCL/SCL policy review

ISE Annual Cert Renewal

_

1.0

CSR generation commands prepared, d001 config staged

QRadar → Sentinel / Monad

_

1.5

Monad pipeline weekly sync with William Cox — FMC/ISE sources, transform design, jq↔GJSON translation reference

Spectrum TV/GetWell iPad Refresh

_

1.0

Getwell iPads — iPSK onboard 2 devices (4C:B9:10:9F:05:9F, C4:12:34:2D:F3:14)

ISE Policy / General Support

_

1.5

Carry-forward task management, CR implementation scheduling coordination (Guest ACL + Anonymous Identity)

Total

8.0

Thursday 06-04

Project Code Hours Activity Description

QRadar → Sentinel / Monad

_

4.0

Monad API discovery — JWT decode, OpenAPI spec, pipeline CRUD operations, edge constraints. Created ise-lab-v2 filtered pipeline via API

ISE Annual Cert Renewal

_

1.0

TLS cert fingerprint script + runbook created (d001 encrypted)

Centralized rsyslog Server

_

1.0

rsyslog central collector partial created (d001 encrypted)

Abnormal Security (ESA→EOP)

_

1.0

ESA-Bypass investigation continued — policy divergence follow-ups

Admin / PeopleSoft

_

1.0

PeopleSoft codes tracker updated — all 28 active projects audited and mapped

Total

8.0

Friday 06-05

Project Code Hours Activity Description

Abnormal Security (ESA→EOP)

_

2.0

ESA-Bypass policy divergence follow-ups, DKIM investigation continued, AutoForwarding remediation

ISE Policy / General Support

_

2.0

Carry-forward items: Tube System re-run coordination, Alex Pena device verification, Android scanners policy (June 8 deadline)

Change Management

_

1.5

Guest ACL + Anonymous Identity implementation scheduling with Tony Sun, David Rukiza, Argam

Linux Research / Server Deployment

_

1.5

Linux inventory discovery — query refinement, dc-run-sql validation

Documentation / Admin

_

1.0

Worklog triage, task prioritization, PeopleSoft code assignment

Total

8.0

Weekly Summary by Project

Project Mon Tue Wed Thu Fri Total

Abnormal Security (ESA→EOP)

2.0

2.5

3.0

1.0

2.0

10.5

QRadar → Sentinel / Monad

1.5

4.0

5.5

Change Management / CRs

2.5

2.0

1.5

6.0

ISE Annual Cert Renewal

1.0

1.0

1.0

3.0

Tube System Upgrade

3.0

3.0

Linux Research / Remediation

2.0

1.5

3.5

Spectrum/GetWell/Scanners

0.5

1.0

1.5

Centralized rsyslog

1.0

1.0

ISE Policy / General Support

1.5

2.0

3.5

Admin / Documentation

0.5

1.0

1.0

2.5

Daily Total

8.0

8.0

8.0

8.0

8.0

40.0


Work (CHLA)

CHARGE TIME IN PEOPLESOFT - CRITICAL. Do this NOW before anything else.

Critical (P0)

Project Description Owner Status Due Blocker

Linux Research (Xianming Ding)

EAP-TLS for Linux workstations, dACL, UFW

Evan

BEHIND (72 days overdue)

02-24

Certificate "password required" - nmcli fix documented

iPSK Manager

Pre-shared key automation

Ben Castillo

BEHIND

 — 

DB replication issues

MSCHAPv2 Migration

Legacy auth deprecation — 6,227 devices, 5 waves. 6 batch SQL queries + 3-API endpoint profile script added (05-11). Report due.

Evan

25% — Report due, batch queries ready

05-30

Report to turn in

Research Segmentation

All endpoints to Untrusted VLAN

Evan

BLOCKED

 — 

CISO decision pending

Disaster Recovery

ISE DR scoping — dot1x closed mode = total blackout

Evan

Scoping

 — 

 — 

Mandiant Remediation

Copy 4/16 findings, Guest ACL lab, Q2 assessment

Evan

Active

 — 

 — 

SIEM QRadar → Sentinel

Full SIEM platform transition. Monad console error resolved 05-12. Secrets configured. Blocked on DCR creation (Rule ID + Stream Name). Azure private network policy unresolved.

Evan

Active — blocked on DCR

Q2 2026

Victor/Mauricio: create DCR, resolve Azure network policy

Abnormal Security

AI email platform — ESA cutover. CR assigned, CAB May 12 15:00. Implementation May 14 10:00.

Evan

Active — CAB today 15:00

05-14

Pre-CAB checklist: confirm Tyler, Jason, Sarah

High Priority (P1)

Project Description Owner Status Target

ISE 3.4 Migration

Upgrade from 3.2p9

Evan

Blocked — maintenance window needed

Q2 2026

Switch Upgrades

IOS-XE fleet update (C9300, 3560CX)

Evan

Pending

Q2 2026

Spikewell BYOD VPN

dACL SQL, AD group integration

Evan

Active

 — 

Strongline Gateway

MAC capture, Identity Group setup — 37 days aging

Evan

Active — David Rukiza assigned

 — 

Abnormal Security

AI email security platform research, ESA cutover timeline

Evan

Newly assigned

 — 

DMZ Migration

External services audit behind NetScaler

Evan

Audit phase

 — 

Firewall Audit (murus-portae)

EtherChannel query, prefilter, policy assignments

Evan

Scoping — ASA API creds needed

 — 

iPSK Manager HA

Server 2 config, TLS, SQL security audit

Evan

In progress

 — 

Sentinel KQL

Build proficiency, distinguish from team

Evan

Onboarding

 — 

VNC Blocking

Block and eliminate VNC protocol enterprise-wide

Evan

Active — Phase 0 (Discovery)

Mid-June 2026

Strategic (P2)

Project Description Owner Status

HHS Regulatory Compliance

New HHS security policies implementation

TBD

NOT STARTED

InfoSec Reporting Dashboard

PowerBI metrics for executives

TBD

NOT STARTED

EDR Migration (AMP → Defender)

Endpoint protection consolidation

TBD

NOT STARTED

Azure Legacy Migration

Modern landing zone

Team

In Progress

ChromeOS EAP-TLS

SCEP + Victor, Paul testing

Victor

In Progress

P0 — Critical / Blocking

Security & Compliance

  • ISE 3.2 Patch 10 upgrade — CVE-2026-20147 CVSS 9.9 / CVE-2026-20148. Propose maintenance window once patch confirmed on software.cisco.com.

  • ISE Advisory sa-ise-rce-traversal-8bYndVrZ — check Patch 10 availability

  • Mandiant Remediation — findings status tracked. Working session prep + defensive posture documented (comms-2026-04-24). Copy 4/16 updates into Excel at work. Guest ACL lockdown (WIR-M-01) pending lab validation. appendix-todos updated with MSCHAPv2 milestones.

  • Guest ACL update — guest redirect ACL work needed. Lab validate GUEST_CWA_REDIRECT_MAX_SECURITY in d000, then joint CR with NE. On today’s task list.

  • Disaster Recovery & Downtime Procedures — ISE top priority (dot1x closed mode = SPOF for network access)

    • ISE DR: Document failover sequence — PAN, MnT, PSN priority order

    • ISE DR: RADIUS dead-server detection on WLCs/switches — critical-auth VLAN fallback

    • ISE DR: Backup/restore procedures — scheduled config backups, tested restores

    • FTD/FMC DR: FMC loss = no policy management

    • Network DR: Core/distribution switch failure, STP reconvergence, HSRP failover

    • Document RTO/RPO per system

SIEM Migration (QRadar → Sentinel)

  • SIEM QRadar → Sentinel Migration — LEAD ROLE. 4 collection iterations (Apr 16, 17, 17-streamlined, 20-streamlined). Python chart pipeline built (qradar-charts.py). Migration XLSX generated. Verification pending. Comms sent Apr 23.

    • d001 artifacts: 8 JSON exports, 2 CSV inventories, migration XLSX, top5 source SVG/PNG, verification doc

    • Dependency: Monad pipeline for log source transition

    • Dependency: Sentinel KQL proficiency for query migration

  • Monad Pipeline Evaluation (origin: 2026-03-11) — lead role. Console error RESOLVED 05-12. 06-09: Architecture decision — rsyslog (CHLXSYSLOG01) as collection tier → Monad → Sentinel. ISE lab → rsyslog → Monad 6-step execution guide created with 10 API calls. ASA lab logs already flowing through rsyslog. DCR still needed — Victor + Mauricio.

  • Sentinel KQL — build proficiency, distinguish from team. Azure portal access acquired.

  • QRadar log source report — run AQL queries, fetch JSON, generate Python Excel

Active Deployments & Migrations

  • MSCHAPv2 Migration — 6-sheet Standard Report ready. Migration window 05-04 to 05-30 CLOSED. Confirm final report status and next steps with team. 6,227 MSCHAPv2 devices, 14,249 EAP-TLS/TEAP (70% migrated).

  • MSCHAPv2 weekly cadence — recurring Wednesday call established (first 04-22). Completed 2026-04-22.

  • MSCHAPv2 ownership matrix — sent in scoping email 4/24 with manager callouts (@Albert, @John). Completed 2026-04-24.

  • TCP Clocks deployment — Batch 1: 7 clocks validated (OUI 40:AC:8D). Batch 2 (06-09): 9 new MACs (OUI 40:AC:BD) added via ERS. 1 one-off reassigned. New switch deployed without RADIUS/AAA — clocks can’t authenticate. Switch onboarding template + 3 validation queries documented. ERS queries self-contained with ers function.

  • SRT Research VLAN — confirm roles with Tony Sun: Tony implementor, Evan tester. CAB approved 04-21.

  • Downtime Computers enforcement — draft ISE AuthZ rule: medigate_724 + Wireless = DenyAccess. Separate CR. d001: DC queries, audit CSVs (v1-v3), wireless violations report delivered 04-21.

  • Enterprise Linux 802.1X — standardize Shahab/Ding deployment (CISO priority). Overdue since 02-24. Blocked by nmcli cert fix.

  • Abnormal Security — CR-2026-05-07. Implemented 05-13. 06-09 update: Full policy review — 20-section EOP validation commands rebuilt, Hoxhunt SCL-1 investigation (intentional bypass confirmed), sclizer junk folder triage (~800 emails), Outlook reactions audit added, Connect-ExchangeOnline msalruntime fix documented. ESA migration expansion in progress — priority to move off ESA to full environment.

    • Team: Cox/William, Landeros/Jason, Rosado/Evan, Naranjo/Mauricio, Sandoval/Carlos

  • ASA VPN: Okta RADIUS → Entra SAML — (NEW 06-09) 5-phase migration plan built. ASA baseline captured (2 tunnel groups: CHLA_CORPORATE_USERS, CHLA_BYOD_USERS). 6 ISE policy screenshots. Tony Sun (ASA), Justin Halbmann (Entra/Okta), Evan (ISE). VPN cert expires 07-28. PDF deliverable ready. Share with team this week.

Tube System Upgrade (NEW — 06-01)

  • Tube System Upgrade — iTrack 3528165. 15x 10" TS stations need MAC addresses added to ISE identity group IoT_Onboard. MACs received from vendor (C8:1A:FE:20:xx:xx series). Station list spans ICU (CTICU, PICU, BMT, NICU, NICCU), ED, Surgery, Trauma, Pharmacy. Vendor contact: John Genest. Rationale: manufacturer no longer supports current system; failure risks delayed/missed patient care.

BMS Controller Segmentation (MIGRATED — 06-09)

  • BMS Controller Segmentation — Full migration from Principia LaTeX to d001. 12 partials, 5 Mermaid diagrams, 4 legacy PDFs, ISE screenshots. d001 open bms-controller. Completed 2026-06-09.

BMS Device Inventory (NEW — 04-24)

  • BMS Device Inventory — 72 devices discovered across 37 switches (04-24). Profile-driven architecture (Claroty/Medigate). 16 queries built. Phase 0 complete. Next: cross-reference with Visio diagrams, classify by function, begin D2 diagrams. Cleanup: delete 4 orphaned test groups, migrate 4 retire-dACL devices, investigate 3 null-profile devices.

VNC Blocking (NEW — 05-11)

  • VNC Blocking — block and eliminate VNC enterprise-wide. Due mid-June 2026. Phase 0: discovery. January AQL query baseline to incorporate. Cross-reference BMS inventory for VNC-capable devices.

Investigations & Audits

  • Murus Portae (WAF) — Phase 0 discovery in progress. FMC cert expired. d001: DMZ NetScaler WAF investigation, zone map, architecture D2 diagrams (v1+v2 SVGs), FMC REST API reference guide, ops script. FMC API returning zero ACP rules — under investigation.

  • Firewall audit — FMC discovery inventory done (d001: fmc-discovery-2026-04-16). EtherChannel query, prefilter, policy assignments pending.

  • IoT Dr. Kim devices — RECURRING. All 4 MACs validated in IoT_iPSK_VLAN1620_Misc (04-24). v2 validation queries built with 7 deep analysis queries (group flapping, credential leakage, profile drift, NAS tracking, remediation timeline, deny audit, OUI scan). Revalidate — confirm no flapping since 04-24.

  • IoT device validation queries — v2 created with partials architecture, 16 queries across ERS/MnT/DataConnect/FMC. Completed 2026-04-24.

Stale Blockers (carried via carryover tracker)

  • k3s NAT verification — rule 170, 10.42.0.0/16 pod network (origin: 2026-03-09). 92 days. Blocks Wazuh indexer recovery → blocks SIEM visibility. Decide: test or defer to Q3.

  • Strongline Gateway VLAN fix — 8 devices wrong identity group (origin: 2026-03-16). 85 days. David Rukiza assigned — follow up on status.

Administrative

  • PeopleSoft — track time for current week

  • iTrack tickets — close open tickets

  • KQL library — build initial queries in codex + d001

  • Linux Research project — finalize and review

  • Tax filing 2025 (MFJ) — see encrypted case file in data/d000/personal/ for details and action items

P1 — Important

  • MSCHAPv2 action-item tracker — owner/status/next-steps per workstream

  • ISE admin MFA enforcement — recommendation tied to advisory (interim control pending Patch 10)

  • DMZ Migration — external services audit behind NetScaler. Linked to Murus Portae investigation.

  • Vocera/Wyse iTrack RCA — complete root cause report

  • GCC ISE Support — 3/4 nodes restored, PSN-04 deferred

  • Wazuh indexer recovery — blocked by k3s NAT (origin: 2026-03-09)

  • Vocera EAP-TLS Supplicant Fix (origin: 2026-03-12)

  • iPSK Manager HA — blocked by DB replication (Ben Castillo)

  • ISE 3.4 Migration — depends on Patch 10 completion first

  • Git history scrub — murus-portae-output.md + ise-analytics CSVs

  • Encrypt prep-cmds-2026-04-15.adoc — plaintext committed to git

  • ISE MnT Messaging Service — enable UDP syslog delivery (maintenance window needed)

Infrastructure (Personal)

  • Borg backups — test and validate on ALL systems (Razer, P16g, vault-01, bind-01, kvm-01, kvm-02)

  • Borg — verify backup script paths updated from dotfiles-optimus to dots-quantum

  • Borg — create initial archive for ThinkPad P16g if none exists

  • Libvirt VLAN hook debug on both KVMs

  • Te1/0/2 cable replacement and re-test

  • Vault Raft cluster — verify vault-01 rejoined

  • Fix EAP-TLS keyring/secrets issue on Razer workstation

Completed (confirmed — do not delete, archive only)

  • CR-2026-04-15 SRT Research VLAN — submitted to iTrack. Completed 2026-04-15.

  • CAB presentation 4/21 — SRT Research VLAN 233 → CHLA-Research. APPROVED. Completed 2026-04-21.

  • Downtime Computers wireless audit — 45 computers, 16 violating, v3 report delivered. Completed 2026-04-21.

  • Git identity fix — dots-quantum/git/.gitconfig email corrected. Completed 2026-04-21.

  • MSCHAPv2 10:30 meeting — next steps + ACL coordination. Completed 2026-04-17.

Service Requests (SR)

SR# Request Requestor Opened Status

3508542

Zoll cards connection issue

STALE — verify in iTrack

3508524

Disable dot1x on (2) network ports - 5th floor 3250 Wilshire (PXE-boot imaging issues)

STALE — verify in iTrack (issues persisted after disable)

3528165

Tube System Upgrade — 15 stations, MAC addresses for ISE IoT_Onboard identity group

Genest, John (vendor contact)

2026-06-01

NEW — MACs received, need ISE onboarding

Incidents (INC)

INC# Priority Description Opened SLA Status

1911859

Strongline Gateways in Miscellaneous Subnet

STALE — verify in iTrack (related to carryover P0)

Change Requests - Emergency (ECAB)

CR# Description Opened Scheduled Status

No emergency changes

Change Requests - Normal

CR# Description Opened Scheduled Status

No normal changes

Change Requests - Scheduled/Standard

CR# Description Opened Window Status

No scheduled changes

Change Requests - Root Cause / Post-Incident

CR# Description Related INC Opened Status

100451

Vocera Phones and Wyse devices went off network

STALE — verify in iTrack


Session Accomplishments (Claude Code)

CLAUDE.md Review & Correction

  • Fixed build invariant contradiction (make | grep → full output review)

  • Added STD-024 (AsciiDoc Build Toolchain) to standards registry

  • Expanded file naming table: 6 missing prefixes (PRJ, SESSION, TEMPLATE, REPORT, INVENTORY, YEAR)

  • Rebuilt directory skeleton: 21 page dirs, 17 partial dirs, examples, images

  • Documented full Makefile target taxonomy (~40 targets)

  • Updated component description: added competencies, sessions

PeopleSoft Timesheet System

  • 13 weekly timesheet partials generated (Mar 09 – Jun 05, 520 hours)

  • Scalable architecture: partials/trackers/work/peoplesoft-codes/timesheet-YYYY-MM-DD.adoc

  • PRJ-peoplesoft-time-entry.adoc wired with all 13 timesheets

  • 4 agents parallelized for generation across 12 weeks

P1: Spam Bypass Investigation (SCL 9 Delivered to Inbox)

  • Root cause identified: SFV:SKA — user safe sender list override

  • 7-phase PowerShell investigation with per-user junk config, message trace, transport rules, tenant allow/block

  • spam-bypass-investigation.adoc — full runbook with root cause matrix

P1: Intune Hybrid Domain Join — Cert Auth Failure

  • Devices failing EAP-TLS WiFi auth, forget/rejoin fixes it

  • Hybrid domain join = dual cert source (GPO AD CS + Intune SCEP/PKCS)

  • ISE DataConnect bulk queries: failure grouping, affected device list, forget/rejoin pattern confirmation

  • Control comparison commands (working machine vs affected)

  • intune-cert-investigation.adoc — full runbook with endpoint + ISE queries

rsyslog CHLXSYSLOG01 Deployment

  • First SSH login to Debian 13 syslog collector (10.248.13.254)

  • Server recon: rsyslog 8.2504.0, UDP+TCP 514 listening, 12G /var, 436G /home

  • ASA logging config documented: AnyC-FP-2140-1 + USC-TEST-RAVPN-5515

  • rsyslog-asa-troubleshooting.adoc — tmux layout, Phase 0-7 with live monitoring

  • rsyslog-ops.adoc — full command reference, fixed for ISO 8601 + MSWinEventLog (encrypted in d001)

  • Windows Event Logs confirmed arriving from L-N63064 (carlsandoval), L-N41999 (mnaranjo)

build-antora-page.sh — Nested Include Fix

  • Fixed recursive partial resolution — copies entire partials/examples trees, rewrites every file

  • PDFs went from 172K (broken, missing sections) to 1.8-2.2MB (complete)

  • Zero errors on both WRKLOG-2026-06-07 and WRKLOG-2026-06-08

API Rate Limits Reference

  • data/d001/api/max-api-calls.adoc.age — ISE, FMC, Graph, Sentinel, Monad, QRadar, Abnormal

  • Retry strategy and rate limit detection patterns included

Project Audit

  • CHLA: P0/P1/P2 trackers 47 days stale, 6 projects missing from trackers, Abnormal duplicate

  • Personal: 106 project partials, 27 pages, 79 partials without pages

  • Identified stale blockers: k3s NAT (59 days), Strongline (52 days)


Personal

In Progress

Project Description Status Notes

k3s Platform

Production k3s cluster on kvm-01

Active

Prometheus, Grafana, Wazuh deployed

Wazuh Archives

Enable archives indexing in Filebeat

Active

PVC fix pending

kvm-02 Hardware

Supermicro B deployment

Active

Hardware ready, RAM upgrade done

Planned

Project Description Target Blocked By

Vault HA (3-node)

vault-02, vault-03 on kvm-02

Q2 2026 (slipped from Q1)

kvm-02 deployment

k3s HA (3-node)

Control plane HA

Q2 2026 (slipped from Q1)

kvm-02 deployment

ArgoCD GitOps

k3s GitOps deployment

After k3s stable

 — 

MinIO S3

Object storage for k3s

After ArgoCD

 — 

Domus Inventory

Personal asset management (YAML + CLI + AsciiDoc)

Q2 2026

Schema approved

Active — Infrastructure

Task Details Priority Status Due

Wazuh agent deployment

Deploy agents to all infrastructure hosts

P2

Pending

After archives fix

k3s Platform

Production k3s cluster on kvm-01

P1

In Progress

 — 

Wazuh Archives

Enable archives indexing in Filebeat, PVC fix

P1

In Progress

 — 

kvm-02 Hardware

Supermicro B deployment, RAM upgrade done

P1

In Progress

 — 


Active — Security & Encryption

Task Details Priority Status Due

Configure 4th YubiKey

SSH FIDO2 keys

P1

TODO

 — 

Cold storage M-DISC backup

age-encrypted archives

P1

TODO

After YubiKey setup


Active — Development & Tools

Task Details Priority Status Due

netapi Commercialization

Go CLI rewrite with Cobra-style argument discovery, package for distribution

P0

Active

 — 

Ollama API Service

FastAPI (17 endpoints), productize — config audit, doc tools, runbook gen

P0

Active

 — 

Shell functions (fe, fec, fef)

File hunting helpers

P3

TODO

 — 


Active — Documentation

Task Details Priority Status Due

D2 Catppuccin Mocha styling

domus-* spoke repos (177 files total)

P3

In Progress

 — 


Active — Financial

Task Details Priority Status Due

Amazon order history import

Download CSV from Privacy Central → parse with awk → populate subscriptions tracker

P1

Waiting

Pending Amazon data export (requested 2026-04-04)


Active — Education

Task Details Priority Status Due

No active education tasks — see education trackers


Active — Personal & Life Admin

Task Details Priority Status Due

ThinkPad T16g Setup

Arch install, stow dotfiles, Ollama stack, netapi dev env

P0

Pending

 — 

P50 Arch to Ubuntu migration

CR-2026-03-12

P2

In Progress

 — 

X1 Carbon Ubuntu installs

2 laptops, LUKS encryption

P2

In Progress

 — 

P50 Steam Test

Test Flatpak Steam + apt cleanup of broken i386 packages

P3

Pending

 — 

Documentation Sites

Notes

Day-specific personal notes here.


Education

Claude Code Mastery

Resource Details Progress Status

Claude Code Full Course (4 hrs)

Nick Saraev - YouTube comprehensive course

26:49 / 4:00:00

IN PROGRESS

Claude Code Certification

Anthropic official certification (newly released)

Not started

GOAL

Skills Mastery (Critical)

Certification Deadlines

  • CISSP - July 12, 2026 (10-week plan active — Week 1)

  • RHCSA 9 - Q3 2026 (after CISSP)

  • LPIC-1 - Renewal required (blocks LPIC-2)

Spanish C1 Certification Goals

Certification Provider Target Status Strategy

SIELE C1

Instituto Cervantes / UNAM / Salamanca

Q2 2026

ACTIVE

Computer-based, faster results - take FIRST

DELE C1

Instituto Cervantes

Q3/Q4 2026

PLANNED

After SIELE success, harder exam

DELE C2

Instituto Cervantes

2027

FUTURE

Mastery level - requires extensive immersion

SIELE is computer-adaptive, results in 3 weeks. DELE is paper-based, results in 3-4 months. Do SIELE first to validate readiness.

Don Quijote Writing Practice - DELE C1/C2 Initiative

Method:

  1. Read chapter in original Spanish

  2. Write personal analysis/understanding en espanol

  3. AI review for grammar, vocabulary, register

  4. Build comprehensive understanding of literary elements

Today’s Study

  • Focus: CISSP (41 days to July 12 exam — schedule exam today 06-01), MSCHAPv2 migration wrap-up

  • Secondary: RHCSA curriculum, Spanish SIELE C1

  • CISSP — Security & Risk Management (continuing). Schedule exam this afternoon.

  • RHCSA — continue curriculum phase

  • Spanish — Don Quijote reading + analysis (DTLA study day)

  • MSCHAPv2 — migration window closed 05-30, review final report

Regex Training (CRITICAL)

  • Status: 52 days carried over (since 2026-03-16)

  • Priority: After PeopleSoft, before Quijote

  • Session: Character classes, word boundaries


Infrastructure

Documentation Sites

Site URL Status Actions Needed

Domus Digitalis

docs.domusdigitalis.dev

Active

Validate, harden, improve

Architectus

docs.architectus.dev

Active

Public portfolio site - maintain

HA Deployment Status

System Description Status Notes

VyOS HA

vyos-01 (kvm-01) + vyos-02 (kvm-02) with VRRP VIP

✅ COMPLETE

2026-03-07 - pfSense decommissioned

BIND DNS HA

bind-01 (kvm-01) + bind-02 (kvm-02) with AXFR

✅ COMPLETE

Zone transfer operational

Vault HA

Raft cluster (vault-01/02/03)

✅ COMPLETE

Integrated with PKI

Keycloak Rebuild

keycloak-01 corrupted, rebuild from scratch

🔄 NEXT

Priority P3 - SSO broken

FreeIPA HA

ipa-02 replica planned

📋 PLANNED

Linux auth redundancy

AD DC HA

home-dc02 replication

📋 PLANNED

Windows auth redundancy

iPSK Manager HA

ipsk-mgr-02 with MySQL replication

📋 PLANNED

PSK portal redundancy

ISE HA

PAN HA (ise-01 reconfigure)

⏳ DEFERRED

Wait until ise-02 stable

ISE 3.5 Migration

Upgrade path: 3.2p9 → 3.4 (P1) → 3.5 (target)

📋 PLANNED

After 3.4 Migration completes (Q2 2026)

Single Points of Failure (CRITICAL)

These systems have NO redundancy - outage impacts production.
System Impact if Down Mitigation

ISE (ise-02)

All 802.1X stops - wired and wireless auth fails

ise-01 reconfiguration deferred until ise-02 stable

Keycloak (keycloak-01)

SAML/OIDC SSO broken (ISE admin, Grafana, etc.)

NEXT PRIORITY - Rebuild runbook

FreeIPA (ipa-01)

Linux auth, sudo rules, HBAC fails

ipa-02 replica planned

AD DC (home-dc01)

Windows auth, Kerberos, GPO fails

home-dc02 replica planned

iPSK Manager

Self-service PSK portal unavailable

ipsk-mgr-02 with MySQL replication planned

Validation Tasks

Task Details Status

docs.domusdigitalis.dev validation

Test all cross-references, search, rendering

TODO

docs.domusdigitalis.dev hardening

HTTPS, CSP headers, security review

TODO

docs.architectus.dev validation

Public site content review

TODO

Hub-spoke sync verification

All components building correctly

Ongoing


Quick Commands

Git & GitHub CLI

create GitHub repo from existing local repo
gh repo create <name> --private --source . --remote origin --push
clone a forked repo into a specific directory
gh repo clone EvanusModestus/PowerShell ~/atelier/_projects/work/PowerShell
gh repo clone defaults to SSH. If key is passphrase-protected, load agent first: eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519_github
cross-repo commit search — all domus repos on a specific date
for repo in ~/atelier/_bibliotheca/domus-*/ ~/atelier/_projects/personal/domus-*/; do
  [ -d "$repo/.git" ] || continue
  name=$(basename "$repo")
  git -C "$repo" log --since="2026-04-06" --until="2026-04-07" --format="%h %aI %s" 2>/dev/null |
    awk -v r="$name" '{print r, $0}'
done
commit history touching only today’s modified files
git log --oneline -- $(find . -name "*.adoc" -type f -newermt "$(date +%F)")
unstage a file without losing changes
git restore --staged data/d001/api/ise-dataconnect/output/output-2026-04-24

Safe — removes from staging area only. Working tree is untouched. Use when you accidentally git add a plaintext or output file.

gh CLI — repo discovery and filtering

list repos by name pattern (domus/antora ecosystem)
gh repo list --limit 100 --json name,description \
  | jq -r '.[] | select(.name | test("domus|antora|asciidoc"; "i")) | "\(.name)\t\(.description)"'
top 20 most recently updated repos
gh repo list --limit 100 --json name,description,updatedAt \
  | jq -r 'sort_by(.updatedAt) | reverse | .[:20] | .[] | "\(.updatedAt[:10])\t\(.name)\t\(.description)"'
top 10 repos by disk usage
gh repo list --limit 100 --json name,diskUsage \
  | jq -r '.[] | "\(.diskUsage)\t\(.name)"' | sort -rn | head -10
clone a repo that’s not local yet
gh repo clone EvanusModestus/<repo-name> ~/atelier/_bibliotheca/<repo-name>

find & grep

files modified since midnight today (precise — not "last 24 hours")
find . -name "*.adoc" -type f -newermt "$(date +%F)" | sort
-mtime 0 means "last 24 hours", not "today". -newermt "$(date +%F)" compares against midnight — exact.
case-insensitive file search
find . -iname "*mschap*" -type f | sort
multiple name patterns with -o
find . -type f \( -iname "*ise*" -o -iname "*mschap*" \) | sort
same thing, single regex — fewer parens, extensible
find . -type f -iregex '.*\(ise\|mschap\).*'
exclude directories
find . -type f -iname "*meeting*" \
  -not -path "*/node_modules/*" \
  -not -path "*/.git/*" \
  -not -path "*/build/*"
recent drafts by modification time (newest first)
find .drafts -type f -printf '%T@ %Tc %p\n' | sort -rn | awk '{$1="";print}' | head -3
grep — know what you’re counting
grep -rl "pattern" . --include="*.adoc"         # file count (which files)
grep -rn "pattern" . --include="*.adoc"         # line matches (every occurrence)
grep -rc "pattern" . --include="*.adoc" | grep -v ':0$'  # match count per file
search with context — avoid opening the file
grep -rn -E 'git init|gh repo create' docs/ --include='*.adoc' -B2 -A2

Search codex by content — which files contain a command?

find all PowerShell files that use a specific cmdlet
find docs/modules/ROOT/examples/codex/powershell -type f -name "*.adoc" \
  -exec grep -l 'Get-Process\|Start-Process\|pipeline\|Where-Object' {} \;

Pattern: find -exec grep -l returns only filenames with matches — like grep -rl but with find’s `-type f -name filtering. Use \| for OR in grep basic regex. Swap the pattern for any cmdlet or keyword to locate coverage across the codex.

inventory a codex tool directory — count files per tier
find docs/modules/ROOT -name "powershell" -type d \
  -exec sh -c 'echo "$1: $(find "$1" -type f | wc -l) files"' _ {} \;
find orphaned examples (not included by any page)
for f in $(find docs/modules/ROOT/examples/codex/powershell -name "*.adoc" -type f); do
  base=$(basename "$f")
  dir_parent=$(basename $(dirname "$f"))
  grep -rq "$dir_parent/$base" docs/modules/ROOT/pages/codex/powershell/ \
    docs/modules/ROOT/examples/codex/powershell/*.adoc 2>/dev/null \
    || echo "ORPHAN: $f"
done

find → grep → open in nvim

find by path + content, open result in nvim
nvim $(find -path '*oauth*' -name '*.adoc' -type f \
  -exec grep -l 'timeout\|expire\|reconfig\|token' {} \;)

Command substitution $(…​) feeds all matches as arguments to nvim — opens every hit as a buffer. :bn/:bp to cycle, :ls to list. One file? Opens directly. Five files? All loaded, ready to navigate.

find by content across entire tree, open in nvim
nvim $(find docs/modules/ROOT -name '*.adoc' -type f \
  -exec grep -l 'token.*expire\|oauth.*refresh' {} \;)
open one at a time (sequential — -exec nvim per match)
find -path '*oauth*' -name '*.adoc' -type f \
  -exec grep -l 'timeout\|expire' {} \; \
  -exec nvim {} \;
Trailing \| in grep patterns matches empty string — every file matches. Always end with a term, not a pipe: 'timeout\|expire\|token' not 'timeout\|expire\|token\|'.

Trace Antora partial inclusion chains

who includes this partial? (one level up)
grep -rl 'commands/shell' docs/modules/ROOT/partials/
count all pages that include a partial
grep -rl 'quick-commands' docs/modules/ROOT | wc -l
full chain: partial → assembler → every page that uses it
file="commands/shell"
grep -rl "$file" docs/modules/ROOT/partials/ | while read f; do
  parent=$(basename "$f" .adoc)
  echo "$file -> $parent"
  grep -rl "$parent" docs/modules/ROOT/pages/ | while read p; do
    echo "  -> $(basename "$p")"
  done
done

Pattern: grep -rl finds which files contain the string. Chain two passes — first finds the assembler partial, second finds every page that includes it. Works for any partial in the Antora include hierarchy.

Multi-pattern file search — worklog partial discovery

brute force — one find per partial name
find docs/modules/ROOT -name "*urgent.adoc*" -type f
find docs/modules/ROOT -name "*morning.adoc*" -type f
consolidated — single find with regex (production approach)
find docs/modules/ROOT -type f -regextype posix-extended \
  -regex '.*(urgent|morning|work-chla|personal|education|infrastructure|quick-commands|related)\.adoc' \
  | sort

Pattern: -regextype posix-extended enables | alternation without escaping. One process, one sort — versus 8 separate finds. The sort deduplicates visually and groups by path.

pipeline alternative — find piped to grep
find docs/modules/ROOT -type f -name "*.adoc" \
  | grep -E 'urgent|morning|work-chla|personal|education|infrastructure|quick-commands|related'

Trade-off: the pipeline version is more readable but spawns two processes. The regex version is a single find — faster on large trees, same result.

Cross-repo literary term search — bibliotheca-wide discovery

When searching for a term across the entire _bibliotheca (multiple repos, mixed file types), these patterns escalate from narrow to broad.

1. Single repo — count matches per file
grep -rn --include='*.adoc' -c 'sanchuelo' . | grep -v ':0$'
2. Cross-repo — filenames only (all bibliotheca)
grep -rl --include='*.adoc' -i 'sanchuelo' ~/atelier/_bibliotheca/ | sort
3. Cross-repo with context — see the line in situ
grep -rn --include='*.adoc' -i -B1 -A1 'sanchuelo' ~/atelier/_bibliotheca/domus-captures/
4. Multi-filetype — .adoc + .txt (catches source texts)
grep -rl -i 'sanchuelo' ~/atelier/_bibliotheca/ --include='*.txt' --include='*.adoc' | sort
5. Null-safe find + xargs — handles spaces in paths
find ~/atelier/_bibliotheca/ -type f \( -name '*.adoc' -o -name '*.txt' \) -print0 \
  | xargs -0 grep -li 'sanchuelo' | sort
6. Open all hits directly in nvim
grep -rl -i 'sanchuelo' ~/atelier/_bibliotheca/ --include='*.adoc' --include='*.txt' | xargs nvim

Pattern escalation: #1 confirms the term exists and where. #2 expands to all repos. #3 shows context without opening files. #4 adds plain text sources (Quijote .txt originals). #5 is the safe version for automation. #6 opens everything for editing.

Trade-off: grep -r --include is faster for known file types. find | xargs grep is safer for paths with spaces and more extensible (add -name '*.md' etc.). For literary searches across the bibliotheca, #4 or #5 is usually the right starting point — the source texts are .txt, not .adoc.

Email thread analysis — extract people, dates, commitments, silence

who’s in the thread (@ mentions + From headers)
grep -P '(@\w+|^From:.*<)' comms.adoc
timeline — every date with context
grep -nP '\d{1,2}/\d{1,2}/\d{2,4}|20\d{2}-\d{2}-\d{2}' comms.adoc
commitments — who promised what
grep -niP '(I can |I will |I.ll |we will |we.ll )' comms.adoc
open questions and unknowns
grep -niP '(\?|need to confirm|need to validate|TBD|pending)' comms.adoc

comm — set difference (who hasn’t replied)

# All recipients
grep -oP '<\K[^>]+' comms.adoc | sort -u > /tmp/all-recipients

# All senders
grep -P '^From:' comms.adoc | grep -oP '<\K[^>]+' | sort -u > /tmp/replied

# Who's silent — follow-up targets
comm -23 /tmp/all-recipients /tmp/replied

comm -23 outputs lines only in file 1 (recipients not in senders). Requires sorted input. grep -oP '<\K[^>]+' uses PCRE lookbehind — match < but don’t include it, capture until >.

Sort find results by modification time (newest first)

find discovers files but has no sort. Chain -printf with sort to order by mtime.

awk '{print $2}' truncates filenames with spaces — Familia Romana_ Lingva…​ becomes Familia. Always use the null-safe or sub() variants below for real data.
epoch sort — space-safe (production version)
# Sort by mtime, strip epoch prefix — handles spaces in filenames
find ~/Downloads -maxdepth 1 -name '*.pdf' -printf '%T@ %p\n' | sort -rn | awk '{sub(/^[^ ]+ /,""); print}'

sub(/[ ]+ /,"") removes everything up to and including the first space (the epoch). {print $2} would split on every space — fatal for Familia Romana_ Lingva Latina.

human-readable timestamps alongside
# ISO 8601 timestamps — readable and lexicographically sortable
find ~/Downloads -maxdepth 1 -name '*.pdf' -printf '%T+ %p\n' | sort -r | head -20

%T+ renders YYYY-MM-DD+HH:MM:SS — no epoch math needed, still sorts correctly as text.

null-safe — the bulletproof version
# Null-delimited: survives any filename (newlines, quotes, unicode)
find ~/Downloads -maxdepth 1 -name '*.pdf' -printf '%T@\t%p\0' | sort -zrn | awk -v RS='\0' -F'\t' '{print $2}'

-printf '%T@\t%p\0' — tab separates epoch from path, null terminates. sort -z sorts null-delimited records. awk -v RS='\0' -F'\t' reads null-terminated, splits on tab — $2 is now the full path regardless of spaces.

stat fallback — portable (BSD/macOS)
# GNU stat equivalent — works where -printf is unavailable
find ~/Downloads -maxdepth 1 -name '*latin*' -exec stat --format='%Y %n' {} + | sort -rn | awk '{sub(/^[^ ]+ /,""); print}'

-exec …​ {} + batches all files into one stat call (faster than \;). On macOS, use stat -f '%m %N' instead of --format='%Y %n'.

File intelligence — size, type, duplicates, age

Beyond finding files — interrogating them.

top 10 largest files in a directory tree
# Size in bytes (-printf %s), human-readable via numfmt
find ~/Downloads -type f -printf '%s\t%p\n' | sort -rn | head -10 | numfmt --to=iec --field=1

numfmt --to=iec --field=1 converts the first field from bytes to K/M/G. sort -rn on raw bytes is exact — ls -lhS rounds and sometimes mis-sorts.

find duplicates by size (fast pre-filter before checksumming)
# Files sharing a byte count — likely duplicates (confirm with md5sum)
find ~/Downloads -type f -printf '%s %p\n' | awk '{seen[$1]++; files[$1]=files[$1] "\n  " $0} END {for (s in seen) if (seen[s]>1) print files[s]}'
find duplicates by content — definitive
# md5sum only files with duplicate sizes (two-pass: fast then precise)
find ~/Downloads -type f -printf '%s\n' | sort | uniq -d | while read -r size; do
  find ~/Downloads -type f -size "${size}c" -exec md5sum {} +
done | sort | uniq -w32 -D

Two-pass: first find duplicate sizes (cheap), then md5sum only those (expensive). uniq -w32 -D compares first 32 chars (the hash) and prints all duplicates.

file type census — what’s actually in this directory?
# Count files by MIME type (not extension — extensions lie)
find ~/Downloads -type f -exec file --mime-type -b {} + | sort | uniq -c | sort -rn

file --mime-type -b reports actual content type. -b suppresses filename. A .pdf that’s really text/html is a failed download.

stale files — untouched for 30+ days
# Files not accessed in 30 days — candidates for cleanup
find ~/Downloads -maxdepth 1 -type f -atime +30 -printf '%A+ %s\t%p\n' | sort | numfmt --to=iec --field=2

-atime 30` = access time older than 30 days. `-printf '%A' shows last access. Useful for Downloads cleanup without deleting something you just renamed.

disk usage by subdirectory — sorted
# Which subdirectories consume the most space?
find . -maxdepth 1 -type d -exec du -sh {} + 2>/dev/null | sort -rh | head -20

Batch operations — rename, move, transform

rename all files — strip spaces, lowercase, normalize unicode
# Dry run — show what would change (remove echo to execute)
find ~/Downloads -maxdepth 1 -type f -name '* *' -print0 | while IFS= read -r -d '' f; do
  dir=$(dirname "$f")
  base=$(basename "$f" | tr ' ' '-' | tr '[:upper:]' '[:lower:]')
  echo mv "$f" "$dir/$base"
done

IFS= read -r -d '' — the holy trinity for null-safe filename reading. IFS= prevents whitespace trimming. -r prevents backslash interpretation. -d '' reads until null.

move files by extension into categorized subdirectories
# Sort Downloads chaos into folders by type
find ~/Downloads -maxdepth 1 -type f -print0 | while IFS= read -r -d '' f; do
  ext="${f##*.}"
  case "$ext" in
    pdf|epub)    dest="books" ;;
    jpg|png|svg) dest="images" ;;
    sh|py|rb)    dest="scripts" ;;
    *)           dest="other" ;;
  esac
  mkdir -p ~/Downloads/"$dest"
  echo mv "$f" ~/Downloads/"$dest"/
done

${f##.} — parameter expansion: strip longest match of . from front, leaving only the extension. No basename or awk needed.

batch convert epub → asciidoc (like your Cicero fetch script)
# Convert all epubs in a directory to asciidoc via pandoc
find . -name '*.epub' -type f -exec sh -c '
  for epub; do
    adoc="${epub%.epub}.adoc"
    pandoc -f epub -t asciidoc "$epub" -o "$adoc" \
      && printf "  → %s (%s lines)\n" "$adoc" "$(wc -l < "$adoc")" \
      || printf "  ✗ failed: %s\n" "$epub"
  done
' _ {} +

-exec sh -c '…​' _ {} + — batch mode. _ fills $0 (script name, discarded). All matched files become $1, $2, …​ iterated by for epub. One sh invocation, not one per file.

xargs power patterns

parallel processing — 4 cores
# Checksum all PDFs in parallel (4 processes)
find ~/Downloads -name '*.pdf' -print0 | xargs -0 -P4 md5sum

-P4 runs 4 md5sum processes simultaneously. -print0 | xargs -0 is the null-safe pipeline — no filename can break it.

batched execution — two arguments at a time
# Compare files pairwise with diff
find . -name '*.adoc' -print0 | xargs -0 -n2 diff --brief

-n2 feeds two arguments per invocation. Useful for pairwise comparisons, copy operations (-n2 with cp), or any command taking exactly two args.

placeholder — insert filename at specific position
# Backup every config file: cp <file> <file>.bak
find /etc -maxdepth 1 -name '*.conf' -print0 | xargs -0 -I{} cp {} {}.bak

-I{} replaces {} with each filename. Slower than + batching (one cp per file) but necessary when the filename must appear in a specific position.

Process substitution — diff without temp files

compare two directory listings
# What files exist in study-A but not study-B?
diff <(find data/d000/education/ciceron-study -type f -name '*.adoc' | sort) \
     <(find data/d000/education/latin-study -type f -name '*.adoc' | sort)

<(cmd) creates a file descriptor from command output. diff sees two "files" — no temp files created, no cleanup needed.

compare file counts across directories
# Side-by-side: file type census of two directories
paste <(find dir1 -type f -exec file --mime-type -b {} + | sort | uniq -c | sort -rn) \
      <(find dir2 -type f -exec file --mime-type -b {} + | sort | uniq -c | sort -rn)

awk, sed, jq

awk — field extraction

print second field (whitespace-delimited)
awk '{print $2}' file.txt
custom delimiter — colon-separated (like /etc/passwd)
awk -F: '{print $1, $3}' /etc/passwd
extract JSON code blocks from AsciiDoc
awk '/\[source,json\]/{getline; if ($0 ~ /^----/) {p=1; next}} p && /^----/{p=0; next} p' file.adoc
field extraction with printf formatting
awk '{printf "%-30s %s\n", $1, $2}' file.txt

sed — stream editing

in-place replacement with verify-before/after
# Before
awk 'NR==73' /etc/ssh/sshd_config
# Change
sed -i '73s/#GSSAPIAuthentication no/GSSAPIAuthentication yes/' /etc/ssh/sshd_config
# After
awk 'NR==73' /etc/ssh/sshd_config
extract line range
sed -n '10,20p' file.txt

sed — line-targeted replacement (verify-before / change / verify-after)

the full pattern: locate → validate → change → verify
# 1. LOCATE: find the line number
grep -n 'adoc-pdf' zsh/.zshrc

# 2. VALIDATE: read the exact line before changing
awk 'NR==1760' zsh/.zshrc

# 3. CHANGE: target by line number — only hits that line
sed -i '1760s/alias adoc-pdf=/alias build-adoc=/' zsh/.zshrc

# 4. VERIFY: confirm change AND check for collateral
grep -n 'build-adoc\|adoc-pdf' zsh/.zshrc

Without the line number prefix (1760s/), sed replaces every match in the file — a shotgun. With it, surgical. The line number comes from grep -n.

multi-line verify — check two specific lines at once
awk 'NR==1218 || NR==1760' zsh/.zshrc
range extraction — NR for surgical reads from large files
# grep found the error at line 44164 — read 50 lines of context
awk 'NR>=44160 && NR<=44210' session-dump.adoc

No head | tail chains. No sed -n '44160,44210p'. One awk, two numbers.

grep -oP with \K — value extraction from key-value logs

extract just the value after a key (Perl regex)
# ISE syslog — extract failure reasons
grep -oP 'FailureReason=\K[^,;]+' /var/log/syslog | sort | uniq -c | sort -rn

# ISE — extract MAC addresses
grep -oP 'Calling-Station-ID=\K[0-9A-Fa-f:.-]+' /var/log/syslog | sort -u

# ISE — extract NAS IPs
grep -oP 'NAS-IP-Address=\K[0-9.]+' /var/log/syslog | sort -u

# ISE — extract device names
grep -oP 'NetworkDeviceName=\K[^,;]+' /var/log/syslog | sort -u

\K resets the match start — everything before \K is required context but excluded from output. [^,;]+ captures until the next delimiter. Pipe to sort -u for unique, sort | uniq -c | sort -rn for counted frequency.

pattern: grep -oP 'KEY=\KVALUE_REGEX' | sort pipeline
# Generic form — works for any key=value log format
grep -oP 'FIELD_NAME=\K[^,;]+' logfile | sort | uniq -c | sort -rn | head -20

jq — JSON processing

extract nested fields
curl -s localhost:8080/stats | jq '.stats.total_files'
filter array by property
jq '.results[] | select(.category == "standards")' response.json
transform to TSV for spreadsheets
jq -r '.[] | [.title, .path] | @tsv' response.json | column -t -s $'\t'
GitHub API + jq — commit history by path
gh api "repos/EvanusModestus/domus-captures/commits?path=docs/&per_page=10" |
  jq -r '.[] | "\(.commit.author.date[:10]) \(.sha[:7]) \(.commit.message | split("\n")[0])"'

Shell Patterns

xargs — when the next command reads arguments, not stdin

Next command reads…​ Use

stdin (awk, grep, wc, sort)

pipe directly

arguments (stat, rm, cp, nvim, git add)

xargs

copy today’s files to backup — -I{} placeholder
mkdir -p /tmp/adoc-backup-$(date +%F) && \
  find . -name "*.adoc" -type f -newermt "$(date +%F)" | \
  xargs -I{} cp {} /tmp/adoc-backup-$(date +%F)/
parallel validation — -P4 runs 4 at a time
find .drafts -name "*.adoc" -type f | xargs -P4 -I{} asciidoctor -o /dev/null {}
null-delimited pipeline — safe for filenames with spaces
find . -name "*.adoc" -type f -print0 | xargs -0 wc -l

Process substitution — <(cmd) treats output as a file

compare tracker state: yesterday vs today
diff <(grep '|' partials/trackers/work/adhoc/carryover.adoc | head -20) \
     <(git show HEAD~1:partials/trackers/work/adhoc/carryover.adoc | grep '|' | head -20)
files on disk vs files in nav — drift detection
diff <(find docs/modules/ROOT/pages/projects/chla/mschapv2-migration -name "*.adoc" -type f | sort) \
     <(grep -oP 'mschapv2-migration/[^[]+\.adoc' docs/modules/ROOT/nav.adoc | sort)

Command substitution — embed output as arguments

open most recently modified file in nvim
nvim "$(find data/ -name '*.adoc' -type f -printf '%T@ %p\n' | sort -rn | awk 'NR==1{print $2}')"
line count across a project
wc -l $(find docs/modules/ROOT -path '*mschapv2*' -name '*.adoc' -type f)

Conditional execution — capture, test, act

open matching files only if they exist
files=$(find .drafts -name 'in*' -type f) && [ -n "$files" ] && nvim $files
open files that contain unchecked items
files=$(grep -rl '\[ \]' .drafts/*.adoc) && [ -n "$files" ] && nvim $files
guard with grep -q — only act if pattern matches
grep -q 'TODO\|FIXME\|\[ \]' "$file" && nvim "$file"

Pattern: $(capture)[ -n ] tests non-empty → && only proceeds if true. grep -q is the idempotent guard — run repeatedly, only opens when there’s work.

Decrypt and open — find .age, decrypt, nvim in one shot

files=$(find . -name "*tcp-clock*.age" -type f) && \
  [ -n "$files" ] && echo "$files" | xargs -I{} decrypt-file {} && \
  nvim $(echo "$files" | sed 's/\.age$//')

Pattern: find .age only (never tries plaintext), sed derives the decrypted path, guard prevents empty nvim. Change the glob to match any project.

tee_clean — color on screen, clean text in file

tee_clean() {
  tee >(sed 's/\x1b\[[0-9;]*m//g' > "$1")
}

# Color output on terminal, stripped in file
jq -C '.' data.json | tee_clean output.json
xq -C '.' data.xml | tee_clean output.json

# Wrap a whole block
{
  echo "=== Summary ==="
  jq -C '.[] | .name' data.json
} | tee_clean summary.txt

The >(cmd) is process substitution — tee writes to stdout AND to the subshell pipe. sed strips ANSI escape sequences (\x1b\[[0-9;]*m) before they hit the file.

Dependency check — verify toolchain in one shot

for cmd in asciidoctor asciidoctor-pdf pandoc rouge d2 mmdc age; do
  printf "%-20s %s\n" "$cmd" "$(command -v $cmd >/dev/null 2>&1 && echo 'OK' || echo 'MISSING')"
done

Pattern: command -v checks if binary exists on PATH. >/dev/null 2>&1 suppresses output — we only care about exit code. Swap the tool list for any project’s dependencies.

printf safety — dashes as data, not options

wrong — printf treats --- as invalid option
printf '---\n\n'
right — %s format string treats --- as data
printf '%s\n\n' '---'

Kill stuck SSH sessions

Find established SSH connections
lsof -i TCP -n -P | awk '/ssh.*ESTABLISHED/ {print $2, $9}'
Kill all stuck SSH sessions to a specific host
lsof -i TCP -n -P | awk '/ssh.*kvm-01.*ESTABLISHED/ {print $2}' | sort -u | xargs kill
Kill ALL stuck SSH sessions
lsof -i TCP -n -P | awk '/ssh.*ESTABLISHED/ {print $2}' | sort -u | xargs kill

lsof -i TCP -n -P lists all TCP connections. awk filters for SSH + ESTABLISHED, prints only the PID ($2). sort -u deduplicates (multiple file descriptors per process). xargs kill sends SIGTERM to each.

File Descriptors & Redirection

The three file descriptors

FD Name Purpose

0

stdin

input to the command

1

stdout

normal output (valid results)

2

stderr

error messages

Split stdout and stderr into separate files

find / -name "*.conf" 1>results.txt 2>errors.txt

Suppress errors — 2>/dev/null

find / -name "*.conf" 2>/dev/null

Merge stderr into stdout — 2>&1

command 2>&1 | grep "pattern"

This sends both stdout and stderr through the pipe. Without 2>&1, only stdout reaches grep — errors print to the terminal and bypass the pipeline.

Heredoc patterns

multi-line input to a command
cat <<'EOF'
Line 1
Line 2
EOF
heredoc commit messages (quotes prevent variable expansion)
git commit -m "$(cat <<'EOF'
feat: add new feature

Multi-line description here.
EOF
)"

API & curl/jq

domus-api — Documentation System REST API

start the API server
cd ~/atelier/_projects/personal/domus-api && uv run uvicorn domus_api.main:app --host 0.0.0.0 --port 8080
health check
curl -s localhost:8080/ | jq
full-text search
curl -s 'localhost:8080/search?q=mandiant' | jq
search — extract path, title, match count
curl -s 'localhost:8080/search?q=mandiant' | jq '.results[] | {path, title, match_count}'
list pages by category
curl -s 'localhost:8080/pages?category=standards' | jq
all antora.yml attributes
curl -s localhost:8080/attributes | jq

GitHub API

cross-repo search via GitHub API
gh search code "vault seal" --owner EvanusModestus --json repository,path,textMatches |
  jq '.[] | {repo: .repository.full_name, file: .path, match: .textMatches[].fragment}'
count .adoc files in a repo via API
gh api 'repos/EvanusModestus/domus-captures/git/trees/main?recursive=1' |
  jq '[.tree[] | select(.path | endswith(".adoc"))] | length'

Domus Workflows

Read content from terminal (meeting-ready)

today’s worklog
bat docs/modules/ROOT/pages/2026/04/WRKLOG-$(date +%Y-%m-%d).adoc
current priorities
bat docs/modules/ROOT/partials/trackers/work/priorities/current.adoc
carryover backlog
bat docs/modules/ROOT/partials/trackers/work/adhoc/carryover.adoc
any project summary
bat docs/modules/ROOT/partials/projects/mandiant-remediation/summary.adoc

Search and discovery

find all files related to a topic
grep -rl "MSCHAPv2" docs/modules/ROOT/ --include="*.adoc" | sort
search codex entries
grep -rn "pattern" docs/modules/ROOT/partials/codex/ --include="*.adoc" -B1 -A3
list all worklogs for a month
ls -1 docs/modules/ROOT/pages/2026/04/WRKLOG-*.adoc

Tracker aging — calculate days from origin

how many days since a carryover item started
echo $(( ($(date +%s) - $(date -d "2026-03-09" +%s)) / 86400 ))

Encrypted data access (d001)

view encrypted file without disk write
age --decrypt -i ~/.secrets/.metadata/keys/master.age.key \
  data/d001/projects/mandiant-remediation/findings-status-2026-04-16.adoc.age \
  | bat --language asciidoc
project encryption dashboard
for d in data/d001/projects/*/; do
  total=$(find "$d" -type f | wc -l)
  plain=$(find "$d" -type f ! -name '*.age' ! -name 'README.adoc' ! -name '.gitkeep' ! -name '*.py' | wc -l)
  printf "%-25s %s files  %s plaintext\n" "$(basename "$d")" "$total" "$plain"
done

d000 study builds

batch build all docs for a Quijote chapter range
for d in p1-cap-03{7,8,9}; do
  for f in data/d000/education/quijote-study/notas/$d/*.adoc; do
    d000 build "$d/$(basename "$f" .adoc)" html --variant light-cyan
  done
done
build a single study doc (use unique path fragment)
d000 build p1-cap-038/texto-anotado html --variant light-cyan
d000 build p1-cap-038/texto-anotado pdf --theme light-cyan
batch build PDFs for a chapter range
for d in p1-cap-03{7,8,9}; do
  for f in data/d000/education/quijote-study/notas/$d/*.adoc; do
    d000 build "$d/$(basename "$f" .adoc)" pdf --theme light-cyan
  done
done
open all rendered chapters at once
firefox data/d000/education/quijote-study/notas/p1-cap-03{7,8,9}/output/*.html &
firefox data/d000/education/quijote-study/notas/p1-cap-03{7,8,9}/output/*.pdf &
print chapter PDFs (requires CUPS configured)
lp data/d000/education/quijote-study/notas/p1-cap-03{7,8,9}/output/*.pdf
build LPL logic study (English / Spanish)
d000 build annotated-text pdf --theme light-cyan
d000 build lpl-study/notas/texto-anotado pdf --theme light-cyan
build Cicero study
d000 build de-oratore/libro-i/texto-anotado html --variant light-cyan

Available themes

PDF themes (--theme)
ls ~/atelier/_bibliotheca/domus-asciidoc-build/themes/pdf/ | sed 's/-theme\.yml//'
# base blue burgundy catppuccin creative dark don-quijote green
# learning light-cyan navy operations orange purple reference royal
HTML variants (--variant)
~/atelier/_bibliotheca/domus-asciidoc-build/docinfo/compose.sh --list
# light dark catppuccin royal light-cyan

ISE & Network Ops

ISE ERS API — endpoint CRUD

set credentials (session)
export ISE_HOST="{ise-ip}" ISE_USER="admin" ISE_PASS="$(gopass show -o ise/admin)"
list identity groups
curl -sk "https://$ISE_HOST:{ise-ers-port}/ers/config/identitygroup" \
  -H "Accept: application/json" -u "$ISE_USER:$ISE_PASS" | jq '.SearchResult.resources[].name'
check if endpoint exists by MAC
curl -sk "https://$ISE_HOST:{ise-ers-port}/ers/config/endpoint?filter=mac.EQ.AA:BB:CC:DD:EE:FF" \
  -H "Accept: application/json" -u "$ISE_USER:$ISE_PASS" | jq '.SearchResult.total'

Certificate inspection

view EAP-TLS client cert from local store
openssl x509 -in {cert-dir}/client.pem -text -noout | head -30
check cert expiry
openssl x509 -in {cert-dir}/client.pem -enddate -noout

Network diagnostics

check listening ports
ss -tlnp | grep -E ':{port-https}|:{port-ssh}|:{port-ldaps}'
test ISE connectivity
nc -zv {ise-ip} {ise-ers-port}
DNS resolution
dig {ise-hostname} +short

ISE eval rotation — backup & restore

backup from ISE CLI (when admin UI is license-locked)
# SSH to ISE
ssh admin@ise-02.inside.domusdigitalis.dev

# Verify NAS repo
show repository nas-01

# Get encryption key (on workstation)
dsource d000 dev/storage
echo $ISE_BACKUP_KEY

# Run backup
backup pre-rotation-2026-06 repository nas-01 ise-config encryption-key plain <KEY>
list backups on NAS
ssh admin@ise-02.inside.domusdigitalis.dev
show repository nas-01
restore to fresh ISE node
configure terminal
repository nas-01
  url nfs://10.50.1.70:/volume1/ise_backups
exit

restore <backup-filename> repository nas-01 encryption-key plain <KEY>

VyOS — VRRP & VLAN inspection

VRRP status and VIPs
show vrrp
show configuration commands | grep vrrp | grep 'address'
firewall zone membership
show configuration commands | grep 'firewall zone' | grep 'member'
DHCP leases and ARP
show dhcp server leases
show arp
full interface/VLAN map
show interfaces

CUPS printing — validation & setup

software validation
command -v lpstat && echo "CUPS present" || echo "CUPS not installed"
lpstat -r                                # scheduler running?
lpstat -p -d                             # printers + default
daemon lifecycle
sudo systemctl enable --now cups         # start + persist
printer discovery
lpinfo -v                                # available backends/URIs
lpinfo -m | grep -i <brand>             # available drivers
add printer and set default
sudo lpadmin -p <name> -v <uri> -m everywhere -E
lpoptions -d <name>
print
lp file.pdf                              # default printer
lp -d <name> -o sides=two-sided-long-edge file.pdf

PowerShell (from zsh)

All PowerShell commands run inside pwsh -NoLogo -Command '…​' from zsh. Running them bare fails — zsh interprets $, |, () as shell syntax.

Process management

top 5 processes by memory
pwsh -NoLogo -Command 'Get-Process | Sort-Object WorkingSet64 -Descending |
  Select-Object -First 5 ProcessName, Id,
    @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} | Format-Table'
stop/start Teams
pwsh -NoLogo -Command 'Get-Process | Where-Object {$_.ProcessName -like "*teams*"} | Stop-Process'
pwsh -NoLogo -Command 'Start-Process "ms-teams"'

Export to JSON (pipe to jq)

always use -NoLogo when piping pwsh output to zsh tools
pwsh -NoLogo -Command 'Get-Process | Sort-Object WorkingSet64 -Descending |
  Select-Object -First 5 ProcessName, Id,
    @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} | ConvertTo-Json' | jq '.'
Never pipe Format-Table into ConvertTo-Json — it produces layout metadata, not data. Select-Object first, then ConvertTo-Json.

Wi-Fi management (netsh)

force fresh network scan
netsh wlan disconnect interface="Wi-Fi"
netsh wlan show networks mode=bssid
netsh wlan connect name="CHLA-Remote" interface="Wi-Fi"

SSH from PowerShell

connect to homelab from Windows terminal
ssh evan@modestus-razer.inside.domusdigitalis.dev

WSL ↔ Windows — Cross-Environment Commands

From zsh (WSL) — control Windows
run any PowerShell command from zsh
pwsh -NoLogo -Command 'Get-Date'
run multi-line PowerShell from zsh (heredoc)
pwsh -NoLogo -Command "$(cat <<'PS'
$procs = Get-Process | Where-Object { $_.WorkingSet64 -gt 100MB }
$procs | Sort-Object WorkingSet64 -Descending |
  Select-Object ProcessName, Id, @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} |
  Format-Table -AutoSize
PS
)"
open a file in Windows from WSL
# Open in default Windows app
wslview /mnt/c/Users/erosado/Documents/report.pdf

# Open Explorer to current WSL directory
explorer.exe .

# Open specific Windows path
explorer.exe 'C:\Users\erosado\Downloads'
copy WSL output to Windows clipboard
# Pipe anything to Windows clipboard
cat file.txt | clip.exe

# Copy a command's output
pwsh -NoLogo -Command 'Get-TransportRule | Format-List Name, State' | clip.exe
access Windows files from WSL
# Windows C: drive is at /mnt/c
ls /mnt/c/Users/erosado/Downloads/

# Copy from Windows to WSL
cp /mnt/c/Users/erosado/Downloads/report.pdf ~/atelier/

# Watch a Windows directory for new files
find /mnt/c/Users/erosado/Downloads -maxdepth 1 -mmin -5 -type f -printf '%T+ %p\n' | sort -r
From PowerShell — control WSL
run a bash command from PowerShell
wsl -e bash -c 'grep -rn "Ghost-Sender" ~/atelier/_bibliotheca/domus-captures/docs/'
run a specific WSL command and capture output
$result = wsl -e bash -c 'git -C ~/atelier/_bibliotheca/domus-captures log --oneline -5'
$result
Process Management — Windows Side
top processes by memory — formatted table
pwsh -NoLogo -Command '
Get-Process | Sort-Object WorkingSet64 -Descending |
  Select-Object -First 20 ProcessName, Id,
    @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}},
    @{N="CPU(s)";E={[math]::Round($_.CPU,1)}},
    @{N="Handles";E={$_.HandleCount}} |
  Format-Table -AutoSize'
find a specific process
pwsh -NoLogo -Command 'Get-Process | Where-Object { $_.ProcessName -like "*teams*" } |
  Select-Object ProcessName, Id, @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} |
  Format-Table -AutoSize'
kill by name
pwsh -NoLogo -Command 'Stop-Process -Name "Teams" -Force -ErrorAction SilentlyContinue'
kill by PID
pwsh -NoLogo -Command 'Stop-Process -Id 12345 -Force'
what’s listening on a port (Windows equivalent of ss -tulnp)
pwsh -NoLogo -Command 'Get-NetTCPConnection -State Listen |
  Select-Object LocalAddress, LocalPort, OwningProcess,
    @{N="Process";E={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName}} |
  Sort-Object LocalPort | Format-Table -AutoSize'
specific port check
pwsh -NoLogo -Command 'Get-NetTCPConnection -LocalPort 8080 -ErrorAction SilentlyContinue |
  Select-Object LocalAddress, LocalPort, RemoteAddress, State,
    @{N="Process";E={(Get-Process -Id $_.OwningProcess).ProcessName}}'
Services — Windows Side
list running services
pwsh -NoLogo -Command 'Get-Service | Where-Object { $_.Status -eq "Running" } |
  Sort-Object DisplayName | Format-Table Name, DisplayName, Status -AutoSize'
check a specific service
pwsh -NoLogo -Command 'Get-Service -Name "WinRM" | Format-List Name, DisplayName, Status, StartType'
restart a service
Restart-Service -Name "WinRM" -Force
System Info — Quick Health from zsh
one-shot Windows system summary
pwsh -NoLogo -Command '
Write-Host "=== Windows System ===" -ForegroundColor Cyan
Write-Host "Hostname: $env:COMPUTERNAME"
Write-Host "User:     $env:USERNAME"
Write-Host "OS:       $((Get-CimInstance Win32_OperatingSystem).Caption)"
Write-Host "Uptime:   $((Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime)"
Write-Host "RAM:      $([math]::Round((Get-CimInstance Win32_OperatingSystem).TotalVisibleMemorySize/1MB))GB total, $([math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory/1MB))GB free"
Write-Host "CPU:      $((Get-CimInstance Win32_Processor).Name)"
Write-Host "Disk C:   $([math]::Round((Get-PSDrive C).Free/1GB))GB free of $([math]::Round(((Get-PSDrive C).Used + (Get-PSDrive C).Free)/1GB))GB"'
disk usage — all drives
pwsh -NoLogo -Command 'Get-PSDrive -PSProvider FileSystem |
  Select-Object Name, @{N="Used(GB)";E={[math]::Round($_.Used/1GB,1)}},
    @{N="Free(GB)";E={[math]::Round($_.Free/1GB,1)}},
    @{N="Total(GB)";E={[math]::Round(($_.Used+$_.Free)/1GB,1)}} |
  Format-Table -AutoSize'
Exchange Online — Connect from zsh
connect to Exchange Online (launches MFA prompt in Windows)
pwsh -NoLogo -Command 'Connect-ExchangeOnline -UserPrincipalName erosado@chla.usc.edu'
MFA prompt opens in the Windows browser. After auth, the session persists in the pwsh process. For multi-command sessions, start pwsh interactively instead of one-shot commands.
interactive PowerShell session from zsh (for Exchange, etc.)
pwsh -NoLogo
# Then inside pwsh:
# Connect-ExchangeOnline
# Get-TransportRule | Format-List Name, State
# exit
File Transfer Patterns
move files between WSL and Windows
# WSL → Windows Downloads
cp ~/atelier/_bibliotheca/domus-captures/output/report.pdf /mnt/c/Users/erosado/Downloads/

# Windows → WSL (glob)
cp /mnt/c/Users/erosado/Downloads/*.{png,pdf,jpg} ~/atelier/_staging/

# Bulk move with null safety
find /mnt/c/Users/erosado/Downloads -maxdepth 1 -name '*.pdf' -mmin -60 -print0 |
  xargs -0 -I{} cp {} ~/atelier/_staging/
watch Windows Downloads for new files (live)
inotifywait -m /mnt/c/Users/erosado/Downloads -e create -e moved_to |
  awk '{printf "%s  %s\n", strftime("%H:%M:%S"), $3}'
inotifywait requires inotify-tools. Install with sudo pacman -S inotify-tools if not present.

Security & Encryption

View encrypted files without writing to disk

pipe age decrypt to bat — nothing touches the filesystem
age --decrypt -i ~/.secrets/.metadata/keys/master.age.key \
  data/d001/projects/mandiant-remediation/findings-status-2026-04-16.adoc.age \
  | bat --language asciidoc --file-name "findings-status-2026-04-16.adoc"

Batch re-encrypt — brace expansion + loop

re-encrypt multiple project files
for f in data/d001/projects/mandiant-remediation/{findings-status,guest-acl-update,siem-report}-2026-04-16.adoc; do
  rm -f "${f}.age" && echo y | encrypt-file "$f"
done
Always rm -f the .age first. If you skip it, encrypt-file prompts about overwrite and may only delete the plaintext without re-encrypting.

Detect stale plaintext — files needing re-encryption

find plaintext newer than its .age counterpart
for f in data/d001/projects/*/*.adoc; do
  age="${f}.age"
  if [ -f "$f" ] && [ -f "$age" ]; then
    pt_mod=$(/usr/bin/stat -c'%Y' "$f")
    age_mod=$(/usr/bin/stat -c'%Y' "$age")
    [ "$pt_mod" -gt "$age_mod" ] && echo "STALE: $f"
  fi
done

Secure delete — shred for sensitive plaintext

shred -u data/d001/projects/mandiant-remediation/man-report.txt
On SSD/NVMe, shred is less effective (wear leveling), but better than rm which only removes the directory entry.

Pre-push audit — find all unencrypted project files

find data/d001/projects -type f ! -name '*.age' ! -name 'README.adoc' ! -name '.gitkeep' ! -name '*.py' | sort

System & Infrastructure

PipeWire audio validation

wpctl status                                    # PipeWire status
pactl list sinks short                          # list audio sinks
pw-play /usr/share/sounds/freedesktop/stereo/bell.oga  # test default sink
journalctl -b --grep='sof|cs35l56' --no-pager | tail -20  # kernel audio firmware
cat /proc/asound/cards                          # ALSA sound cards

gopass — personal document management

gopass-personal-docs    # interactive entry creation
gopass-query bills      # list recurring bills with totals
gopass-query storage    # list storage units with gate codes
gopass-query export bills  # export category to JSON

Makefile — daily workflow

make new-day      # create today's worklog + update attributes
make serve        # build + local server (port 8000)
make              # build only
make sync-nav     # sync worklog nav entries
make update-index # rebuild monthly index

KVM — VM & ISO management

list VMs on a KVM host
ssh kvm-01 "sudo virsh list --all"
ssh kvm-02 "sudo virsh list --all"
find ISE ISOs across KVM hosts (case-insensitive glob)
ssh kvm-01 "ls -lh /mnt/nas/isos/*[Ii][Ss][Ee]* /var/lib/libvirt/images/*[Ii][Ss][Ee]* /mnt/onboard-ssd/isos/*[Ii][Ss][Ee]* 2>/dev/null"
ssh kvm-02 "ls -lh /mnt/nas/isos/*[Ii][Ss][Ee]* /mnt/ssd/libvirt/images/*[Ii][Ss][Ee]* 2>/dev/null"
console into a VM
sudo virsh console <vm-name>             # Escape: Ctrl+]
check NAS mount on KVM host
ssh kvm-01 "mount | grep nas; ls /mnt/"

Per-project file dashboard

per-project summary — total files vs unencrypted plaintext
for d in data/d001/projects/*/; do
  total=$(find "$d" -type f | wc -l)
  plain=$(find "$d" -type f ! -name '*.age' ! -name 'README.adoc' ! -name '.gitkeep' ! -name '*.py' | wc -l)
  echo "$(basename "$d") | ${total} files | ${plain} plaintext"
done

USB-C / Thunderbolt Charging Diagnostics

Full evidence capture to file (one block, timestamped)
{
  echo "=== Power Supply ==="
  cat /sys/class/power_supply/*/status
  echo ""
  cat /sys/class/power_supply/*/type
  echo ""
  echo "=== UPower ==="
  upower -d | grep -E 'state|percentage|energy-rate|voltage'
  echo ""
  echo "=== dmesg (typec/thunderbolt/PD) ==="
  sudo dmesg | grep -iE 'typec|thunderbolt|ucsi|PD|power.delivery|charging' | tail -20
  echo ""
  echo "=== Pacman log (kernel/typec) ==="
  grep -iE 'thunderbolt|typec|ucsi|^.*upgraded linux ' /var/log/pacman.log | tail -20
} | tee /tmp/INC-$(date +%F)-usbc-charging.txt

Pattern: { } groups commands into a single stdout stream. tee writes to file AND displays on screen. Reusable for any multi-command evidence capture — change the commands inside, keep the structure.