From 6bd416657c1ecb931b046f076cb7ddf30be965b8 Mon Sep 17 00:00:00 2001 From: Howard Enos Date: Wed, 22 Apr 2026 17:39:57 -0700 Subject: [PATCH] sync: auto-sync from HOWARD-HOME at 2026-04-22 17:39:56 Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-04-22 17:39:56 --- .claude/memory/MEMORY.md | 1 + .claude/memory/reference_gururmm_api.md | 92 ++++++ .../docs/cloud/caregiver-m365-p2-rollout.md | 5 +- .../cascades-staff-followup-2026-04-22.md | 2 +- .../cascades-staff-working-list-2026-04-22.md | 17 +- .../docs/cloud/p2-staff-candidates.md | 5 +- .../cascades-staff-editor-2026-04-22.html | 7 +- ...cades-staff-open-questions-2026-04-22.docx | Bin 3041 -> 3201 bytes .../docs/cloud/user-account-rollout-plan.md | 92 +++++- .../docs/migration/phase2-server-prep.md | 7 + .../docs/migration/phase4-synology.md | 81 +++++ .../entra-connect-preflight-remediation.ps1 | 212 +++++++++++++ .../scripts/entra-connect-readiness.ps1 | 288 ++++++++++++++++++ .../docs/security/hipaa-review-2026-04-22.md | 169 ++++++++++ ...-04-22-cs-server-entra-preflight-result.md | 89 ++++++ ...04-22-cs-server-entra-readiness-verdict.md | 122 ++++++++ .../2026-04-22-cs-server-entra-readiness.md | 246 +++++++++++++++ .../scripts/build-open-questions-docx.py | 10 +- 18 files changed, 1409 insertions(+), 36 deletions(-) create mode 100644 .claude/memory/reference_gururmm_api.md create mode 100644 clients/cascades-tucson/docs/migration/scripts/entra-connect-preflight-remediation.ps1 create mode 100644 clients/cascades-tucson/docs/migration/scripts/entra-connect-readiness.ps1 create mode 100644 clients/cascades-tucson/docs/security/hipaa-review-2026-04-22.md create mode 100644 clients/cascades-tucson/reports/2026-04-22-cs-server-entra-preflight-result.md create mode 100644 clients/cascades-tucson/reports/2026-04-22-cs-server-entra-readiness-verdict.md create mode 100644 clients/cascades-tucson/reports/2026-04-22-cs-server-entra-readiness.md diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md index 28204b1..e87863e 100644 --- a/.claude/memory/MEMORY.md +++ b/.claude/memory/MEMORY.md @@ -13,6 +13,7 @@ - [Client Docs Structure](reference_client_docs_structure.md) - clients//docs/ layout (overview, network, servers, cloud, security, rmm, issues). Template at clients/_client_template/. - [MSP Audit Scripts](reference_msp_audit_scripts.md) - server_audit.ps1 / workstation_audit.ps1 at projects/msp-tools/msp-audit-scripts/. ScreenConnect 80-char rule. - [GuruRMM Server Layout](reference_gururmm_server.md) - SSH as `guru`, repo at /home/guru/gururmm, deploy to /var/www/gururmm/dashboard/ +- [GuruRMM API — run script on agent](reference_gururmm_api.md) - POST /api/agents/:id/command with command_type=powershell + command text; poll /api/commands/:id for stdout/stderr. Use instead of ScreenConnect copy-paste. - [Pluto Build Server](reference_pluto_build_server.md) - General-purpose Windows build VM, 172.16.3.36, SSH as Administrator, MSVC toolchain — use for any EXE (utilities, Howard's tools, GuruRMM agent) ## Users diff --git a/.claude/memory/reference_gururmm_api.md b/.claude/memory/reference_gururmm_api.md new file mode 100644 index 0000000..692ae02 --- /dev/null +++ b/.claude/memory/reference_gururmm_api.md @@ -0,0 +1,92 @@ +--- +name: GuruRMM API — run PowerShell on any agent +description: API endpoints, auth flow, and curl recipe to execute a script on any GuruRMM agent and retrieve output. Use this instead of asking user to paste script into ScreenConnect. +type: reference +--- + +# GuruRMM API — Execute Script on an Agent + +**API base:** `http://172.16.3.30:3001` (reachable from HOWARD-HOME and similar dev machines via Tailscale — not reachable from cascades internal-network-only boxes, but that doesn't matter since the API talks to the agent, not the target machine). + +**Auth creds:** `infrastructure/gururmm-server.sops.yaml` → `credentials.gururmm-api.admin-email` + `admin-password`. Login returns a JWT valid for ~24h (expires 86400s from iat). + +## Flow + +```bash +VAULT="$PWD/.claude/scripts/vault.sh" +EMAIL=$(bash "$VAULT" get-field infrastructure/gururmm-server.sops.yaml credentials.gururmm-api.admin-email) +PASS=$(bash "$VAULT" get-field infrastructure/gururmm-server.sops.yaml credentials.gururmm-api.admin-password) + +JWT=$(curl -s -X POST http://172.16.3.30:3001/api/auth/login \ + -H "Content-Type: application/json" \ + -d "{\"email\":\"$EMAIL\",\"password\":\"$PASS\"}" \ + | python -c "import json,sys; print(json.load(sys.stdin)['token'])") + +# List agents (find the agent_id for the host you want) +curl -s http://172.16.3.30:3001/api/agents -H "Authorization: Bearer $JWT" + +# Submit a PowerShell command — works with any file, json-encode to preserve quotes/newlines +AGENT="" +PAYLOAD=$(python -c " +import json +with open('path/to/script.ps1','r',encoding='utf-8') as f: s=f.read() +print(json.dumps({'command_type':'powershell','command':s})) +") +RESP=$(curl -s -X POST http://172.16.3.30:3001/api/agents/$AGENT/command \ + -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" -d "$PAYLOAD") +CMD_ID=$(echo "$RESP" | python -c "import json,sys; print(json.load(sys.stdin)['command_id'])") + +# Poll until completed (status values: running, completed, failed, timeout) +while true; do + STATUS=$(curl -s http://172.16.3.30:3001/api/commands/$CMD_ID -H "Authorization: Bearer $JWT" \ + | python -c "import json,sys; print(json.load(sys.stdin)['status'])") + [ "$STATUS" != "running" ] && break + sleep 5 +done + +# Fetch result (stdout / stderr / exit_code) +curl -s http://172.16.3.30:3001/api/commands/$CMD_ID -H "Authorization: Bearer $JWT" +``` + +## Required request fields + +`POST /api/agents/:id/command` requires: +- `command_type` — the interpreter. Valid values include `powershell`, `shell`, `script`, `exec` — any string is accepted by the API but the Windows agent only runs powershell-compatible content. Use `powershell` for Windows agents. +- `command` — the script text. JSON-encode to preserve newlines, quotes, and dollar-sign escapes. + +## Response shape (from `/api/commands/:cmd_id`) + +```json +{ + "id": "uuid", + "agent_id": "uuid", + "command_type": "powershell", + "command_text": "...", + "status": "completed", // or running | failed | timeout + "exit_code": 0, + "stdout": "...", + "stderr": "...", + "created_at": "ISO-8601", + "started_at": "ISO-8601", + "completed_at": "ISO-8601" +} +``` + +## When to use this + +- Readiness / diagnostic checks on any client server where GuruRMM is installed +- One-off remediation without needing ScreenConnect copy-paste +- Anywhere you'd otherwise ask the user to paste a script manually + +## When NOT to use this + +- When the agent isn't enrolled in GuruRMM (check `GET /api/agents` first) +- For interactive sessions (no stdin; single-shot execution) +- For >1 MB of script (untested — keep scripts modular) + +## Notes +- Script output is limited; if you need large output, have the script write to a file on the agent and fetch via a separate command +- `command_type: "powershell"` runs in the SYSTEM context on Windows (agent runs as LocalSystem) +- Idempotent commands only — there is no transactional rollback +- The tunnel API (`/api/v1/tunnel/...`) is a planned interactive feature per `.claude/gururmm-tunnel-plan.md`, not yet deployed as of 2026-04-22. Stick to `/api/agents/:id/command` for now. +- Agents enrolled as of 2026-04-22 include CS-SERVER (`6766e973-e703-47c1-be56-76950290f87c`) for Cascades, DESKTOP-DLTAGOI for Cascades LE, AD2 for AZ Computer Guru. Use `GET /api/agents` for the live list. diff --git a/clients/cascades-tucson/docs/cloud/caregiver-m365-p2-rollout.md b/clients/cascades-tucson/docs/cloud/caregiver-m365-p2-rollout.md index 8eab65c..9c81860 100644 --- a/clients/cascades-tucson/docs/cloud/caregiver-m365-p2-rollout.md +++ b/clients/cascades-tucson/docs/cloud/caregiver-m365-p2-rollout.md @@ -107,7 +107,7 @@ All UPNs above use the `@cascadestucson.com` suffix (standard). - **Patricia Sandoval-Beck** — **Resolved 2026-04-22 (CSV inline note from Meredith):** hyphen is correct. SamAccountName may still need to be `Patricia.SandovalBeck` if ALIS/MDM reject hyphens — test during Wave 3. - **Ederick Yuzon** — **Still pending:** spelling asked in 2026-04-22 email. - **Maia Baker** — **Resolved 2026-04-22 (CSV inline note):** part-time, still employed. -- **Reliable Agency shared logins (x2)** — **Resolved 2026-04-22 (John's reply): usernames `reliable1@` and `reliable2@` confirmed.** Shared-login accounts, not per-person. Create in Wave 1 alongside Alma/Kyla. +- **Reliable Agency caregivers** — **Final decision 2026-04-22 (post-HIPAA review): NO shared logins.** Originally planned `reliable1@` / `reliable2@`; dropped because shared log-on IDs for PHI access violate 45 CFR §164.312(a)(2)(i) (Required spec, no compensating-control exception). Per-person accounts only, created when Reliable Agency supplies individual names. Rationale in `docs/security/hipaa-review-2026-04-22.md`. ## Licensing plan (when ready — NOT now) @@ -171,7 +171,8 @@ Group-policy impact: the `CSC - Folder Redirection (LE)` work done for Life Enri - [x] ~~Confirm Christine Nyanzunda is one person, not two~~ (resolved 2026-04-22 — one person, one account) - [x] ~~HR spelling confirmation on Paty Doran, Polett Pinazavala, Patricia Sandoval-Beck, Maia Baker~~ (all resolved 2026-04-22) - [ ] **Ederick Yuzon first-name spelling** — asked in 2026-04-22 email, still outstanding -- [x] ~~Reliable Agency shared-login short usernames~~ (resolved 2026-04-22: reliable1/reliable2 confirmed) +- [x] ~~Reliable Agency shared-login short usernames~~ (SUPERSEDED 2026-04-22 by HIPAA review — no shared logins, per-person only) +- [ ] **Reliable Agency contract review** — confirm staffing contract says caregivers work under Cascades direct clinical control (workforce) vs. agency-supervised (BA). Get individual caregiver names before any PHI access. - [ ] Will caregivers use ALIS on the shared phones (need ALIS accounts + Entra SSO) or only email? - [ ] Does Cascades want to purchase 39 additional Business Premium licenses up-front, or roll out in waves (e.g., MedTechs first, then CCGs, then Caregivers)? - [ ] Confirm pfSense WAN IP(s) are static enough to rely on in a CA Named Location policy diff --git a/clients/cascades-tucson/docs/cloud/cascades-staff-followup-2026-04-22.md b/clients/cascades-tucson/docs/cloud/cascades-staff-followup-2026-04-22.md index ce17b06..c089ed2 100644 --- a/clients/cascades-tucson/docs/cloud/cascades-staff-followup-2026-04-22.md +++ b/clients/cascades-tucson/docs/cloud/cascades-staff-followup-2026-04-22.md @@ -32,7 +32,7 @@ I will send a full list for you all to look over. - **#2 Alma R Montt — ANSWERED.** D+P, ALIS=Y, Outside sign-in=Y. Title = "Memory Care Life Enrichment" (LE staff assigned to Memory Care residents — department stays Life Enrichment, title reflects the MC focus). - **#3 Polett Pinazavala — DEPARTED.** No longer an employee. Was not in AD/M365 yet — just remove from the roster. No license to harvest, no account to disable. - **#4 Ederick Yuzon — STILL PENDING.** John didn't address the spelling; assume he'll send a separate reply or we ping him again. -- **#5 / #6 Agency — CONFIRMED.** Usernames `reliable1` and `reliable2` as proposed. Shared-login accounts for whichever Reliable Agency caregiver is on shift. +- **#5 / #6 Agency — SUPERSEDED 2026-04-22 by HIPAA review.** Although John approved `reliable1` / `reliable2`, post-review the shared-login approach was dropped: HHS has explicitly stated shared log-on IDs for PHI access violate §164.312(a)(2)(i) (Required spec, no compensating-control exception). Replaced with: Reliable Agency must supply individual names; per-person accounts only. No shared credentials. Full rationale in `docs/security/hipaa-review-2026-04-22.md`. ### John's note about "keeps not saving things" diff --git a/clients/cascades-tucson/docs/cloud/cascades-staff-working-list-2026-04-22.md b/clients/cascades-tucson/docs/cloud/cascades-staff-working-list-2026-04-22.md index f9ecae3..5a2ce96 100644 --- a/clients/cascades-tucson/docs/cloud/cascades-staff-working-list-2026-04-22.md +++ b/clients/cascades-tucson/docs/cloud/cascades-staff-working-list-2026-04-22.md @@ -172,14 +172,13 @@ All caregivers sign into the shared company-issued Android phones using their ow | Ezekiel Huerta | Caregiver PRN — Tower | ezekiel.huerta@cascadestucson.com | Y | N | | Maia Baker | MedTech PRN — Memory Care | maia.baker@cascadestucson.com | Y | N | -### Agency — shared-account logins (confirmed 2026-04-22) +### Agency caregivers — no shared logins (HIPAA decision 2026-04-22) -Shared logins used by whoever from Reliable Agency is covering a shift. Not tied to a specific person. John confirmed `reliable1` and `reliable2` as the usernames. +Originally planned as shared logins `reliable1@` / `reliable2@`. **Dropped** after HIPAA review — shared log-on IDs for PHI access violate 45 CFR §164.312(a)(2)(i) Unique User Identification (Required spec, no compensating-control exception). See `docs/security/hipaa-review-2026-04-22.md`. -| Name | Role | Email | Phone | Outside sign-in | -|---|---|---|---|---| -| Reliable Agency shared login #1 | Agency caregiver | reliable1@cascadestucson.com | Y | N | -| Reliable Agency shared login #2 | Agency caregiver | reliable2@cascadestucson.com | Y | N | +**Policy going forward:** Reliable Agency must provide individual names before any shift where a caregiver needs PHI access. Per-person accounts only. If the agency won't commit to that, their caregivers don't get ALIS / email access and must work under direct supervision of a Cascades-employed caregiver who does. + +No entries on this list until names arrive. --- @@ -194,8 +193,8 @@ Shared logins used by whoever from Reliable Agency is covering a shift. Not tied | Shared front-desk receptionists | 4 | | Courtesy Patrol | 3 | | Caregivers / shift staff | 37 | -| Agency shared logins | 2 | -| **Total active identities / mailboxes** | **68** | +| Agency caregivers | 0 *(per-person only; no accounts until Reliable provides names — HIPAA decision 2026-04-22)* | +| **Total active identities / mailboxes** | **66** | ### Employees on the roster but no IT account @@ -223,7 +222,7 @@ Shared logins used by whoever from Reliable Agency is covering a shift. Not tied - **Britney Thompson — DEPARTED.** Disable existing AD account and harvest Business Standard + Exchange Online Essentials license. - **Polett Pinazavala — DEPARTED.** Not in AD, no action needed other than removal from roster. - **Alma R Montt — ANSWERED.** Title "Memory Care Life Enrichment", D+P, ALIS=Y, Outside=Y. -- **Agency usernames — CONFIRMED.** `reliable1` and `reliable2` as proposed. +- **Agency usernames — SUPERSEDED by HIPAA review.** John approved `reliable1` / `reliable2`, but shared-login accounts for PHI access are not HIPAA-compliant (§164.312(a)(2)(i)). No accounts created. Reliable Agency must provide individual names for per-person accounts. - **Drivers — NO ACCOUNTS.** Disable existing 3 AD accounts (Richard Adams, Julian Crim, Christopher Holick). ## Still pending from Meredith/John diff --git a/clients/cascades-tucson/docs/cloud/p2-staff-candidates.md b/clients/cascades-tucson/docs/cloud/p2-staff-candidates.md index e1f626b..32a636b 100644 --- a/clients/cascades-tucson/docs/cloud/p2-staff-candidates.md +++ b/clients/cascades-tucson/docs/cloud/p2-staff-candidates.md @@ -110,7 +110,8 @@ No answer yet. This decision directly changes the license count and the CA polic | Office staff with Outside=Y (Office-PHI external-OK) | **18** | Includes Alma. Britney removed (departed). | | + Office Outside=N + ALIS=Y (Allison Reibschied, Sharon Edwards) | **20** | Need CA coverage even in building-only posture | | + Matt Brooks (dual-dept, ALIS=Y) | **21** | Per rollout plan §3 | -| All licensed seats under building-only-default | 21 office + 3 Courtesy Patrol + 4 Reception + 37 caregivers + 2 agency = **67** | Plus Ramon Castaneda for office non-PHI = **68** total active identities | +| All licensed seats under building-only-default | 21 office + 3 Courtesy Patrol + 4 Reception + 37 caregivers = **65** | Plus Ramon Castaneda for office non-PHI = **66** total active identities | +| Agency caregivers (per-person, if/when names arrive) | +1 each | No accounts until Reliable Agency provides names — HIPAA §164.312(a)(2)(i) prohibits shared PHI-access logins | ## Action items @@ -118,7 +119,7 @@ No answer yet. This decision directly changes the license count and the CA polic - [ ] Push Meredith for the "restrict everyone or just some" decision — still unanswered as of 2026-04-22 - [x] ~~Britney phone+outside flags~~ (resolved 2026-04-22: departed) - [x] ~~Alma R Montt title~~ (resolved 2026-04-22: Memory Care Life Enrichment, D+P/Y/Y) -- [x] ~~Agency shared-login username preference~~ (resolved 2026-04-22: reliable1/reliable2 confirmed) +- [x] ~~Agency shared-login username preference~~ (SUPERSEDED 2026-04-22 by HIPAA review — no shared logins; per-person only) - [ ] **Ederick Yuzon spelling** — only remaining question from the 2026-04-22 follow-up email - [ ] Decide: standalone P2 add-on for the 19 OR move those users to Business Premium OR move whole tenant to Business Premium (default recommendation: Premium tenant-wide) - [ ] Build CA policy `CSC - Office Staff PHI Access` separate from the caregiver mobile policy diff --git a/clients/cascades-tucson/docs/cloud/questionnaires/cascades-staff-editor-2026-04-22.html b/clients/cascades-tucson/docs/cloud/questionnaires/cascades-staff-editor-2026-04-22.html index 69b89c7..0c10f27 100644 --- a/clients/cascades-tucson/docs/cloud/questionnaires/cascades-staff-editor-2026-04-22.html +++ b/clients/cascades-tucson/docs/cloud/questionnaires/cascades-staff-editor-2026-04-22.html @@ -340,9 +340,10 @@ const INITIAL = { ["Ezekiel Huerta","Caregiver PRN — Tower","Caregivers (shift staff)","D+P",false,true,""], ["Maia Baker","MedTech PRN — Memory Care","Caregivers (shift staff)","D+P",false,true,"Part-time (confirmed)"], - // Caregivers — agency shared-login accounts (usernames confirmed by John 2026-04-22) - ["Reliable Agency shared login #1","Agency caregiver","Caregivers (shift staff)","D+P",false,true,"Shared login — whoever from Reliable Agency is on shift signs in. Username: reliable1@cascadestucson.com (confirmed by John)."], - ["Reliable Agency shared login #2","Agency caregiver","Caregivers (shift staff)","D+P",false,true,"Shared login — whoever from Reliable Agency is on shift signs in. Username: reliable2@cascadestucson.com (confirmed by John)."], + // Agency caregivers — no shared accounts. HIPAA review 2026-04-22: shared logins for PHI + // access violate 45 CFR 164.312(a)(2)(i) Unique User Identification. Reliable Agency must + // supply individual names before per-person accounts can be provisioned. No rows here + // until names arrive. ] }; const CAREGIVER_DEPT = "Caregivers (shift staff)"; diff --git a/clients/cascades-tucson/docs/cloud/questionnaires/cascades-staff-open-questions-2026-04-22.docx b/clients/cascades-tucson/docs/cloud/questionnaires/cascades-staff-open-questions-2026-04-22.docx index dd65c9e29b41c0ae80dce40064c068982acd7a43..bded011471ea89d37ce6cf818c5a17f7e3093188 100644 GIT binary patch delta 1325 zcmV+|1=9NA7l9cJP)h>@6aWAK2mptPu?#u^0*8r{NCDXbhl!&j0s#((iI!ZYesWce z1ONap3zIPe8Gl`J<3td?N~0I-TE})w2q{;bl*ul{OSa-7=7A?_EVZPm9Zidwk%jhY z?*Mn;2)yr6_9XO-7f&{#=&7M%{q5ulDKkvf}2 zKdinvxro3zp%bA<<1A{>M%P!D^)#WlDo{IM1KLjOS$~u}S58MG8|PREJERgducc%P z;rP~Mqnb=o8j8_cwqK~xWIR3}6+-IBn_N@U`2RBeEKT@(aE(H!ryHSW(Mmdn(dg=O zwA&DV0*a|EMa&ROgBHyOqpKTXW09bRkMDnjdyQ~kxeyF{hlRreNW+5@X$te$qk=nW zoj2}+3xCr(+F@!PwtnrqEvU)3L)5K&0?cGQIX@YnolGVGAN~N~l~Nc?VBNqi)xsq3 zN|PPH4HaeO(7?Bqsk*&n9lWMoe{O+~spcOregeYtPOWmG-$Fwba4sQ3=RAFD5x)gT zP@pH#<>+O?L@H)5@GVr~Q6r11ak)PtE!dx{5P!3%MFX1ZA$)D5)7SuK1(u}PI^<%5 zutwAzYe5^{o*F8G55p#znVu$KJ!X7~MX9JkwEY3hRUw!m=T#C6iZ-k45-d9CywoHe zvKQW>@Texox5HOVoaCzgv3f`PxGuLIJ*(HCg&G{}k$BVZ2tt+XLc8VUfv8|+~4sELx)`m{TV}Z58T`<%Jx__#Ko}Y>X z_^wg>`Nrnhi$kSHNG;rH5%ukbngtG zJxPw`^6N@0d+^PLUms5=lQVw%tfx6&e|d4%l~I|!5neowN`8LUZZR^;-Trn>&QY1QY-O00;nwiL*cl zw*dl&iL?0#UI7A!iIZ6hKLUq|lbQ-Q0*8r{(+Wrqhl!S4rG9c%j06AxFAI|?3o!zR jiIZFl90Ammc?%u_hl!J!3mgKC36r-ABnImW00000Wmk1n delta 1165 zcmV;81akX<8Q~WUP)h>@6aWAK2mrT)u?#u^0=I;dNCDXbw}hi30s#)UgqB=HNod&Y z0{{T@36n7c8GpfU<2Dfem8mXGuukL%={7Lp1Zj5L^)`zHjeF>+prw&Sgyd*R%BuFX z|Iq$R@BNhhk`5`^NziO-q(yB&5=C<6&3iK=o}T}r6|B)ZNoJlL9ZnNKlT#s0HBWwA zetU3|fb+r>LXp9F(xXex&rZ8pL3yjucwhs@&ANF~dw<`|($wWOYT*v4LBn$;SuH#d zZIyOpi^fup&ar*1(rh|?nQ9?T5=^eB=)=8zx4u^h-E1w?JXuPwFiFo&)9r$I zi6~~S5jjI_EIPDnOwKNa%SC|>K7ITRt_{L<>titN9Tpxnkbzq-$`UT}fC{dp^TD`} zF6`iFi+^cwIQVrRHlVWUh-jSo447=1y*!v6A7mN8AHM_eOd~87uON(t;WCAxok`F{sKe!J&t}cWlr0a2Z}) z$r71yEAu+!@dRGIxM34li`xlMSvu*FO$IB$vF`|eKqbYBO9ueXekrXR!N+L1Zjw>TWD*|7C(dw38h?j| zfy&|eZW_x7Hz&mgMz|-_@ZU-53*%Vd89eg!*uf*ym(%dy$@I_v;`e`c`RDDrHhE}x z!r$j`%uU03Yu0!%^s-eeRWW=DAm5bLHl?MBy{QpyXjj}4IajD0Y6E@Sz+PzW6ZpPY zeEmy5e$dTc~AO&tgw7A zTQfGa^W^I+4of2cU|6+24mT;eftGF#Rq6eK?d(rbO9KQH000080JnseT(jZ_wE+UR zgtM6mUI7BPgp>ISKLWRelR67G0=I;da|=igw}h5lL`i7a>;nJ*^a+#63o!z>gp>RW f904?w84Ml*w}g{93>*UO2$NR~BnC?g00000G>R~s diff --git a/clients/cascades-tucson/docs/cloud/user-account-rollout-plan.md b/clients/cascades-tucson/docs/cloud/user-account-rollout-plan.md index 11c4168..0fd5c03 100644 --- a/clients/cascades-tucson/docs/cloud/user-account-rollout-plan.md +++ b/clients/cascades-tucson/docs/cloud/user-account-rollout-plan.md @@ -29,11 +29,11 @@ Build every person on the 2026-04-22 CSV into a consistent AD + M365 identity, l | **Courtesy Patrol** | D+P | N | N | 3 | Sebastian Leon, Sheldon Gardfrey, Ray Rai | | **Shared-PC Reception** | D | N | N | 4 | Cathy, Shontiel, Kyla, Michelle | | **Caregiver (shared-phone)** | D+P | N | Y | 37 | See caregiver-m365-p2-rollout.md | -| **Agency shared login** | D+P | N | Y | 2 | `reliable1`, `reliable2` | +| **Agency caregivers (per-person)** | D+P | N | Y | 0 | None created. HIPAA-mandated per-person IDs — Reliable must supply names. No shared logins. | | **Driver (no IT access)** | — | — | — | 3 | Richard Adams, Julian Crim, Christopher Holick — on roster for tracking, existing AD accounts to be disabled | | **Departed (disable/remove)** | — | — | — | 2 | Britney Thompson (has AD+M365, must be disabled), Polett Pinazavala (no account, just remove from roster) | -(Identities to create or keep active: **68**. Roster-only-no-account: 3 drivers. Departures: Britney + Polett. Christine Nyanzunda sits in one persona — Office-PHI — with her caregiver-shift sign-in handled via exception group if needed.) +(Identities to create or keep active: **66**. Roster-only-no-account: 3 drivers. Departures: Britney + Polett. No agency accounts created — per-person names required. Christine Nyanzunda sits in one persona — Office-PHI — with her caregiver-shift sign-in handled via exception group if needed.) ## 3. License mapping per persona @@ -51,14 +51,15 @@ Build every person on the 2026-04-22 CSV into a consistent AD + M365 identity, l | Courtesy Patrol | Business Standard | Could be F3 if they don't need full desktop Office; confirm with Meredith | | Shared-PC Reception | Business Standard | Frontdesk@ stays as shared mailbox, named accounts read it | | Caregiver | **Business Premium** | Per `caregiver-m365-p2-rollout.md` — P2 is load-bearing for shared-phone CA | -| Agency shared login | **Business Premium** | Same CA posture as caregivers (shared-phone, building-only) | +| Agency caregivers (per-person) | **Business Premium** each | Only provisioned when Reliable Agency provides individual names. Zero created as of 2026-04-22. | | Driver | **None** | No IT access — accounts disabled. License previously used (if any) harvested. | | Britney Thompson (departing) | **None** (harvest) | Disable account, free Business Standard + Exchange Online Essentials | Expected license count at full rollout: -- Business Premium: 18 (office PHI ext) + 2 (office PHI int) + 1 (Matt) + 37 caregivers + 2 agency = **60** +- Business Premium: 18 (office PHI ext) + 2 (office PHI int) + 1 (Matt) + 37 caregivers = **58** - Business Standard: 1 (Ramon) + 3 courtesy + 4 reception = **8** - F3: 0 (drivers no longer need accounts) +- Per-person agency: +1 each if/when Reliable Agency provides names **Post-2026-04-22 update:** With the building-only-by-default CA decision confirmed, every licensed user needs Entra P1 coverage (either via Business Premium, or Business Standard + standalone Entra P1). Without P1, CA policies don't apply and the user sidesteps the default-deny. This effectively collapses the mixed-SKU table above into a recommendation for **Business Premium tenant-wide (~68 seats)** — the Business Standard rows stay in the table only as a reference for what we'd buy if budget forces unbundling. Proceed with Premium-tenant-wide unless Meredith pushes back. Britney's harvested Business Standard + Exchange Online Essentials license plus any freed driver licenses go back into the pool to offset the Premium purchase. @@ -129,27 +130,64 @@ These must be resolved before creating or converting accounts. See also `cascade | **Ederick Yuzon** — spelling not confirmed | **Still pending Meredith/John.** | Block on creation of his caregiver account only. Everyone else proceeds. Tentative: `Ederick.Yuzon` if needed to unblock Wave 3. | | **Matt Brooks** — AD dept = Maintenance, CSV note "works in both departments" | Confirmed (CSV-inline). | Keep in Maintenance OU; add to secondary MC group for access overlap. | | **37 caregivers** — on CSV, none in AD | Unchanged. | Create all 37 AD accounts (+ M365) in Wave 3. | -| **2 agency placeholders** — on CSV, not in AD | **RESOLVED 2026-04-22 (John's reply) — usernames `reliable1` / `reliable2` confirmed. Shared logins, not per-person.** | Create 2 shared AD/M365 accounts: `reliable1@cascadestucson.com` and `reliable2@cascadestucson.com`. Audit attribution caveat: individual accountability in sign-in logs is weaker because multiple people share the account. Acceptable tradeoff. | +| **2 agency placeholders** — on CSV, not in AD | **RESOLVED 2026-04-22 (Howard, post-HIPAA-review) — NO shared logins. Per-person accounts only.** | Do NOT create `reliable1`/`reliable2`. Reliable Agency must supply individual names before any caregiver can access PHI. Until then, agency staff work under direct supervision of a Cascades-employed caregiver who is signed in. Rationale documented in `docs/security/hipaa-review-2026-04-22.md`. | | **Generic AD accounts** (`Culinary`, `RECEPTIONIST`, `saleshare`, `directoryshare`) | Unchanged. | Phase 5 cleanup after named-account coverage. | **Username convention for new accounts:** TitleCase `First.Last` (e.g., `Alma.Montt`, `Kyla.QuickTiffany`). Existing lowercase exceptions in AD (`britney.thompson`, `karen.rossini`, `lauren.hasselman`) are the known legacy cases — leave as-is, don't rename. All net-new accounts follow TitleCase. ## 7. Rollout sequence -### Wave 0 — Pre-flight (blocks waves 1+) -- **Ederick Yuzon spelling** — only remaining email blocker. Blocks Wave 3 only (his caregiver account); does NOT block Waves 1/2. -- Final license decision (Business Premium tenant-wide vs. mixed) — recommendation is Premium tenant-wide, needs Meredith sign-off -- Purchase license count locked in +### Wave 0 — HIPAA pre-flight (must complete before any account changes) -### Wave 1 — Departures + new office accounts (ready to execute) -- Disable `britney.thompson` AD account; convert mailbox to shared; harvest Business Standard + Exchange Online Essentials license +Per `docs/security/hipaa-review-2026-04-22.md`. These are compliance blockers, not operational blockers — fix before touching accounts. + +- **Sign Microsoft HIPAA BAA** (5 min, free) — M365 Admin Center → Settings → Org Settings → Security & Privacy → HIPAA BAA +- **Verify/sign ALIS BAA** (Meredith-ask) +- **Create break-glass cloud-only admin** (`breakglass@cascadestucson.com`): excluded from all CA, FIDO2 security key, vaulted password, sign-in alerts to Howard + Meredith +- **Enable SMB3 encryption** on `\\CS-SERVER\homes`: `Set-SmbShare -Name homes -EncryptData $true` +- **Extend M365 audit retention** to 6+ years (Purview Audit Premium add-on or retention policy) +- **Put Britney's mailbox on Litigation Hold** with verified archive license — BEFORE her account is disabled +- **Ask Meredith** for the Reliable Agency staffing contract (confirm direct-control language = workforce, not BA) +- **Draft Risk Analysis** `docs/security/risk-analysis-2026-04.md` following NIST 800-66 Rev 2 §3 +- **Create Security Rule Implementation Register** `docs/security/implementation-register.md` + +### Wave 0.5 — Entra Connect / AD-M365 identity tie-in (before any account creation in Wave 1) + +Without Entra Connect, new accounts are cloud-only and create the same AD-vs-M365 drift the tenant already suffers from. Install order: + +1. **AD prereq cleanup** (no user impact — all reversible): + - Rename `Tamra.Johnson` → `Tamra.Matthews` + - Rename `strozzi` → `Shelby.Trozzi` + - Rename `Alyssa.Shestko` → `Alyssa.Brooks` + delete lowercase duplicate `alyssa.brooks` + - Fix `Christopher.Holik` → `Christopher.Holick` + - Fix `Matt.Brooks` UPN to `matthew.brooks@` OR update M365 side to `matt.brooks@` + - Delete confirmed former employees (Anna.Pitzlin, Nela.Durut-Azizi, Jodi.Ramstack, Monica.Ramirez) + - Disable + remove legacy accounts (Haris.Durut, Nuria.Diaz, Cathy.Reece, Kelly.Wallace, Isabella.Islas, ann.dery) +2. **Add UPN suffix** `cascadestucson.com` in AD Domains and Trusts +3. **Update all synced users' UPN** to `firstname.lastname@cascadestucson.com` +4. **Convert M365 role-based accounts to shared mailboxes** FIRST (accounting@, frontdesk@, hr@, etc. — listed in `docs/cloud/m365.md`) — frees 11 licenses +5. **Delete** `Kristiana Dowse` and `howaed` typo accounts from M365 +6. **Reconcile** `nick pavloff` (M365-only) — create AD account if still employed, or delete +7. **CS-SERVER readiness check** (separate task — OS version, .NET, disk, FSMO, conflict with QuickBooks DB listener) +8. **Install Entra Connect in staging mode** on CS-SERVER → Password Hash Sync → Seamless SSO → scope to `OU=Departments` +9. **Review planned sync output** for unexpected matches/duplicates +10. **Take out of staging**, verify users see their cloud mailboxes working on the same password +11. **Communicate to users:** Outlook will prompt once for password; enter your Windows password + +User-visible impact: one Outlook password prompt on day-of-cutover. **No impact on AD domain logon.** + +### Wave 1 — Departures + new office accounts (ready after Waves 0 and 0.5) +- Disable `britney.thompson` AD account — AFTER Litigation Hold is confirmed, mailbox converted to shared with designated custodian (likely Meredith or Lois), Business Standard + Exchange Online Essentials license harvested - Disable 3 driver AD accounts (`Richard.Adams`, `Julian.Crim`, `Christopher.Holick`) - Ask Meredith whether to keep or retire `Transportation@` shared mailbox -- Create AD + M365 for Alma R Montt (`Alma.Montt` — Memory Care Life Enrichment, D+P, ALIS=Y, Outside=Y) -- Create AD + M365 for Kyla QuickTiffany (`Kyla.QuickTiffany` — Shared-PC Reception, D only, building-only) -- Create AD + M365 for `reliable1@` and `reliable2@` (shared agency logins, D+P, ALIS=Y, building-only) +- Create AD accounts (and let Entra Connect sync to M365) for: + - Alma R Montt (`Alma.Montt` — Memory Care Life Enrichment, D+P, ALIS=Y, Outside=Y) + - Kyla QuickTiffany (`Kyla.QuickTiffany` — Shared-PC Reception, D only, building-only) - Validate group membership + CA policy assignment on the new accounts before moving to Wave 2 -- Pilot the `CSC - Building Only (Default)` policy with Kyla +- Pilot the `CSC - Building Only (Default)` policy with Kyla (Report-only mode first) + +### Wave 1 — DO NOT DO +- Do NOT create `reliable1@` or `reliable2@` shared agency accounts (HIPAA review 2026-04-22). See §6 reconciliation + `docs/security/hipaa-review-2026-04-22.md`. ### Wave 2 — Existing office accounts, reassignment only - Move existing users into new OU layout (no identity changes, just OU move + group membership) @@ -185,6 +223,28 @@ Applies to Wave 1 + Wave 3 (and any future hire). Precise script will be built l - **Folder redirection GPO rollout** (`CONTEXT.md` §48) — when we move users to new OUs, make sure the FR GPOs are re-linked to the new OU or stay linked to parent `OU=Cascades Users`. Test on one mover before batch. - **Intune phone rollout** (`PROJECT_STATE.md`) — caregiver accounts must exist before Wave 3 of phone deployment (24 remaining Samsung A15s). Identity-first, device-second. - **Business Premium purchase proposal** (`docs/proposals/m365-premium-upgrade.md`) — blocks wave 1 if Meredith hasn't approved license spend. +- **File-share migration: Synology → CS-SERVER** (`docs/migration/phase2-server-prep.md` §4c–4d + `docs/migration/phase4-synology.md`) — Synology Drive Client is live-syncing `\\cascadesds\*` → `D:\Shares\Main` on CS-SERVER (confirmed 2026-03-07). Before users are cut over to CS-SERVER-sourced mapped drives, the AD security groups used for NTFS ACLs on CS-SERVER (`SG-Management-RW`, `SG-Sales-RW`, `SG-Culinary-RW`, `SG-Directory-RW`, `SG-IT-RW`, `SG-Receptionist-RW`, `SG-Chat-RW`, `SG-Server-RW`) must: + 1. Exist in AD (created by `scripts/phase2-ad-setup.ps1`) + 2. Have membership that matches the current per-user access on Synology — a **permission-inventory** step (see below) must produce this mapping before `scripts/phase2-file-shares.ps1` runs + 3. Populate from the user rollout waves — the 22 office-PHI users, 4 receptionists, 3 courtesy patrol, 1 Matt Brooks (dual-dept), 1 Ramon Castaneda, plus caregivers as needed all land in the right `SG-*` groups at account creation + - Additional HIPAA additions to the phase2 script (per `docs/security/hipaa-review-2026-04-22.md`): enable SMB3 encryption (`Set-SmbShare -EncryptData $true` on every share) and enable Object Access auditing for §164.312(b) Audit Controls + - Drivers off the SG-* lists entirely — they lose file-share access along with their AD accounts + +### Permission-inventory prerequisite + +A one-time non-destructive read of the live Synology is needed to produce the mapping from Synology local users/groups → AD security groups. Commands (run via SSH to `admin@192.168.0.120`, creds at `clients/cascades-tucson/synology-cascadesds.sops.yaml`): + +```bash +sudo synogroup --list # Synology local groups +sudo synouser --list # Synology local users +sudo cat /etc/synoinfo.conf | grep -i share # share definitions +for share in homes Management SalesDept Server chat Public Culinary IT Receptionist directoryshare; do + sudo synoacltool -get /volume1/$share # ACLs per share +done +sudo synoshare --get homes # per-share config incl. SMB encryption state +``` + +Output goes to `docs/migration/synology-permission-inventory.md`, which is then the reference for populating AD groups and building `phase2-file-shares.ps1` inputs. Discovery is non-destructive and can run any time the Synology is up — does not require a maintenance window. ## 10. Open decisions blocking the rollout @@ -199,7 +259,7 @@ Applies to Wave 1 + Wave 3 (and any future hire). Precise script will be built l - Alma R Montt → `Alma.Montt`, title "Memory Care Life Enrichment", D+P, ALIS=Y, Outside=Y (answered by John). - Britney Thompson → **departed (John)**. Disable AD + harvest license. - Polett Pinazavala → **departed (John)**. Remove from roster. -- Agency shared logins → usernames `reliable1` / `reliable2` (confirmed by John). +- Agency shared logins → **NOT CREATED** (HIPAA review supersedes John's confirmation — §164.312(a)(2)(i) prohibits shared PHI-access log-ons). Per-person accounts only when Reliable Agency provides names. - Drivers → no IT access per Howard. Disable 3 AD accounts. Stay on roster for tracking. ## 11. Related docs diff --git a/clients/cascades-tucson/docs/migration/phase2-server-prep.md b/clients/cascades-tucson/docs/migration/phase2-server-prep.md index ad1a705..0f8aaf9 100644 --- a/clients/cascades-tucson/docs/migration/phase2-server-prep.md +++ b/clients/cascades-tucson/docs/migration/phase2-server-prep.md @@ -109,6 +109,13 @@ Run `scripts/phase2-file-shares.ps1` on CS-SERVER (AFTER sync completes). Creates SMB shares for synced folders and sets NTFS permissions matching Synology access. **HIPAA §164.312(b):** After shares are created, enable Advanced Audit Logging on all PHI-containing shares (Management, Server, homes) to track read/write/delete operations. +**Prerequisite (added 2026-04-22 per `docs/security/hipaa-review-2026-04-22.md` + user-rollout dependency):** Before this script runs, the Synology permission inventory must be captured and translated to AD security group memberships. See `docs/migration/phase4-synology.md` §6.0.1–6.0.2 for the discovery commands and `docs/migration/synology-permission-inventory.md` (to be created) for the mapping output. + +**HIPAA-review additions (must be applied as part of this phase, not deferred):** +- `Set-SmbShare -EncryptData $true` on every share in the table — satisfies Addressable specs §164.312(a)(2)(iv) at-rest and §164.312(e)(2)(ii) in-transit encryption +- NTFS SACL (audit rule) set to audit Success + Failure for ReadData / WriteData / Delete / ChangePermissions on all PHI shares — satisfies Required spec §164.312(b) Audit Controls +- See `phase4-synology.md` §6.0.3 for the exact PowerShell + | Share | NTFS Access | SMB Share | |---|---|---| | Management | SG-Management-RW = Modify | `\\CS-SERVER\Management` | diff --git a/clients/cascades-tucson/docs/migration/phase4-synology.md b/clients/cascades-tucson/docs/migration/phase4-synology.md index c94eb20..be89fd8 100644 --- a/clients/cascades-tucson/docs/migration/phase4-synology.md +++ b/clients/cascades-tucson/docs/migration/phase4-synology.md @@ -1,5 +1,86 @@ # Step 6: Synology Transition (~2 hours, remote) +**Pre-requisite before any of the 6.x steps below:** a permission inventory of the live Synology must be captured and translated into AD group memberships, and CS-SERVER's NTFS + SMB permissions on the synced shares must match before users' drives get remapped. That work lives in §6.0. + +--- + +## 6.0 — Permission inventory + CS-SERVER ACL application (pre-cutover) + +**Why:** Synology Drive Client has been live-syncing `\\cascadesds\*` → `D:\Shares\Main` on CS-SERVER since 2026-03-07 (per `phase2-server-prep.md` §4c). Sync copies the files but **not** the permissions — CS-SERVER's shares inherit whatever the script in `phase2-file-shares.ps1` applies, which currently assumes AD security group memberships that are correct for the target state. Those group memberships are empty or incomplete today. + +Before users' mapped drives switch from Synology to CS-SERVER, the ACLs on CS-SERVER must replicate current Synology access rights. Do this in three steps. + +### 6.0.1 — Discovery (non-destructive, no maintenance window needed) + +SSH into `admin@192.168.0.120` (credentials at `clients/cascades-tucson/synology-cascadesds.sops.yaml`). Run: + +```bash +sudo synogroup --list +sudo synouser --list +sudo cat /etc/synoinfo.conf | grep -iE 'share|mode' +for share in homes Management SalesDept Server chat Public Culinary IT Receptionist directoryshare; do + echo "=== $share ===" + sudo synoacltool -get /volume1/$share + sudo synoshare --get "$share" 2>/dev/null || true +done +``` + +Paste the output into a new file `docs/migration/synology-permission-inventory.md` with one section per share. Capture: + +- Owner, group, mode (bitmask) +- Per-user ACL entries (read / write / delete / changeperm) +- Per-group ACL entries +- SMB-share-level permission overrides +- Inheritance flags + +### 6.0.2 — Map Synology accounts to AD + +Produce a translation table in the inventory doc: + +| Synology identity | AD identity | Notes | +|---|---|---| +| `admin` | Domain Admins | keep | +| `meredith.kuhn` (Synology local) | `Meredith.Kuhn` (AD) | same human | +| Synology group `Management` | AD `SG-Management-RW` | direct 1:1 | +| Synology group `Marketing` | AD `SG-Sales-RW` | renamed | +| ... | ... | ... | + +Any Synology account with no AD equivalent either (a) corresponds to a departed employee and gets dropped, or (b) is a new account we need to create in AD first (feeds back into the user rollout waves). + +### 6.0.3 — Apply to CS-SERVER + HIPAA additions + +Update `scripts/phase2-file-shares.ps1` inputs to reflect the mapping, then run on CS-SERVER. After shares + NTFS are applied, add HIPAA-review-required settings per `docs/security/hipaa-review-2026-04-22.md`: + +```powershell +# Enable SMB3 encryption on every PHI-containing share (addresses 164.312(a)(2)(iv), (e)(2)(ii)) +foreach ($share in 'homes','Management','SalesDept','Server','chat','Culinary','IT','Receptionist','directoryshare') { + Set-SmbShare -Name $share -EncryptData $true -Force +} + +# Enable Object Access auditing on the PHI file-share root (addresses 164.312(b)) +auditpol /set /subcategory:"File System" /success:enable /failure:enable +# NTFS SACL — audit reads+writes on D:\Shares and subtree +$acl = Get-Acl D:\Shares +$auditRule = New-Object System.Security.AccessControl.FileSystemAuditRule( + 'Everyone','ReadData,WriteData,Delete,ChangePermissions','ContainerInherit,ObjectInherit','None','Success,Failure') +$acl.AddAuditRule($auditRule) +Set-Acl D:\Shares $acl +``` + +Verify with: + +```powershell +Get-SmbShare | Select-Object Name, EncryptData +Get-Acl D:\Shares -Audit | Format-List +auditpol /get /subcategory:"File System" +``` + +### 6.0.4 — Validation before any user is cut over + +Pick one pilot user (Sharon Edwards on DESKTOP-DLTAGOI — already our folder-redirection pilot). Map her CS-SERVER drives manually, open representative files from each share she currently uses on Synology, verify open/save/delete works. Do not touch the GPO drive maps or run §6.1 below until the pilot validates cleanly. + +**Rollback at this stage:** no user impact — just don't push the GPO change, and the Synology shares remain authoritative. + --- ## 6.1 — Verify drive mappings diff --git a/clients/cascades-tucson/docs/migration/scripts/entra-connect-preflight-remediation.ps1 b/clients/cascades-tucson/docs/migration/scripts/entra-connect-preflight-remediation.ps1 new file mode 100644 index 0000000..89f6517 --- /dev/null +++ b/clients/cascades-tucson/docs/migration/scripts/entra-connect-preflight-remediation.ps1 @@ -0,0 +1,212 @@ +# ============================================================================ +# Entra Connect Pre-flight Remediation - CS-SERVER +# ---------------------------------------------------------------------------- +# Applies the three items from the 2026-04-22 readiness check: +# 1. Time sync (w32tm) - immediate, no reboot +# 2. TLS 1.2 enforcement (.NET + Schannel) - requires reboot +# 3. Install Windows Server Backup feature - no reboot +# +# Then schedules a reboot at 18:00 local time (Arizona) for Schannel changes +# to take effect. Snapshot of all pre-change state is written to +# D:\Backups\pre-entra-connect-\ for rollback. +# +# To cancel the scheduled reboot at any time before 18:00: shutdown /a +# ---------------------------------------------------------------------------- +# Prepared: 2026-04-22 +# Source: docs/migration/scripts/entra-connect-preflight-remediation.ps1 +# ============================================================================ + +$ErrorActionPreference = 'Continue' +$TargetRebootHour = 18 # 6 PM local (Arizona) + +function Section($n) { + Write-Output '' + Write-Output ('=' * 72) + Write-Output "== $n" + Write-Output ('=' * 72) +} + +function Status($ok, $msg) { + $tag = if ($ok) { '[OK] ' } else { '[FAIL]' } + Write-Output "$tag $msg" +} + +# ---------------------------------------------------------------------------- +Section '0. Pre-flight snapshot (rollback material)' +# ---------------------------------------------------------------------------- +$ts = Get-Date -Format 'yyyy-MM-dd-HHmm' +$backupDir = "D:\Backups\pre-entra-connect-$ts" +try { + New-Item -Path $backupDir -ItemType Directory -Force | Out-Null + Status $true "Backup dir: $backupDir" +} catch { + Status $false "Could not create $backupDir - $_" + exit 1 +} + +# Export registry keys we're about to modify +reg export "HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" "$backupDir\dotnet-64.reg" /y 2>&1 | Out-Null +reg export "HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319" "$backupDir\dotnet-32.reg" /y 2>&1 | Out-Null +reg export "HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" "$backupDir\schannel-protocols-pre.reg" /y 2>&1 | Out-Null +Status $true 'Registry pre-state exported (.NET + Schannel Protocols)' + +# Snapshot w32tm state +w32tm /query /configuration 2>&1 | Out-File "$backupDir\w32tm-config-pre.txt" +w32tm /query /status 2>&1 | Out-File "$backupDir\w32tm-status-pre.txt" +w32tm /query /peers 2>&1 | Out-File "$backupDir\w32tm-peers-pre.txt" +Status $true 'w32tm pre-state captured' + +# Snapshot recent events (for post-reboot comparison) +try { + Get-WinEvent -LogName System -MaxEvents 200 -ErrorAction Stop | + Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message | + Export-Csv "$backupDir\events-system-pre.csv" -NoTypeInformation + Status $true "Event log snapshot saved (200 System events)" +} catch { + Status $false "Event log snapshot: $_" +} + +Write-Output '' +Write-Output ("To roll back TLS changes after reboot: " + + "`nreg import $backupDir\dotnet-64.reg `nreg import $backupDir\dotnet-32.reg " + + "`nreg import $backupDir\schannel-protocols-pre.reg `nRestart-Computer") + +# ---------------------------------------------------------------------------- +Section '1. Time sync fix (w32tm) - no reboot' +# ---------------------------------------------------------------------------- +try { + # PDC emulator should be an authoritative time source + sync from external pool + $ntpPeers = 'time.windows.com,0x8 pool.ntp.org,0x8 time.nist.gov,0x8' + & w32tm /config /manualpeerlist:$ntpPeers /syncfromflags:manual /reliable:yes /update | Out-Null + Status $true "Configured w32tm peer list: $ntpPeers" + + Restart-Service w32time -Force + Status $true 'Restarted w32time service' + + Start-Sleep 4 + & w32tm /resync /force 2>&1 | Out-Null + Start-Sleep 3 + + $statusOut = & w32tm /query /status 2>&1 + $statusOut | Out-File "$backupDir\w32tm-status-post.txt" + $statusOut | Select-Object -First 20 | ForEach-Object { Write-Output " $_" } + + $refIdLine = $statusOut | Where-Object { $_ -match 'ReferenceId' } | Select-Object -First 1 + if ($refIdLine -match 'LOCL') { + Status $false "ReferenceId still LOCL - w32tm has not synced yet. Check firewall for outbound UDP 123." + } else { + Status $true "ReferenceId: $refIdLine (no longer LOCL)" + } +} catch { + Status $false "Time sync fix: $_" +} + +# ---------------------------------------------------------------------------- +Section '2. TLS 1.2 enforcement (.NET + Schannel) - requires reboot' +# ---------------------------------------------------------------------------- +# .NET framework: enable strong crypto + system default TLS versions for both +# 64-bit and 32-bit runtimes. These take effect immediately for new processes. +foreach ($p in 'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319', + 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319') { + try { + if (-not (Test-Path $p)) { New-Item -Path $p -Force | Out-Null } + New-ItemProperty -Path $p -Name 'SchUseStrongCrypto' -PropertyType DWord -Value 1 -Force | Out-Null + New-ItemProperty -Path $p -Name 'SystemDefaultTlsVersions' -PropertyType DWord -Value 1 -Force | Out-Null + Status $true ".NET TLS keys set at $p" + } catch { + Status $false ".NET TLS at $p - $_" + } +} + +# Schannel: disable TLS 1.0 and 1.1 (both Client and Server). Enable TLS 1.2 +# explicitly. Takes effect only after reboot. +$base = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols' +foreach ($proto in 'TLS 1.0','TLS 1.1') { + foreach ($role in 'Client','Server') { + $k = "$base\$proto\$role" + try { + if (-not (Test-Path $k)) { New-Item -Path $k -Force | Out-Null } + New-ItemProperty -Path $k -Name 'Enabled' -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $k -Name 'DisabledByDefault' -PropertyType DWord -Value 1 -Force | Out-Null + Status $true "Disabled $proto $role" + } catch { + Status $false "Disable $proto $role - $_" + } + } +} +foreach ($role in 'Client','Server') { + $k = "$base\TLS 1.2\$role" + try { + if (-not (Test-Path $k)) { New-Item -Path $k -Force | Out-Null } + New-ItemProperty -Path $k -Name 'Enabled' -PropertyType DWord -Value 1 -Force | Out-Null + New-ItemProperty -Path $k -Name 'DisabledByDefault' -PropertyType DWord -Value 0 -Force | Out-Null + Status $true "Enabled TLS 1.2 $role" + } catch { + Status $false "Enable TLS 1.2 $role - $_" + } +} + +# Snapshot post-state for audit +reg export "HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" "$backupDir\schannel-protocols-post.reg" /y 2>&1 | Out-Null + +# ---------------------------------------------------------------------------- +Section '3. Install Windows Server Backup feature - no reboot' +# ---------------------------------------------------------------------------- +try { + $feature = Get-WindowsFeature -Name Windows-Server-Backup + if ($feature.InstallState -eq 'Installed') { + Status $true 'Windows-Server-Backup already installed' + } else { + $result = Install-WindowsFeature -Name Windows-Server-Backup -IncludeManagementTools + if ($result.Success) { + Status $true "Installed Windows-Server-Backup. RestartNeeded: $($result.RestartNeeded)" + } else { + Status $false "Install-WindowsFeature returned Success=False" + } + } +} catch { + Status $false "WSB install: $_" +} + +# ---------------------------------------------------------------------------- +Section "4. Schedule reboot for $TargetRebootHour`:00 local" +# ---------------------------------------------------------------------------- +$now = Get-Date +$target = $now.Date.AddHours($TargetRebootHour) +if ($target -lt $now) { $target = $target.AddDays(1) } +$seconds = [int]($target - $now).TotalSeconds + +Write-Output "Current time: $now" +Write-Output "Target reboot: $target" +Write-Output "Delay: $seconds seconds ($([math]::Round($seconds/60,1)) minutes)" + +if ($seconds -lt 60) { + Status $false "Target reboot is less than 1 minute away - not scheduling. Run again closer to window." +} elseif ($seconds -gt 86400) { + Status $false "Target reboot more than 24 hours away - $seconds seconds. Rejecting." +} else { + # /r restart, /t timeout, /d p:4:2 = Planned / Application: Maintenance + # /c comment (<512 chars) shows in user popup + event log + # No /f - we want graceful shutdown of services (AD, Hyper-V, QB VSS) + $comment = 'Entra Connect preflight: TLS 1.2 + time sync enforcement. Cancel: shutdown /a' + shutdown /r /t $seconds /d p:4:2 /c $comment + if ($LASTEXITCODE -eq 0) { + Status $true "Reboot scheduled for $target (in $seconds sec). Cancel with: shutdown /a" + } else { + Status $false "shutdown command returned exit $LASTEXITCODE" + } +} + +# ---------------------------------------------------------------------------- +Section '5. Summary' +# ---------------------------------------------------------------------------- +Write-Output "Backup/rollback dir: $backupDir" +Write-Output "Reboot scheduled: $target" +Write-Output 'Cancel reboot: shutdown /a' +Write-Output '' +Write-Output 'Post-reboot verification:' +Write-Output ' 1. w32tm /query /status - confirm ReferenceId is no longer LOCL' +Write-Output ' 2. nltest /dsgetdc:cascades.local - confirm DC is responding' +Write-Output ' 3. Re-run entra-connect-readiness.ps1 for full pass/fail sweep' +Write-Output '' +Write-Output "Completed at $(Get-Date)" diff --git a/clients/cascades-tucson/docs/migration/scripts/entra-connect-readiness.ps1 b/clients/cascades-tucson/docs/migration/scripts/entra-connect-readiness.ps1 new file mode 100644 index 0000000..b099f12 --- /dev/null +++ b/clients/cascades-tucson/docs/migration/scripts/entra-connect-readiness.ps1 @@ -0,0 +1,288 @@ +# ============================================================================ +# Entra Connect Readiness Check - CS-SERVER +# ---------------------------------------------------------------------------- +# Read-only diagnostic. No state changes. No service restarts. No registry +# writes. Safe to run on a production DC at any time. Takes ~30-60 seconds. +# +# Output is structured text with section headers. Copy the full output back +# to Howard for analysis. +# +# Prepared: 2026-04-22 +# Target: CS-SERVER (cascades.local single DC) +# Prerequisite check for: Entra Connect install per user-account-rollout-plan +# ============================================================================ + +$ErrorActionPreference = 'Continue' +$sep = '=' * 76 + +function Write-Section($title) { + Write-Output '' + Write-Output $sep + Write-Output "== $title" + Write-Output $sep +} + +function Write-Check($label, $value, $status = '') { + $marker = switch ($status) { + 'PASS' { '[OK] ' } + 'WARN' { '[WARN] ' } + 'FAIL' { '[FAIL] ' } + default { ' ' } + } + Write-Output ("{0}{1,-40}: {2}" -f $marker, $label, $value) +} + +Write-Output "Entra Connect Readiness Check - $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz')" +Write-Output "Host: $env:COMPUTERNAME" + +# ---------------------------------------------------------------------------- +Write-Section '1. Operating System' +# ---------------------------------------------------------------------------- +$os = Get-CimInstance Win32_OperatingSystem +Write-Check 'OS Caption' $os.Caption +Write-Check 'OS Version' $os.Version +Write-Check 'OS Build' $os.BuildNumber +Write-Check 'Architecture' $os.OSArchitecture +Write-Check 'Install Date' ($os.InstallDate) +Write-Check 'Last Boot' ($os.LastBootUpTime) +Write-Check 'Uptime (days)' ([math]::Round(((Get-Date) - $os.LastBootUpTime).TotalDays, 1)) +$osMajor = [int]($os.Version -split '\.')[0] +$osBuild = [int]$os.BuildNumber +$osStatus = if ($osBuild -ge 14393) { 'PASS' } else { 'FAIL' } +Write-Check 'Server 2016+ required' "$($os.Caption) -> $osStatus" $osStatus + +# ---------------------------------------------------------------------------- +Write-Section '2. .NET Framework version' +# ---------------------------------------------------------------------------- +# Release key lookup: https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed +$netKey = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' -ErrorAction SilentlyContinue +if ($netKey) { + $release = $netKey.Release + $netName = switch ($true) { + ($release -ge 533320) { '4.8.1' } + ($release -ge 528040) { '4.8' } + ($release -ge 461808) { '4.7.2' } + ($release -ge 461308) { '4.7.1' } + ($release -ge 460798) { '4.7' } + ($release -ge 394802) { '4.6.2' } + default { "Older (release=$release)" } + } + $netStatus = if ($release -ge 461808) { 'PASS' } else { 'FAIL' } + Write-Check '.NET Framework version' $netName + Write-Check '.NET release key' $release + Write-Check '.NET 4.7.2+ required' "$netName -> $netStatus" $netStatus +} else { + Write-Check '.NET Framework v4 Full' 'NOT INSTALLED' 'FAIL' +} + +# ---------------------------------------------------------------------------- +Write-Section '3. PowerShell' +# ---------------------------------------------------------------------------- +Write-Check 'PSVersion' $PSVersionTable.PSVersion +Write-Check 'PSEdition' $PSVersionTable.PSEdition +$psStatus = if ($PSVersionTable.PSVersion.Major -ge 5) { 'PASS' } else { 'FAIL' } +Write-Check 'PS 5.0+ required' "$($PSVersionTable.PSVersion) -> $psStatus" $psStatus + +# ---------------------------------------------------------------------------- +Write-Section '4. TLS 1.2 configuration' +# ---------------------------------------------------------------------------- +# Entra Connect requires TLS 1.2 enforced for outbound sync +$net4 = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319' -Name SchUseStrongCrypto,SystemDefaultTlsVersions -ErrorAction SilentlyContinue +$net4w = Get-ItemProperty 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319' -Name SchUseStrongCrypto,SystemDefaultTlsVersions -ErrorAction SilentlyContinue +Write-Check '.NET SchUseStrongCrypto (64-bit)' $net4.SchUseStrongCrypto +Write-Check '.NET SchUseStrongCrypto (32-bit)' $net4w.SchUseStrongCrypto +Write-Check '.NET SystemDefaultTlsVersions (64)' $net4.SystemDefaultTlsVersions +Write-Check '.NET SystemDefaultTlsVersions (32)' $net4w.SystemDefaultTlsVersions +foreach ($role in 'Client','Server') { + foreach ($proto in 'TLS 1.0','TLS 1.1','TLS 1.2') { + $k = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$proto\$role" + $v = Get-ItemProperty $k -ErrorAction SilentlyContinue + $enabled = if ($v) { "Enabled=$($v.Enabled) DisabledByDefault=$($v.DisabledByDefault)" } else { 'unset (OS default)' } + Write-Check "SCHANNEL $proto $role" $enabled + } +} +Write-Output '(Entra Connect requires TLS 1.2 client enabled; TLS 1.0/1.1 should be disabled per HIPAA best practice.)' + +# ---------------------------------------------------------------------------- +Write-Section '5. Disk space' +# ---------------------------------------------------------------------------- +Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object { + $free = [math]::Round($_.FreeSpace / 1GB, 1) + $total = [math]::Round($_.Size / 1GB, 1) + $pct = if ($_.Size) { [math]::Round(100 * $_.FreeSpace / $_.Size, 1) } else { 0 } + Write-Check "Drive $($_.DeviceID)" "$free GB free of $total GB ($pct% free)" +} +Write-Output '(Entra Connect needs ~5-20 GB free on install drive, typically C:.)' + +# ---------------------------------------------------------------------------- +Write-Section '6. AD Domain + FSMO roles' +# ---------------------------------------------------------------------------- +try { + Import-Module ActiveDirectory -ErrorAction Stop + $dom = Get-ADDomain + $for = Get-ADForest + Write-Check 'Domain' $dom.DNSRoot + Write-Check 'NetBIOS name' $dom.NetBIOSName + Write-Check 'Forest mode' $for.ForestMode + Write-Check 'Domain mode' $dom.DomainMode + Write-Check 'Schema master' $for.SchemaMaster + Write-Check 'Domain naming master' $for.DomainNamingMaster + Write-Check 'PDC emulator' $dom.PDCEmulator + Write-Check 'RID master' $dom.RIDMaster + Write-Check 'Infrastructure master' $dom.InfrastructureMaster + $userCount = (Get-ADUser -Filter * -ResultSetSize $null | Measure-Object).Count + $groupCount = (Get-ADGroup -Filter * -ResultSetSize $null | Measure-Object).Count + $ouCount = (Get-ADOrganizationalUnit -Filter * | Measure-Object).Count + Write-Check 'AD user count' $userCount + Write-Check 'AD group count' $groupCount + Write-Check 'AD OU count' $ouCount +} catch { + Write-Check 'AD module' "FAIL: $_" 'FAIL' +} + +# ---------------------------------------------------------------------------- +Write-Section '7. AD Schema version' +# ---------------------------------------------------------------------------- +try { + $schema = Get-ADObject (Get-ADRootDSE).schemaNamingContext -Property objectVersion + Write-Check 'Schema objectVersion' $schema.objectVersion + $schemaName = switch ($schema.objectVersion) { + 88 { 'Windows Server 2019' } + 87 { 'Windows Server 2016' } + 69 { 'Windows Server 2012 R2' } + 56 { 'Windows Server 2012' } + 47 { 'Windows Server 2008 R2' } + default { "Unknown ($($schema.objectVersion))" } + } + Write-Check 'Schema version (mapped)' $schemaName +} catch { + Write-Check 'AD Schema' "FAIL: $_" 'FAIL' +} + +# ---------------------------------------------------------------------------- +Write-Section '8. Time sync' +# ---------------------------------------------------------------------------- +Write-Output '(Entra Connect requires clock within ~5 min of Microsoft time.)' +$w32status = w32tm /query /status 2>&1 +$w32status | Out-String | Write-Output +$w32peers = w32tm /query /peers 2>&1 +$w32peers | Out-String | Write-Output + +# ---------------------------------------------------------------------------- +Write-Section '9. Internet connectivity to Microsoft sync endpoints' +# ---------------------------------------------------------------------------- +$endpoints = @( + 'login.microsoftonline.com', + 'login.windows.net', + 'secure.aadcdn.microsoftonline-p.com', + 'management.azure.com', + 'graph.windows.net', + 'adminwebservice.microsoftonline.com', + 'provisioningapi.microsoftonline.com' +) +foreach ($e in $endpoints) { + $r = Test-NetConnection -ComputerName $e -Port 443 -InformationLevel Quiet -WarningAction SilentlyContinue + $status = if ($r) { 'PASS' } else { 'FAIL' } + Write-Check "HTTPS 443 -> $e" $r $status +} + +# ---------------------------------------------------------------------------- +Write-Section '10. WinHTTP proxy' +# ---------------------------------------------------------------------------- +netsh winhttp show proxy | Out-String | Write-Output + +# ---------------------------------------------------------------------------- +Write-Section '11. Existing Entra Connect / AAD Sync installations' +# ---------------------------------------------------------------------------- +$svcs = Get-Service -Name 'ADSync','MIISERVER','Microsoft Azure AD Sync' -ErrorAction SilentlyContinue +if ($svcs) { + $svcs | ForEach-Object { Write-Check "Existing service $($_.Name)" "$($_.Status) - CONFLICT" 'WARN' } +} else { + Write-Check 'Entra Connect / AAD Sync service' 'Not found (expected)' 'PASS' +} +$aadApps = Get-CimInstance Win32_Product -Filter "Name LIKE '%Azure AD%' OR Name LIKE '%Entra%' OR Name LIKE '%AADSync%'" -ErrorAction SilentlyContinue | + Select-Object Name, Version, InstallDate +if ($aadApps) { + $aadApps | Format-Table -AutoSize | Out-String | Write-Output +} else { + Write-Check 'Azure/Entra installed products' 'none' 'PASS' +} + +# ---------------------------------------------------------------------------- +Write-Section '12. SQL services (LocalDB conflict check)' +# ---------------------------------------------------------------------------- +# Entra Connect installs SQL Server 2019 LocalDB by default. Existing SQL +# instances are not a conflict (different service name), but worth noting. +$sql = Get-Service -Name 'MSSQL*' -ErrorAction SilentlyContinue +if ($sql) { + $sql | ForEach-Object { Write-Check "$($_.Name)" "$($_.Status) ($($_.DisplayName))" } +} else { + Write-Check 'Existing SQL services' 'none' +} + +# ---------------------------------------------------------------------------- +Write-Section '13. Key services running (potential conflicts / heavy load)' +# ---------------------------------------------------------------------------- +$watch = 'NTDS','DNS','DHCPServer','W3SVC','vmms','Spooler','SynoDriveClient','QBIDPService','QuickBooksDB34','DattoAV','ScreenConnect','SyncroDeviceAgent','Splashtop Streamer' +Get-Service -Name $watch -ErrorAction SilentlyContinue | Sort-Object Name | ForEach-Object { + Write-Check "Service $($_.Name)" "$($_.Status) - $($_.DisplayName)" +} + +# ---------------------------------------------------------------------------- +Write-Section '14. Memory + CPU pressure (current)' +# ---------------------------------------------------------------------------- +$mem = Get-CimInstance Win32_OperatingSystem +$memTotal = [math]::Round($mem.TotalVisibleMemorySize / 1MB, 1) +$memFree = [math]::Round($mem.FreePhysicalMemory / 1MB, 1) +$memUsed = [math]::Round($memTotal - $memFree, 1) +$memPct = [math]::Round(100 * $memUsed / $memTotal, 0) +Write-Check 'RAM total (GB)' $memTotal +Write-Check 'RAM in use (GB)' "$memUsed ($memPct%)" +Write-Check 'RAM free (GB)' $memFree +$cpu = Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average +Write-Check 'CPU load (avg %)' ([math]::Round($cpu.Average,1)) + +# ---------------------------------------------------------------------------- +Write-Section '15. Event log health (last 24h)' +# ---------------------------------------------------------------------------- +$since = (Get-Date).AddHours(-24) +foreach ($log in 'System','Application') { + $ev = Get-WinEvent -FilterHashtable @{LogName=$log; Level=1,2; StartTime=$since} -ErrorAction SilentlyContinue + $crit = ($ev | Where-Object Level -eq 1 | Measure-Object).Count + $err = ($ev | Where-Object Level -eq 2 | Measure-Object).Count + Write-Check "$log log errors/critical" "$err errors, $crit critical" + if ($ev) { + $ev | Group-Object ProviderName | + Sort-Object Count -Descending | + Select-Object -First 5 Count, Name | + Format-Table -AutoSize | Out-String | Write-Output + } +} + +# ---------------------------------------------------------------------------- +Write-Section '16. DC health (dcdiag subset)' +# ---------------------------------------------------------------------------- +# Focused tests only - full dcdiag is ~2 minutes. Skip if too slow. +Write-Output '--- dcdiag /test:connectivity,fsmocheck,services,advertising /v (trimmed) ---' +$dc = dcdiag /test:connectivity /test:fsmocheck /test:services /test:advertising 2>&1 +$dc | Where-Object { $_ -match 'Starting test|passed test|failed test|warning|error' } | Out-String | Write-Output + +# ---------------------------------------------------------------------------- +Write-Section '17. Windows Features (Server Backup etc.)' +# ---------------------------------------------------------------------------- +$features = Get-WindowsFeature -Name 'Windows-Server-Backup','ADDS-AdminCenter','RSAT-AD-PowerShell','RSAT-AD-Tools' -ErrorAction SilentlyContinue +$features | Format-Table Name, InstallState -AutoSize | Out-String | Write-Output + +# ---------------------------------------------------------------------------- +Write-Section '18. Certificate expirations (local cert store, expires < 90d)' +# ---------------------------------------------------------------------------- +Get-ChildItem Cert:\LocalMachine\My, Cert:\LocalMachine\Root -ErrorAction SilentlyContinue | + Where-Object { $_.NotAfter -lt (Get-Date).AddDays(90) -or $_.NotAfter -lt (Get-Date) } | + Sort-Object NotAfter | + Select-Object Subject, NotAfter, Thumbprint | + Format-Table -AutoSize -Wrap | Out-String | Write-Output + +# ---------------------------------------------------------------------------- +Write-Section 'Done' +# ---------------------------------------------------------------------------- +Write-Output "Completed at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz')" diff --git a/clients/cascades-tucson/docs/security/hipaa-review-2026-04-22.md b/clients/cascades-tucson/docs/security/hipaa-review-2026-04-22.md new file mode 100644 index 0000000..1c9b8c6 --- /dev/null +++ b/clients/cascades-tucson/docs/security/hipaa-review-2026-04-22.md @@ -0,0 +1,169 @@ +# HIPAA Compliance Review — 2026-04-22 User Account Rollout + +**Reviewed by:** Howard Enos (Computer Guru) +**Scope:** Decisions captured in `docs/cloud/user-account-rollout-plan.md` as of 2026-04-22 +**Trigger:** Client request for a pre-execution compliance check before creating / disabling accounts +**Primary references:** 45 CFR Part 164 Subpart C (HIPAA Security Rule), NIST SP 800-66 Rev 2 (Feb 2024), HHS OCR guidance + +--- + +## Findings classified CRITICAL — must fix before rollout + +### C1. Shared agency logins would violate §164.312(a)(2)(i) — Unique User Identification + +Original plan: create `reliable1@cascadestucson.com` and `reliable2@cascadestucson.com` as shared accounts for rotating Reliable Agency caregivers. + +**Rule:** §164.312(a)(2)(i) Unique User Identification is a **Required** implementation spec (not Addressable). HHS has explicitly answered this in public FAQ: covered entities may not assign the same log-on ID to multiple employees. There is no compensating-control carve-out because Required specs don't permit alternatives. NIST SP 800-66 Rev 2 maps this to SP 800-53 IA-2 (Identification and Authentication) and AC-2 (Account Management), which likewise require individual accounts. + +**Decision 2026-04-22:** Drop `reliable1` / `reliable2`. Require Reliable Agency to supply individual caregiver names before any shift where PHI access is needed. Per-person accounts only. If the agency won't commit, agency staff work under direct supervision of a Cascades-employed caregiver who is signed in — no independent PHI access. + +**Docs updated:** `user-account-rollout-plan.md` §6 and Wave 1; `cascades-staff-working-list-2026-04-22.md`; `cascades-staff-editor-2026-04-22.html`; `p2-staff-candidates.md`; `caregiver-m365-p2-rollout.md`; `cascades-staff-followup-2026-04-22.md`. + +--- + +### C2. Britney Thompson mailbox must be placed on Litigation Hold before disable + mailbox conversion + +**Rule:** §164.308(a)(3)(ii)(C) Termination Procedures + §164.316(b)(2)(i) 6-year documentation retention. + +**Issue:** Business Standard doesn't include unlimited archive/hold. Converting a licensed mailbox to shared can trim content based on default retention settings, potentially purging PHI subject to state medical-records retention (AZ = 7 years post-last-encounter) or subpoena. + +**Decision:** Before disabling `britney.thompson`: +1. Place mailbox on Litigation Hold (verify Business Standard has Exchange Online Plan 2 features; if not, temporarily assign an EOA or E3 before harvest) +2. Designate a named custodian (recommended: Meredith Kuhn as Executive Director, or Lois Lane as Health Services Director) +3. Then disable sign-in, revoke tokens +4. Then convert to shared and harvest user license + +Documentation of the termination action retained ≥6 years per §164.316(b)(2). + +--- + +### C3. Microsoft M365 BAA not yet signed + +**Rule:** §164.308(b)(1) Business Associate contracts. + +**Issue:** `docs/cloud/m365.md` line 12 and `docs/security/hipaa.md` gap #13 note that no Microsoft HIPAA BAA has been signed. Every day Cascades uses M365 for PHI without a BAA is a continuing Security Rule violation. Every new account we provision expands that exposure. + +**Decision:** Sign the Microsoft BAA **before Wave 1** — M365 Admin Center → Settings → Org Settings → Security & Privacy → HIPAA BAA. Free, 5 minutes. + +Parallel: verify or secure an ALIS BAA (go-alis.com) before any new caregiver accesses ALIS. + +--- + +### C4. No formal Risk Analysis on file (§164.308(a)(1)(ii)(A) — Required) + +**Rule:** A formal risk analysis covering scope, threats, likelihood, impact, and control effectiveness is Required (not Addressable). + +**Issue:** Cross-doc sweep confirmed no standalone risk analysis document exists. The existing `hipaa.md` gap list is a useful inventory but does not meet the Security Rule's definition. + +**Decision:** Produce `docs/security/risk-analysis-2026-04.md` following the NIST 800-66 Rev 2 §3 framework before Wave 2. Reference it in every Addressable-spec decision. + +--- + +## Findings classified HIGH — fix in Wave 1 or before + +### H1. M365 audit log retention default (1 year) is insufficient + +**Rule:** §164.312(b) Audit Controls + §164.316(b)(2) 6-year documentation retention. OCR enforcement posture treats audit logs as documentation subject to the 6-year clock. + +**Decision:** Purchase Microsoft Purview Audit (Premium) add-on (10-year retention) OR configure a retention policy for 7 years via E5 Compliance OR monthly export to immutable Azure Blob. Decision documented in Security Rule Implementation Register (see M2 below). + +--- + +### H2. No documented break-glass emergency access account (§164.312(a)(2)(ii) — Required) + +**Decision:** Create `breakglass@cascadestucson.com` — cloud-only (not AD-synced), excluded from all CA policies, protected by FIDO2 security key + unique vaulted password in `clients/cascades-tucson/breakglass.sops.yaml`, sign-in alerted to Howard + Meredith, quarterly test sign-in. Must exist before disabling any other admin accounts. + +--- + +### H3. `\\CS-SERVER\homes` SMB3 encryption not enabled; folder redirection routes PHI to that share + +**Rule:** §164.312(a)(2)(iv) Encryption/Decryption + §164.312(e)(2)(ii) Transmission Encryption (both Addressable). + +**Issue:** `CONTEXT.md` notes `EncryptData=false` on the homes share. Folder redirection GPO pushes Documents / Desktop / Downloads — including staff-generated PHI — to that share. In-transit encryption is off; at-rest encryption status on CS-SERVER's D: drive is not documented. + +**Decision:** Before Alma / Kyla folder redirection goes live: +- `Set-SmbShare -Name homes -EncryptData $true` (immediate, free) +- Verify / enable BitLocker on CS-SERVER D: drive +- Document both decisions in Implementation Register + +--- + +### H4. Drivers need Privacy Rule training + signed sanctions acknowledgment (workforce, not IT) + +**Rule:** §164.530(b)(1) Privacy training for workforce; §164.530(e) sanctions apply to all workforce; §160.103 defines workforce inclusive of workers with no electronic system access. + +**Issue:** Decision that drivers don't need IT access is correct; however, drivers encounter PHI on pickup sheets (rider names, appointment context). + +**Decision (not an IT deliverable):** Flag to Meredith. Drivers need annual short-form Privacy training, signed confidentiality / sanctions acknowledgment, and documented pickup-sheet handling procedures. If dispatch uses personal phones for texts with rider names, those phones now trigger mobile-device safeguards (§164.312(a)(1) + (e)) — consider moving dispatch to a controlled channel. + +--- + +## Findings classified MEDIUM — address before Wave 3 (caregiver bulk) + +### M1. Automatic-logoff duration not codified for shared front-desk PCs and MSDM sign-out + +**Rule:** §164.312(a)(2)(iii) Automatic Logoff (Addressable). + +**Decision:** +- GPO `CSC - Shared Workstation`: screen lock at 10 min idle, sign-out at 30 min idle, disable Fast User Switching +- MSDM global sign-out timer: 15 min idle +- Both documented in Implementation Register as the Addressable-spec implementation + +--- + +### M2. No Security Rule Implementation Register + +**Rule:** §164.306(d)(3) Addressable spec decisions; §164.316(b)(1)-(2) documentation retention. + +**Decision:** Create `docs/security/implementation-register.md` — one row per Addressable spec (encryption at rest, encryption in transit, automatic logoff, emergency access mode, integrity controls) with: decision, rationale tied to risk analysis, alternative measure if applicable, owner, next review date. This is the artifact OCR asks for in an audit. + +--- + +### M3. Reliable Agency — Business Associate status not determined + +**Decision:** Ask Meredith for the Reliable Agency staffing contract. Confirm direct-control language (workforce) vs. agency-directed (Business Associate). If no workforce-control language, either secure an addendum OR sign a BAA with Reliable. No individual agency-caregiver accounts created until this is sorted. + +--- + +### M4. Christine Nyanzunda's single-account dual-role access scoping + +**Rule:** §164.308(a)(4)(ii)(B) Access Authorization (Addressable — minimum necessary). + +**Decision:** Single account retained (MC Admin + part-time MedTech). Document in Implementation Register that operational simplicity was weighed against strict minimum-necessary. Mitigation: rely on ALIS's internal role-based access controls to scope her view based on shift / context if supported. + +--- + +## Findings classified GOOD — HIPAA-aligned decisions being kept + +- **Building-only CA default + allow-list for outside sign-in** — defensible implementation of §164.312(a)(1) Access Control, stronger than baseline +- **Shared front-desk PCs with individual M365 accounts** — fully compliant (identity is per-person; hardware sharing is fine) +- **MSDM shared phones with per-user Entra sign-in** — satisfies unique-ID + automatic-logoff on the mobile tier +- **Drivers with no electronic PHI access** — correct minimum-necessary scoping on the IT side +- **Same-day account disable on termination** — meets termination-procedure timing +- **Business Premium tenant-wide recommendation** — provides the P1 + Defender + DLP + Intune baseline the rest of the design relies on +- **Decline to reinstate Sandra Fish admin** — correct; 2026-04-14 revocation stands + +--- + +## Open questions unresolved at review time + +| # | Question | Owner | +|---|---|---| +| 1 | Does Business Standard (current SKU for 23 users) include Exchange Online Plan 2 features needed for Litigation Hold? If not, what's the cheapest path to EOA on Britney's mailbox before harvest? | Howard (verify in M365 Admin Center) | +| 2 | Reliable Agency staffing contract — direct-control language or not? | Meredith | +| 3 | Audit retention path chosen (Purview Premium add-on vs. E5 Compliance vs. export to immutable storage)? | Meredith (budget) + Howard (design) | +| 4 | BitLocker state on CS-SERVER D: drive — enabled, encrypted-no-protectors, or off? | Howard (verify onsite or via SSH) | + +--- + +## Source material cited + +- [45 CFR §164.312 — Technical safeguards (eCFR)](https://www.ecfr.gov/current/title-45/subtitle-A/subchapter-C/part-164/subpart-C/section-164.312) +- [45 CFR §164.316 — Policies, procedures, documentation (eCFR)](https://www.ecfr.gov/current/title-45/subtitle-A/subchapter-C/part-164/subpart-C/section-164.316) +- [45 CFR §164.308 — Administrative safeguards (eCFR)](https://www.ecfr.gov/current/title-45/subtitle-A/subchapter-C/part-164/subpart-C/section-164.308) +- [HHS FAQ — shared log-on IDs not permitted](https://www.hhs.gov/hipaa/for-professionals/faq/2018/does-the-security-rule-permit-a-covered-entity-to-assign-the-same-log-on-id-to-multiple-employees/index.html) +- [HHS FAQ — Addressable vs Required implementation specs](https://www.hhs.gov/hipaa/for-professionals/faq/2020/what-is-the-difference-between-addressable-and-required-implementation-specifications/index.html) +- [HHS — Business Associates guidance](https://www.hhs.gov/hipaa/for-professionals/privacy/guidance/business-associates/index.html) +- [NIST SP 800-66 Rev 2 — Implementing the HIPAA Security Rule (Feb 2024)](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-66r2.pdf) +- [Microsoft Learn — Entra HIPAA access control safeguards](https://learn.microsoft.com/en-us/entra/standards/hipaa-access-controls) +- [Microsoft Learn — Shared device mode overview](https://learn.microsoft.com/en-us/entra/identity-platform/msal-shared-devices) diff --git a/clients/cascades-tucson/reports/2026-04-22-cs-server-entra-preflight-result.md b/clients/cascades-tucson/reports/2026-04-22-cs-server-entra-preflight-result.md new file mode 100644 index 0000000..91e8fd2 --- /dev/null +++ b/clients/cascades-tucson/reports/2026-04-22-cs-server-entra-preflight-result.md @@ -0,0 +1,89 @@ +# CS-SERVER Entra Connect Pre-flight Remediation Result + +**Command ID:** 1bb38813-57ae-4321-ba81-e8dc7ea4a30d +**Run at:** 2026-04-23T00:37:14.365639Z +**Completed:** 2026-04-23T00:39:04.479126Z +**Exit code:** 0 + +## STDOUT + +``` + +======================================================================== +== 0. Pre-flight snapshot (rollback material) +======================================================================== +[OK] Backup dir: D:\Backups\pre-entra-connect-2026-04-22-1736 +[OK] Registry pre-state exported (.NET + Schannel Protocols) +[OK] w32tm pre-state captured +[OK] Event log snapshot saved (200 System events) + +To roll back TLS changes after reboot: +reg import D:\Backups\pre-entra-connect-2026-04-22-1736\dotnet-64.reg +reg import D:\Backups\pre-entra-connect-2026-04-22-1736\dotnet-32.reg +reg import D:\Backups\pre-entra-connect-2026-04-22-1736\schannel-protocols-pre.reg +Restart-Computer + +======================================================================== +== 1. Time sync fix (w32tm) - no reboot +======================================================================== +[OK] Configured w32tm peer list: time.windows.com,0x8 pool.ntp.org,0x8 time.nist.gov,0x8 +[OK] Restarted w32time service + Leap Indicator: 0(no warning) + Stratum: 4 (secondary reference - syncd by (S)NTP) + Precision: -23 (119.209ns per tick) + Root Delay: 0.0311588s + Root Dispersion: 61.0046385s + ReferenceId: 0x287706E4 (source IP: 40.119.6.228) + Last Successful Sync Time: 4/22/2026 5:36:28 PM + Source: time.windows.com,0x8 + Poll Interval: 6 (64s) + +[OK] ReferenceId: ReferenceId: 0x287706E4 (source IP: 40.119.6.228) (no longer LOCL) + +======================================================================== +== 2. TLS 1.2 enforcement (.NET + Schannel) - requires reboot +======================================================================== +[OK] .NET TLS keys set at HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 +[OK] .NET TLS keys set at HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319 +[OK] Disabled TLS 1.0 Client +[OK] Disabled TLS 1.0 Server +[OK] Disabled TLS 1.1 Client +[OK] Disabled TLS 1.1 Server +[OK] Enabled TLS 1.2 Client +[OK] Enabled TLS 1.2 Server + +======================================================================== +== 3. Install Windows Server Backup feature - no reboot +======================================================================== +WARNING: You must restart this server to finish the installation process. +[OK] Installed Windows-Server-Backup. RestartNeeded: Yes + +======================================================================== +== 4. Schedule reboot for 18:00 local +======================================================================== +Current time: 04/22/2026 17:38:59 +Target reboot: 04/22/2026 18:00:00 +Delay: 1261 seconds (21 minutes) +[OK] Reboot scheduled for 04/22/2026 18:00:00 (in 1261 sec). Cancel with: shutdown /a + +======================================================================== +== 5. Summary +======================================================================== +Backup/rollback dir: D:\Backups\pre-entra-connect-2026-04-22-1736 +Reboot scheduled: 04/22/2026 18:00:00 +Cancel reboot: shutdown /a + +Post-reboot verification: + 1. w32tm /query /status - confirm ReferenceId is no longer LOCL + 2. nltest /dsgetdc:cascades.local - confirm DC is responding + 3. Re-run entra-connect-readiness.ps1 for full pass/fail sweep + +Completed at 04/22/2026 17:38:59 + +``` + +## STDERR + +``` + +``` diff --git a/clients/cascades-tucson/reports/2026-04-22-cs-server-entra-readiness-verdict.md b/clients/cascades-tucson/reports/2026-04-22-cs-server-entra-readiness-verdict.md new file mode 100644 index 0000000..f23bb5a --- /dev/null +++ b/clients/cascades-tucson/reports/2026-04-22-cs-server-entra-readiness-verdict.md @@ -0,0 +1,122 @@ +# CS-SERVER Entra Connect Readiness — Verdict + +**Executed:** 2026-04-22 17:26 MST (via GuruRMM agent `6766e973-e703-47c1-be56-76950290f87c`) +**Exit code:** 0 +**Full output:** `reports/2026-04-22-cs-server-entra-readiness.md` +**Script source:** `docs/migration/scripts/entra-connect-readiness.ps1` + +## Overall verdict + +**READY to install Entra Connect, after addressing three small pre-install items.** No hard blockers. Hardware / OS / AD / network environment all meet requirements. + +## PASS (13 checks) + +| Check | Result | +|---|---| +| Operating system | Windows Server 2019 Standard, build 17763 (≥2016 required) | +| .NET Framework | 4.8 (release 528049, ≥4.7.2 required) | +| PowerShell | 5.1.17763.8510 (≥5.0 required) | +| Disk space | C: 149 GB free / D: 548 GB free | +| AD domain / forest mode | Windows2016Forest / Windows2016Domain | +| AD Schema version | 88 (Windows Server 2019) | +| FSMO roles | All 5 on CS-SERVER (expected for single DC) | +| AD size | 44 users, 55 groups, 18 OUs — small enough for fast sync | +| Internet to Microsoft | All 7 sync endpoints reach on HTTPS 443 | +| WinHTTP proxy | Direct access, no proxy config needed | +| Existing AAD/Entra Sync | None — clean install target | +| DC health (dcdiag) | Connectivity / Advertising / Services / FsmoCheck all pass | +| CPU / RAM headroom | 1% CPU, 27% of 48 GB RAM used | + +## Pre-install items to fix (in order) + +### 1. Time sync — HIGHEST priority + +Currently free-running on the local system clock. `w32tm /query /status` reports: + +- `Source: Free-running System Clock` +- `ReferenceId: 0x4C4F434C ("LOCL")` +- `Last Successful Sync Time: 4/21/2026 8:31:32 PM` (~21 hours ago at time of check) +- Peer state: `Pending` + +Cloud sync has a ±5-minute drift tolerance. A PDC emulator with no external NTP source will drift over days and Entra Connect will start failing intermittently. As the PDC, it's also supposed to be the authoritative time source for the domain — so every other machine is inheriting this drift. + +**Fix (no reboot needed):** + +```powershell +w32tm /config /manualpeerlist:"time.windows.com,0x8 pool.ntp.org,0x8 time.nist.gov,0x8" /syncfromflags:manual /reliable:yes /update +Restart-Service w32time +w32tm /resync /force +w32tm /query /status # verify Source is no longer "Free-running" +``` + +### 2. Backup before install — safety net + +Per the earlier audit, **Windows Server Backup feature is Available but not Installed** and there's no documented Synology ABB of CS-SERVER. Entra Connect install touches the AD schema (extends it with a couple of attributes) and creates a service account. If anything goes sideways, we need a rollback path. + +**Fix:** + +```powershell +Install-WindowsFeature Windows-Server-Backup +# One-shot full backup + system state to Synology SMB share +wbadmin start backup -backupTarget:\\CASCADESDS\Backups\CS-SERVER -include:C:,D: -allCritical -vssFull -quiet +``` + +(Or use existing Synology ABB if configured — confirm it covers CS-SERVER before install.) + +### 3. TLS 1.2 explicit enforcement — HIPAA + defense in depth + +Server 2019 defaults to TLS 1.2 enabled, so Entra Connect will work today. But the Schannel registry entries are "unset (OS default)" and `.NET SchUseStrongCrypto` is set on 64-bit but missing on 32-bit. Best practice (and cleaner audit story) is to explicitly enable TLS 1.2 and disable 1.0/1.1. + +**Fix (REQUIRES REBOOT for Schannel):** + +```powershell +# .NET side (takes effect immediately for new processes) +$paths = @( + 'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319', + 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319' +) +foreach ($p in $paths) { + New-Item -Path $p -Force | Out-Null + Set-ItemProperty -Path $p -Name SchUseStrongCrypto -Type DWord -Value 1 + Set-ItemProperty -Path $p -Name SystemDefaultTlsVersions -Type DWord -Value 1 +} + +# Schannel side (requires reboot) +$base = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols' +foreach ($proto in 'TLS 1.0','TLS 1.1') { + foreach ($role in 'Client','Server') { + $k = "$base\$proto\$role" + New-Item -Path $k -Force | Out-Null + Set-ItemProperty -Path $k -Name Enabled -Type DWord -Value 0 + Set-ItemProperty -Path $k -Name DisabledByDefault -Type DWord -Value 1 + } +} +foreach ($role in 'Client','Server') { + $k = "$base\TLS 1.2\$role" + New-Item -Path $k -Force | Out-Null + Set-ItemProperty -Path $k -Name Enabled -Type DWord -Value 1 + Set-ItemProperty -Path $k -Name DisabledByDefault -Type DWord -Value 0 +} +# Then: Restart-Computer +``` + +Schedule this for a maintenance window since it requires a reboot of the only DC. + +## Observations (not blockers) + +- **Windows Internal Database (`MSSQL$MICROSOFT##WID`) running** — likely AD Certificate Services or a legacy role. No conflict with Entra Connect's SQL Server LocalDB. Check if still needed. +- **QBVSS (QuickBooks VSS) running** — QuickBooks on a DC is already known issue #17 per `hipaa.md`. Not blocking. Keep on long-term cleanup list. +- **Event log: 3 System errors + 4 Application errors last 24h** — Firefox browser agent, TPM-WMI (benign on non-TPM hardware), DistributedCOM, .NET Runtime, Security-SPP (licensing). None critical. Not blocking. +- **Expired self-signed cert `CN=CS-SERVER.cascades.local`** — known issue #19 (hipaa.md), unrelated to Entra Connect (which uses its own cert for the sync service account). + +## Recommended pre-install sequence + +1. Run the time-sync fix immediately — no downtime, fixes drift right away +2. Install Windows Server Backup, run a full backup to Synology share (~30 min depending on D: size) +3. Schedule TLS reboot window (tell Meredith — brief disruption) +4. After reboot, re-verify with the readiness script (same command, same agent) +5. Proceed with Wave 0.5 Entra Connect install + +## Hardware note (not changed by this check) + +CS-SERVER is still the 2009-era Dell R610 with consumer SATA drives carrying C: (the OS drive Entra Connect installs on). This check confirms it's *ready* for Entra Connect — it does not change the underlying "extreme failure risk" status noted in the issue tracker. Entra Connect adds one more critical dependency on aging hardware. A second DC on modern hardware is still the right long-term fix, independent of this rollout. diff --git a/clients/cascades-tucson/reports/2026-04-22-cs-server-entra-readiness.md b/clients/cascades-tucson/reports/2026-04-22-cs-server-entra-readiness.md new file mode 100644 index 0000000..4d713b4 --- /dev/null +++ b/clients/cascades-tucson/reports/2026-04-22-cs-server-entra-readiness.md @@ -0,0 +1,246 @@ +# CS-SERVER Entra Connect Readiness Check Result + +**Run at:** 2026-04-23T00:27:11.103711Z +**Completed:** 2026-04-23T00:27:31.663891Z +**Exit code:** 0 +**Command ID:** 83d558be-2a76-416a-b135-1551060ae661 + +--- + +## STDOUT + +``` +Entra Connect Readiness Check - 2026-04-22 17:26:18 -07:00 +Host: CS-SERVER + +============================================================================ +== 1. Operating System +============================================================================ + OS Caption : Microsoft Windows Server 2019 Standard + OS Version : 10.0.17763 + OS Build : 17763 + Architecture : 64-bit + Install Date : 8/4/2024 6:39:38 PM + Last Boot : 4/14/2026 8:29:03 PM + Uptime (days) : 7.9 +[OK] Server 2016+ required : Microsoft Windows Server 2019 Standard -> PASS + +============================================================================ +== 2. .NET Framework version +============================================================================ + .NET Framework version : System.Object[] + .NET release key : 528049 +[OK] .NET 4.7.2+ required : 4.8 4.7.2 4.7.1 4.7 4.6.2 -> PASS + +============================================================================ +== 3. PowerShell +============================================================================ + PSVersion : 5.1.17763.8510 + PSEdition : Desktop +[OK] PS 5.0+ required : 5.1.17763.8510 -> PASS + +============================================================================ +== 4. TLS 1.2 configuration +============================================================================ + .NET SchUseStrongCrypto (64-bit) : 1 + .NET SchUseStrongCrypto (32-bit) : + .NET SystemDefaultTlsVersions (64) : + .NET SystemDefaultTlsVersions (32) : + SCHANNEL TLS 1.0 Client : unset (OS default) + SCHANNEL TLS 1.1 Client : unset (OS default) + SCHANNEL TLS 1.2 Client : unset (OS default) + SCHANNEL TLS 1.0 Server : unset (OS default) + SCHANNEL TLS 1.1 Server : unset (OS default) + SCHANNEL TLS 1.2 Server : unset (OS default) +(Entra Connect requires TLS 1.2 client enabled; TLS 1.0/1.1 should be disabled per HIPAA best practice.) + +============================================================================ +== 5. Disk space +============================================================================ + Drive C: : 149.4 GB free of 296.9 GB (50.3% free) + Drive D: : 548.5 GB free of 1117.2 GB (49.1% free) +(Entra Connect needs ~5-20 GB free on install drive, typically C:.) + +============================================================================ +== 6. AD Domain + FSMO roles +============================================================================ + Domain : cascades.local + NetBIOS name : CASCADES + Forest mode : Windows2016Forest + Domain mode : Windows2016Domain + Schema master : CS-SERVER.cascades.local + Domain naming master : CS-SERVER.cascades.local + PDC emulator : CS-SERVER.cascades.local + RID master : CS-SERVER.cascades.local + Infrastructure master : CS-SERVER.cascades.local + AD user count : 44 + AD group count : 55 + AD OU count : 18 + +============================================================================ +== 7. AD Schema version +============================================================================ + Schema objectVersion : 88 + Schema version (mapped) : Windows Server 2019 + +============================================================================ +== 8. Time sync +============================================================================ +(Entra Connect requires clock within ~5 min of Microsoft time.) +Leap Indicator: 0(no warning) +Stratum: 1 (primary reference - syncd by radio clock) +Precision: -23 (119.209ns per tick) +Root Delay: 0.0000000s +Root Dispersion: 10.0000000s +ReferenceId: 0x4C4F434C (source name: "LOCL") +Last Successful Sync Time: 4/21/2026 8:31:32 PM +Source: Free-running System Clock +Poll Interval: 6 (64s) + + +#Peers: 1 + +Peer: +State: Pending +Time Remaining: 10209.9342707s +Mode: 0 (reserved) +Stratum: 0 (unspecified) +PeerPoll Interval: 0 (unspecified) +HostPoll Interval: 0 (unspecified) + + +============================================================================ +== 9. Internet connectivity to Microsoft sync endpoints +============================================================================ +[OK] HTTPS 443 -> login.microsoftonline.com : True +[OK] HTTPS 443 -> login.windows.net : True +[OK] HTTPS 443 -> secure.aadcdn.microsoftonline-p.com: True +[OK] HTTPS 443 -> management.azure.com : True +[OK] HTTPS 443 -> graph.windows.net : True +[OK] HTTPS 443 -> adminwebservice.microsoftonline.com: True +[OK] HTTPS 443 -> provisioningapi.microsoftonline.com: True + +============================================================================ +== 10. WinHTTP proxy +============================================================================ + +Current WinHTTP proxy settings: + + Direct access (no proxy server). + + + +============================================================================ +== 11. Existing Entra Connect / AAD Sync installations +============================================================================ +[OK] Entra Connect / AAD Sync service : Not found (expected) +[OK] Azure/Entra installed products : none + +============================================================================ +== 12. SQL services (LocalDB conflict check) +============================================================================ + MSSQL$MICROSOFT##WID : Running (Windows Internal Database) + +============================================================================ +== 13. Key services running (potential conflicts / heavy load) +============================================================================ + Service DHCPServer : Running - DHCP Server + Service DNS : Running - DNS Server + Service NTDS : Running - Active Directory Domain Services + Service QBVSS : Running - QBIDPService + Service QuickBooksDB34 : Stopped - QuickBooksDB34 + Service Spooler : Running - Print Spooler + Service vmms : Running - Hyper-V Virtual Machine Management + Service W3SVC : Running - World Wide Web Publishing Service + +============================================================================ +== 14. Memory + CPU pressure (current) +============================================================================ + RAM total (GB) : 47.9 + RAM in use (GB) : 12.8 (27%) + RAM free (GB) : 35.1 + CPU load (avg %) : 1 + +============================================================================ +== 15. Event log health (last 24h) +============================================================================ + System log errors/critical : 3 errors, 0 critical + +Count Name +----- ---- + 2 Microsoft-Windows-TPM-WMI + 1 Microsoft-Windows-DistributedCOM + + + + Application log errors/critical : 4 errors, 0 critical + +Count Name +----- ---- + 2 .NET Runtime + 1 Firefox Default Browser Agent + 1 Microsoft-Windows-Security-SPP + + + + +============================================================================ +== 16. DC health (dcdiag subset) +============================================================================ +--- dcdiag /test:connectivity,fsmocheck,services,advertising /v (trimmed) --- + Starting test: Connectivity + ......................... CS-SERVER passed test Connectivity + Starting test: Advertising + ......................... CS-SERVER passed test Advertising + Starting test: Services + ......................... CS-SERVER passed test Services + Starting test: FsmoCheck + ......................... cascades.local passed test FsmoCheck + + +============================================================================ +== 17. Windows Features (Server Backup etc.) +============================================================================ + +Name InstallState +---- ------------ +RSAT-AD-Tools Installed +RSAT-AD-PowerShell Installed +Windows-Server-Backup Available + + + + +============================================================================ +== 18. Certificate expirations (local cert store, expires < 90d) +============================================================================ + +Subject +------- +OU=Copyright (c) 1997 Microsoft Corp., OU=Microsoft Time Stamping Service Root, OU=Microsoft Corporation, O=Microsoft +Trust Network +CN=Microsoft Authenticode(tm) Root Authority, O=MSFT, C=US +OU="NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc.", OU=VeriSign Time Stamping Service Root, OU="VeriSign, Inc.", +O=VeriSign Trust Network +CN=GTE CyberTrust Global Root, OU="GTE CyberTrust Solutions, Inc.", O=GTE Corporation, C=US +CN=UTN-USERFirst-Object, OU=http://www.usertrust.com, O=The USERTRUST Network, L=Salt Lake City, S=UT, C=US +CN=Microsoft Root Authority, OU=Microsoft Corporation, OU=Copyright (c) 1997 Microsoft Corp. +CN=Thawte Timestamping CA, OU=Thawte Certification, O=Thawte, L=Durbanville, S=Western Cape, C=ZA +CN=Microsoft Root Certificate Authority, DC=microsoft, DC=com +CN=CS-SERVER.cascades.local + + + + +============================================================================ +== Done +============================================================================ +Completed at 2026-04-22 17:26:38 -07:00 + +``` + +## STDERR + +``` + +``` diff --git a/clients/cascades-tucson/scripts/build-open-questions-docx.py b/clients/cascades-tucson/scripts/build-open-questions-docx.py index 377eafb..1d5fc16 100644 --- a/clients/cascades-tucson/scripts/build-open-questions-docx.py +++ b/clients/cascades-tucson/scripts/build-open-questions-docx.py @@ -17,9 +17,13 @@ INTRO = ( "Thank you for getting back to me on the staff list — almost everything is squared " "away now. Britney and Polett have been removed from the roster (no longer employees), " "Alma's title and access are set (Memory Care Life Enrichment, D+P, ALIS, offsite), " - "and the two Reliable Agency shared logins will use the short names reliable1 and " - "reliable2 as you requested. Drivers will stay on the roster for tracking but no " - "longer get Cascades IT accounts. There is one small item still outstanding — see below." + "and drivers will stay on the roster for tracking but no longer get Cascades IT accounts. " + "On the two Reliable Agency caregivers: after a HIPAA compliance review, we cannot use " + "shared log-ins for PHI access (it's a federal rule, §164.312(a)(2)(i)). Reliable will " + "need to provide individual caregiver names before those caregivers can have their own " + "Cascades account — otherwise they will need to work under the direct supervision of a " + "Cascades-employed caregiver who is signed in. There is one small item still outstanding " + "from the staff list itself — see below." ) QUESTIONS = [