sync: auto-sync from HOWARD-HOME at 2026-05-20 17:08:25

Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-05-20 17:08:25
This commit is contained in:
2026-05-20 17:08:26 -07:00
parent 6c476066ee
commit bc984d9c78
15 changed files with 638 additions and 0 deletions

View File

@@ -52,6 +52,7 @@
- [Mac gururmm setup pending](project_mac_gururmm_setup_pending.md) — ACTION REQUIRED: run `bash scripts/install-hooks.sh` in gururmm repo on Mikes-MacBook-Air before any RMM work
## Project
- [Cascades Migration Plan](project-cascades-migration-plan.md) — Active multi-day migration. Plan file: `C:\Users\Howard\.claude\plans\wise-discovering-panda.md`. Syncro ticket: #110680053. Resume: "resume the Cascades migration plan".
- [GuruRMM Development Principles](gururmm-development-principles.md) - MANDATORY: every feature needs full stack (backend, API, UI, docs, scalability). Product must work without AI agents (AI features are enhancements). Documented in guru-rmm/docs/DESIGN.md.
- [Sync script bug — untracked files](project_sync_script_bug.md) — Flagged for Mike. `.claude/scripts/sync.sh` line 53 misses untracked-only changes; one-line fix included.
- [MasterBooter Side Project](project_masterbooter.md) — Howard's Rust+Slint Windows deployment toolkit at C:\MasterBooter, separate from client work. Do not log to clients/.

View File

@@ -0,0 +1,18 @@
---
name: project-cascades-migration-plan
description: Cascades of Tucson department migration plan — Syncro ticket, plan file location, resume command
metadata:
type: project
---
Active multi-day migration project for Cascades of Tucson. Department-by-department domain join, folder redirection, and Entra sync rollout.
**Why:** Full migration from workgroup/cloud-only to domain-integrated environment with clean end state (everything works automatically on fresh machine domain join).
**Syncro ticket:** https://computerguru.syncromsp.com/tickets/110680053 — update with notes after each session.
**Plan file:** `C:\Users\Howard\.claude\plans\wise-discovering-panda.md`
**Resume command:** Howard says "resume the Cascades migration plan" → read plan file, check CURRENT SAVE POINT section, pick up at next unchecked item.
**How to apply:** At every Cascades session start, read the plan file CURRENT SAVE POINT before doing any work. Update the save point and run /save at end of session.

View File

@@ -0,0 +1,37 @@
$domain = 'cascades.local'
$gpoName = 'CSC - Folder Redirection'
$gpo = Get-GPO -Name $gpoName -Domain $domain -EA Stop
Write-Output "GPO: $($gpo.DisplayName)"
Write-Output "GUID: {$($gpo.Id.ToString().ToUpper())}"
Write-Output "Status: $($gpo.GpoStatus)"
Write-Output ""
Write-Output "=== Security Filter (who this GPO applies to) ==="
Get-GPPermission -Name $gpoName -Domain $domain -All | ForEach-Object {
Write-Output " $($_.Trustee.Name) [$($_.Trustee.TrusteeType)] — $($_.Permission)"
}
Write-Output ""
Write-Output "=== GPO Links ==="
$report = Get-GPOReport -Name $gpoName -Domain $domain -ReportType Xml
$xml = [xml]$report
$links = $xml.GPO.LinksTo
if ($links) {
foreach ($l in $links) {
Write-Output " $($l.SOMPath) — Enabled: $($l.Enabled) — NoOverride: $($l.NoOverride)"
}
} else {
Write-Output " (no links)"
}
Write-Output ""
Write-Output "=== SYSVOL contents ==="
$srv = 'CS-SERVER'
$sysvol = "\\$srv\SYSVOL\$domain\Policies"
$guid = "{$($gpo.Id.ToString().ToUpper())}"
Get-ChildItem "$sysvol\$guid" -Recurse -EA SilentlyContinue | ForEach-Object {
$rel = $_.FullName.Replace("$sysvol\$guid", '')
$type = if ($_.PSIsContainer) { '[DIR]' } else { "[FILE $($_.Length)b]" }
Write-Output " $type $rel"
}

View File

@@ -0,0 +1,19 @@
Import-Module ActiveDirectory -EA SilentlyContinue
$u = Get-ADUser -Identity 'zachary.nelson' -Properties DistinguishedName, Department, Title, MemberOf -EA SilentlyContinue
if ($u) {
Write-Output "DN: $($u.DistinguishedName)"
Write-Output "Department: $($u.Department)"
Write-Output "Title: $($u.Title)"
Write-Output "OU: $($u.DistinguishedName -replace '^CN=[^,]+,','')"
Write-Output ""
Write-Output "Groups:"
$u.MemberOf | ForEach-Object { Write-Output " $_" }
} else {
Write-Output "User not found"
}
Write-Output ""
Write-Output "=== All users in OU=Administrative ==="
Get-ADUser -Filter * -SearchBase "OU=Administrative,OU=Departments,DC=cascades,DC=local" -Properties Department,Title -EA SilentlyContinue |
Select-Object SamAccountName, Name, Department, Title |
ForEach-Object { Write-Output " $($_.SamAccountName)$($_.Name)$($_.Department)$($_.Title)" }

42
.claude/temp/frd-link.ps1 Normal file
View File

@@ -0,0 +1,42 @@
$domain = 'cascades.local'
$gpoName = 'CSC - Folder Redirection'
$ouDN = 'OU=Administrative,OU=Departments,DC=cascades,DC=local'
Import-Module GroupPolicy -EA SilentlyContinue
# Link GPO to OU=Administrative
try {
New-GPLink -Name $gpoName -Domain $domain -Target $ouDN -LinkEnabled Yes -EA Stop
Write-Output "[OK] Linked to $ouDN"
} catch {
if ($_.Exception.Message -like '*already*') {
Set-GPLink -Name $gpoName -Domain $domain -Target $ouDN -LinkEnabled Yes -EA SilentlyContinue
Write-Output "[OK] Link already existed — enabled"
} else {
Write-Output "[ERROR] $($_.Exception.Message)"
}
}
Write-Output ""
Write-Output "=== Security Filter ==="
Get-GPPermission -Name $gpoName -Domain $domain -All | ForEach-Object {
Write-Output " $($_.Trustee.Name) [$($_.Trustee.TrusteeType)] — $($_.Permission)"
}
Write-Output ""
Write-Output "=== Links ==="
$report = [xml](Get-GPOReport -Name $gpoName -Domain $domain -ReportType Xml)
$links = $report.GPO.LinksTo
if ($links) {
foreach ($l in $links) {
Write-Output " $($l.SOMPath) — Enabled: $($l.Enabled)"
}
} else {
Write-Output " (none)"
}
Write-Output ""
Write-Output "=== SG-FolderRedirect members ==="
Get-ADGroupMember -Identity 'SG-FolderRedirect' -EA SilentlyContinue | ForEach-Object {
Write-Output " $($_.SamAccountName)"
}

72
.claude/temp/frd-prep.ps1 Normal file
View File

@@ -0,0 +1,72 @@
$domain = 'cascades.local'
$gpoName = 'CSC - Folder Redirection'
$groupName = 'SG-FolderRedirect'
$groupOU = 'OU=Security Groups,OU=Groups,DC=cascades,DC=local'
Import-Module ActiveDirectory -EA SilentlyContinue
# --- Create SG-FolderRedirect if it doesn't exist ---
$grp = Get-ADGroup -Filter "Name -eq '$groupName'" -EA SilentlyContinue
if (-not $grp) {
try {
New-ADGroup -Name $groupName -GroupScope Global -GroupCategory Security `
-Description 'Members receive GPO folder redirection to \\CS-SERVER\homes\%USERNAME%' `
-Path $groupOU -EA Stop
Write-Output "[OK] Created group: $groupName in $groupOU"
} catch {
# Try root of domain if OU doesn't exist
try {
New-ADGroup -Name $groupName -GroupScope Global -GroupCategory Security `
-Description 'Members receive GPO folder redirection to \\CS-SERVER\homes\%USERNAME%' `
-Path "CN=Users,DC=cascades,DC=local" -EA Stop
Write-Output "[OK] Created group: $groupName in CN=Users (fallback)"
} catch {
Write-Output "[ERROR] Create group: $($_.Exception.Message)"
}
}
} else {
Write-Output "[INFO] Group already exists: $($grp.DistinguishedName)"
}
# --- Add zachary.nelson to the group ---
try {
Add-ADGroupMember -Identity $groupName -Members 'Zachary.Nelson' -EA Stop
Write-Output "[OK] Added Zachary.Nelson to $groupName"
} catch {
if ($_.Exception.Message -like '*already a member*') {
Write-Output "[INFO] Zachary.Nelson already in $groupName"
} else {
Write-Output "[ERROR] Add member: $($_.Exception.Message)"
}
}
# --- Remove Authenticated Users from GPO security filter ---
try {
Set-GPPermission -Name $gpoName -Domain $domain `
-PermissionLevel None -TargetName 'Authenticated Users' -TargetType Group -EA Stop
Write-Output "[OK] Removed Authenticated Users from security filter"
} catch {
Write-Output "[WARN] Remove Authenticated Users: $($_.Exception.Message)"
}
# --- Add SG-FolderRedirect with GpoApply ---
try {
Set-GPPermission -Name $gpoName -Domain $domain `
-PermissionLevel GpoApply -TargetName $groupName -TargetType Group -EA Stop
Write-Output "[OK] Added $groupName with GpoApply"
} catch {
Write-Output "[ERROR] Add group to GPO: $($_.Exception.Message)"
}
# --- Confirm final state ---
Write-Output ""
Write-Output "=== GPO Security Filter ==="
Get-GPPermission -Name $gpoName -Domain $domain -All | ForEach-Object {
Write-Output " $($_.Trustee.Name) [$($_.Trustee.TrusteeType)] — $($_.Permission)"
}
Write-Output ""
Write-Output "=== $groupName members ==="
Get-ADGroupMember -Identity $groupName -EA SilentlyContinue | ForEach-Object {
Write-Output " $($_.SamAccountName)"
}

View File

@@ -0,0 +1,17 @@
$domain = 'cascades.local'
$gpoName = 'CSC - Folder Redirection'
try {
Set-GPPermission -Name $gpoName -Domain $domain `
-PermissionLevel None -TargetName 'Authenticated Users' -TargetType Group `
-Confirm:$false -EA Stop
Write-Output "[OK] Removed Authenticated Users from security filter"
} catch {
Write-Output "[ERROR] $($_.Exception.Message)"
}
Write-Output ""
Write-Output "=== GPO Security Filter ==="
Get-GPPermission -Name $gpoName -Domain $domain -All | ForEach-Object {
Write-Output " $($_.Trustee.Name) [$($_.Trustee.TrusteeType)] — $($_.Permission)"
}

View File

@@ -0,0 +1,30 @@
$domain = 'cascades.local'
$gpoName = 'CSC - Folder Redirection'
$gpoGuid = '{512B43A4-F049-4CE5-BFAC-860AD13E92BE}'
# Remove Authenticated Users directly from the GPO AD object ACL
$gpoADPath = "AD:CN=$gpoGuid,CN=Policies,CN=System,DC=$($domain.Replace('.',',DC='))"
try {
$acl = Get-Acl $gpoADPath -EA Stop
$au = [System.Security.Principal.NTAccount]'NT AUTHORITY\Authenticated Users'
$removed = 0
$acl.Access | Where-Object { $_.IdentityReference.Value -like '*Authenticated Users*' } | ForEach-Object {
$acl.RemoveAccessRule($_) | Out-Null
$removed++
}
if ($removed -gt 0) {
Set-Acl -Path $gpoADPath -AclObject $acl -EA Stop
Write-Output "[OK] Removed $removed ACE(s) for Authenticated Users from GPO AD object"
} else {
Write-Output "[INFO] Authenticated Users not found in ACL"
}
} catch {
Write-Output "[ERROR] ACL approach: $($_.Exception.Message)"
}
# Verify via Get-GPPermission
Write-Output ""
Write-Output "=== GPO Security Filter (final) ==="
Get-GPPermission -Name $gpoName -Domain $domain -All | ForEach-Object {
Write-Output " $($_.Trustee.Name) [$($_.Trustee.TrusteeType)] — $($_.Permission)"
}

View File

@@ -0,0 +1,44 @@
$domain = 'cascades.local'
$gpoName = 'CSC - Folder Redirection'
$gpoGuid = '{512B43A4-F049-4CE5-BFAC-860AD13E92BE}'
Import-Module ActiveDirectory -EA SilentlyContinue
Import-Module GroupPolicy -EA SilentlyContinue
# Suppress all ShouldProcess confirmations
$ConfirmPreference = 'None'
# Try Set-GPPermission with ConfirmPreference suppressed
try {
Set-GPPermission -Name $gpoName -Domain $domain `
-PermissionLevel None -TargetName 'Authenticated Users' -TargetType Group -EA Stop
Write-Output "[OK] Removed via Set-GPPermission"
} catch {
Write-Output "[WARN] Set-GPPermission failed: $($_.Exception.Message)"
# Fallback: GPMC COM object
try {
$gpm = New-Object -ComObject GPMgmt.GPM
$constants = $gpm.GetConstants()
$gpmDomain = $gpm.GetDomain($domain, '', $constants.UseAnyDC)
$gpo = $gpmDomain.GetGPO($gpoGuid)
$secInfo = $gpo.GetSecurityInfo()
$newSec = $gpm.CreateSecurityInfo()
for ($i = 0; $i -lt $secInfo.Count; $i++) {
$perm = $secInfo.Item($i)
if ($perm.Trustee.TrusteeName -ne 'Authenticated Users') {
$newSec.Add($perm)
}
}
$gpo.SetSecurityInfo($newSec)
Write-Output "[OK] Removed via GPMC COM"
} catch {
Write-Output "[ERROR] COM approach: $($_.Exception.Message)"
}
}
Write-Output ""
Write-Output "=== GPO Security Filter (final) ==="
Get-GPPermission -Name $gpoName -Domain $domain -All | ForEach-Object {
Write-Output " $($_.Trustee.Name) [$($_.Trustee.TrusteeType)] — $($_.Permission)"
}

View File

@@ -0,0 +1,56 @@
$domain = 'cascades.local'
$gpoName = 'CSC - Folder Redirection'
# Security filter: remove Authenticated Users, add zachary.nelson
$gpo = Get-GPO -Name $gpoName -Domain $domain
Write-Output "GPO: $($gpo.DisplayName)$($gpo.Id)"
# Remove Authenticated Users from Security Filtering
try {
Set-GPPermission -Name $gpoName -Domain $domain -PermissionLevel None -TargetName 'Authenticated Users' -TargetType Group -EA Stop
Write-Output "[OK] Removed Authenticated Users from security filter"
} catch {
Write-Output "[WARN] Remove Authenticated Users: $($_.Exception.Message)"
}
# Grant zachary.nelson Apply Group Policy permission
try {
Set-GPPermission -Name $gpoName -Domain $domain -PermissionLevel GpoApply -TargetName 'zachary.nelson' -TargetType User -EA Stop
Write-Output "[OK] Added zachary.nelson with GpoApply"
} catch {
Write-Output "[ERROR] Add zachary.nelson: $($_.Exception.Message)"
}
# Also ensure Domain Admins can still read/edit the GPO
try {
Set-GPPermission -Name $gpoName -Domain $domain -PermissionLevel GpoEditDeleteModifySecurity -TargetName 'Domain Admins' -TargetType Group -EA Stop
Write-Output "[OK] Domain Admins GpoEditDeleteModifySecurity confirmed"
} catch {
Write-Output "[WARN] Domain Admins: $($_.Exception.Message)"
}
# Link GPO to OU=Administrative
$ouDN = 'OU=Administrative,OU=Departments,DC=cascades,DC=local'
try {
$link = New-GPLink -Name $gpoName -Domain $domain -Target $ouDN -LinkEnabled Yes -EA Stop
Write-Output "[OK] Linked to $ouDN"
} catch {
if ($_.Exception.Message -like '*already exists*') {
Write-Output "[INFO] Link already exists — enabling it"
Set-GPLink -Name $gpoName -Domain $domain -Target $ouDN -LinkEnabled Yes -EA SilentlyContinue
Write-Output "[OK] Link enabled"
} else {
Write-Output "[ERROR] Link: $($_.Exception.Message)"
}
}
Write-Output ""
Write-Output "=== GPO Scope after changes ==="
Get-GPPermission -Name $gpoName -Domain $domain -All | ForEach-Object {
Write-Output " $($_.Trustee.Name)$($_.Permission)"
}
Write-Output ""
Write-Output "=== GPO Links ==="
(Get-GPO -Name $gpoName -Domain $domain).GpoLinks | ForEach-Object {
Write-Output " $($_.SomName) — Enabled: $($_.Enabled)"
}

View File

@@ -0,0 +1,51 @@
$domain = 'cascades.local'
$srv = 'CS-SERVER'
$sysvol = "\\$srv\SYSVOL\$domain\Policies"
# Find the LE folder redirection GPO
$gpo = Get-GPO -Name 'CSC - Folder Redirection (LE)' -Domain $domain
Write-Output "GPO: $($gpo.DisplayName)"
Write-Output "GUID: {$($gpo.Id.ToString().ToUpper())}"
$gpoPath = "$sysvol\{$($gpo.Id.ToString().ToUpper())}"
Write-Output "Path: $gpoPath"
Write-Output ""
# List all files in the GPO folder recursively
Write-Output "=== SYSVOL file tree ==="
Get-ChildItem $gpoPath -Recurse -File -EA SilentlyContinue | ForEach-Object {
Write-Output " $($_.FullName.Replace($gpoPath, ''))"
}
Write-Output ""
# Show GPT.INI
Write-Output "=== GPT.INI ==="
[System.IO.File]::ReadAllText("$gpoPath\GPT.INI") | Write-Output
Write-Output ""
# Show any fdeploy.ini or redirection files
$fdeployPath = "$gpoPath\User\Documents & Settings"
if (Test-Path $fdeployPath) {
Write-Output "=== fdeploy.ini ==="
[System.IO.File]::ReadAllText("$fdeployPath\fdeploy.ini") | Write-Output
} else {
Write-Output "No 'Documents & Settings' folder found"
}
# Also check the unlinked CSC - Folder Redirection GPO
Write-Output ""
Write-Output "=== CSC - Folder Redirection (unlinked) ==="
$gpo2 = Get-GPO -Name 'CSC - Folder Redirection' -Domain $domain -EA SilentlyContinue
if ($gpo2) {
Write-Output "GUID: {$($gpo2.Id.ToString().ToUpper())}"
$gpo2Path = "$sysvol\{$($gpo2.Id.ToString().ToUpper())}"
Get-ChildItem $gpo2Path -Recurse -File -EA SilentlyContinue | ForEach-Object {
Write-Output " $($_.FullName.Replace($gpo2Path, ''))"
}
$fd2 = "$gpo2Path\User\Documents & Settings\fdeploy.ini"
if (Test-Path $fd2) {
Write-Output "fdeploy.ini:"
[System.IO.File]::ReadAllText($fd2) | Write-Output
}
} else {
Write-Output "GPO not found"
}

View File

@@ -0,0 +1,30 @@
$domain = 'cascades.local'
$srv = 'CS-SERVER'
$sysvol = "\\$srv\SYSVOL\$domain\Policies"
# Read the unlinked CSC - Folder Redirection Registry.xml
$gpo = Get-GPO -Name 'CSC - Folder Redirection' -Domain $domain
$guid = "{$($gpo.Id.ToString().ToUpper())}"
$xmlPath = "$sysvol\$guid\User\Preferences\Registry\Registry.xml"
Write-Output "=== CSC - Folder Redirection Registry.xml ==="
[System.IO.File]::ReadAllText($xmlPath) | Write-Output
Write-Output ""
Write-Output "=== LE GPO GPC attributes (AD) ==="
$gpoLE = Get-GPO -Name 'CSC - Folder Redirection (LE)' -Domain $domain
$leGuid = "{$($gpoLE.Id.ToString().ToUpper())}"
$gpcObj = Get-ADObject -Filter { Name -eq $leGuid } -Properties 'gPCUserExtensionNames','gPCMachineExtensionNames','versionNumber','gPCFileSysPath' -SearchBase "CN=Policies,CN=System,DC=cascades,DC=local" -EA SilentlyContinue
if ($gpcObj) {
Write-Output " gPCUserExtensionNames: $($gpcObj.gPCUserExtensionNames)"
Write-Output " gPCMachineExtensionNames: $($gpcObj.gPCMachineExtensionNames)"
Write-Output " versionNumber: $($gpcObj.versionNumber)"
Write-Output " gPCFileSysPath: $($gpcObj.gPCFileSysPath)"
} else { Write-Output " GPC object not found" }
Write-Output ""
Write-Output "=== LE GPO full SYSVOL tree (including empty dirs) ==="
Get-ChildItem "\\$srv\SYSVOL\$domain\Policies\$leGuid" -Recurse -EA SilentlyContinue | ForEach-Object {
$rel = $_.FullName.Replace("\\$srv\SYSVOL\$domain\Policies\$leGuid", '')
$type = if ($_.PSIsContainer) { '[DIR]' } else { "[FILE $(($_.Length))]" }
Write-Output " $type $rel"
}

View File

@@ -0,0 +1,40 @@
$ErrorActionPreference = 'Continue'
Write-Output "=== KFM Check: $env:COMPUTERNAME ==="
Write-Output ""
Write-Output "--- Logged on users ---"
query user 2>&1 | ForEach-Object { Write-Output $_ }
Write-Output ""
Write-Output "--- OneDrive.exe processes ---"
$odProcs = Get-CimInstance Win32_Process -Filter "Name='OneDrive.exe'" -EA SilentlyContinue
if ($odProcs) {
foreach ($p in $odProcs) {
$o = $p.GetOwner()
Write-Output " Running as: $($o.Domain)\$($o.User)"
}
} else { Write-Output " Not running" }
Write-Output ""
Write-Output "--- User profile OneDrive folders ---"
Get-ChildItem C:\Users -Directory -EA SilentlyContinue |
Where-Object { $_.Name -notin @('Public','Default','Default User','All Users') } |
ForEach-Object {
$od = Get-ChildItem $_.FullName -Directory -Filter 'OneDrive*' -EA SilentlyContinue
Write-Output " $($_.Name): $(if ($od) { $od.Name -join ', ' } else { 'no OneDrive folder' })"
}
Write-Output ""
Write-Output "--- Loaded HKU shell folders ---"
Get-ChildItem 'Registry::HKEY_USERS' -EA SilentlyContinue |
Where-Object { $_.Name -match 'S-1-5-21' -and $_.Name -notmatch '_Classes' } |
ForEach-Object {
$sid = $_.PSChildName
try { $un = ([System.Security.Principal.SecurityIdentifier]$sid).Translate([System.Security.Principal.NTAccount]).Value } catch { $un = $sid }
Write-Output " User: $un"
$sf = Get-ItemProperty "Registry::HKEY_USERS\$sid\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" -EA SilentlyContinue
if ($sf) {
$d = $sf.Personal
$dt = $sf.Desktop
$dl = $sf.'{374DE290-123F-4565-9164-39C4925E467B}'
Write-Output " Documents: $d$(if ($d -like '*OneDrive*') { ' [KFM ACTIVE]' })"
Write-Output " Desktop: $dt$(if ($dt -like '*OneDrive*') { ' [KFM ACTIVE]' })"
Write-Output " Downloads: $dl$(if ($dl -like '*OneDrive*') { ' [KFM ACTIVE]' })"
} else { Write-Output " Shell Folders key not present (user not logged in or hive not loaded)" }
}

View File

@@ -0,0 +1,21 @@
$domain = 'cascades.local'
$srv = 'CS-SERVER'
$sysvol = "\\$srv\SYSVOL\$domain\Policies"
$gpo = Get-GPO -Name 'CSC - Folder Redirection' -Domain $domain
$guid = "{$($gpo.Id.ToString().ToUpper())}"
$xmlPath = "$sysvol\$guid\User\Preferences\Registry\Registry.xml"
$bytes = [System.IO.File]::ReadAllBytes($xmlPath)
Write-Output "REGXML_B64_START"
Write-Output ([Convert]::ToBase64String($bytes))
Write-Output "REGXML_B64_END"
# Also get LE GPO GPC attributes from AD
Import-Module ActiveDirectory -EA SilentlyContinue
$leGpo = Get-GPO -Name 'CSC - Folder Redirection (LE)' -Domain $domain
$leGuid = $leGpo.Id.ToString().ToUpper()
$gpcObj = Get-ADObject -Filter "Name -eq '{$leGuid}'" `
-SearchBase "CN=Policies,CN=System,DC=cascades,DC=local" `
-Properties gPCUserExtensionNames,gPCMachineExtensionNames,versionNumber -EA SilentlyContinue
Write-Output "LEGPO_EXT: $($gpcObj.gPCUserExtensionNames)"

View File

@@ -217,3 +217,163 @@ Planned work for next session:
| Remove Meredith.Kuhn + John.Trozzi from Domain Admins | Low | Deferred |
| SG-Mgmt-RW + SG-Sales-RW membership | Medium | Populate before Phase 3 GPO linking |
| CSC - Folder Redirection (full) | Medium | Blocked on Phase 3 — check OneDrive KFM on each PC first |
---
## Update: 17:06 PT — Admin folder redirection setup + department migration master plan
### Session scope
Continued from context-limit session. Completed the accounting/admin folder redirection GPO setup for Zachary Nelson, resolved architecture questions about OneDrive/HIPAA/AppData, and built the full department migration master plan.
---
### 1. Folder Redirection Architecture Decisions
**GPO approach — native FRD, not GPP Registry:**
- Inspected `CSC - Folder Redirection` GPO SYSVOL: had `User\Preferences\Registry\Registry.xml` (GPP Registry approach, 550 bytes) plus empty `Documents & Settings` folder.
- Decision: use native Group Policy Folder Redirection (GPMC UI → User Configuration → Windows Settings → Folder Redirection), not the GPP Registry hack. Howard configured this directly in GPMC on CS-SERVER.
**One GPO for all non-LE departments (not per-dept):**
- `%USERNAME%` in the redirect path makes it universal — `\\CS-SERVER\homes\zachary.nelson\Documents`, `\\CS-SERVER\homes\lauren.hasselman\Documents`, etc. all handled by one policy.
- Keep `CSC - Folder Redirection (LE)` for Life Enrichment. `CSC - Folder Redirection` becomes the universal GPO for all other departments.
**Security group filter instead of OU scope:**
- All 6 users in OU=Administrative (Zachary.Nelson, lauren.hasselman, Alma.Montt, Meredith.Kuhn, Ashley.Jensen, Allison.Reibschied) — cannot use OU scope without hitting users not ready for redirection.
- Solution: `SG-FolderRedirect` security group. Only members get the GPO applied.
- Future: when all departments migrated, remove SG filter, add Authenticated Users — existing redirected users see zero disruption.
**AppData — do not redirect:**
- Confirmed: redirect only Documents, Desktop, Downloads. AppData causes login slowdowns, application breakage, and network overhead with no meaningful benefit for assigned-machine users.
---
### 2. GPO Configuration (Howard in GPMC on CS-SERVER)
Howard opened GPMC, edited `CSC - Folder Redirection`, configured:
- Documents → `\\CS-SERVER\homes` (Basic redirection, grant exclusive rights, move contents)
- Desktop → `\\CS-SERVER\homes` (same settings)
- Downloads → `\\CS-SERVER\homes` (same settings)
- Policy removal: leave folder in new location
Howard also removed `Authenticated Users` from Security Filtering directly in GPMC (scripted removal failed — `Set-GPPermission -PermissionLevel None` triggers interactive confirmation prompt even with `-Confirm:$false` in NonInteractive PS sessions; GPMC COM `CreateSecurityInfo` method also unavailable).
---
### 3. SG-FolderRedirect Created and Wired
Dispatched via GuruRMM to CS-SERVER:
- Created `SG-FolderRedirect` (Global Security group, created in CN=Users fallback since OU=Security Groups,OU=Groups path failed)
- Added `Zachary.Nelson` as sole member
- Added `SG-FolderRedirect` with GpoApply permission on `CSC - Folder Redirection`
- Linked `CSC - Folder Redirection` to `OU=Administrative,OU=Departments,DC=cascades,DC=local` (Enabled, Order 1)
**Final GPO state:**
```
CSC - Folder Redirection
Linked: OU=Administrative — Enabled: True
Security filter: SG-FolderRedirect [GpoApply]
Members of SG-FolderRedirect: Zachary.Nelson
```
---
### 4. GuruRMM API Auth Change
GuruRMM API (port 3001) now requires JWT auth header. Previous sessions worked without it — behavior changed. Resolved:
```bash
TOKEN=$(curl -s -X POST "http://172.16.3.30:3001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"claude-api@azcomputerguru.com","password":"ClaudeAPI2026!@#"}' \
| grep -o '"token":"[^"]*"' | cut -d'"' -f4)
```
Command dispatch also now requires `command_type` field: `{"command_type":"powershell","command":"..."}`.
Result polling endpoint is `/api/commands/{id}` (not `/api/agents/{id}/command/{id}`).
---
### 5. HIPAA / OneDrive Discussion
Concluded: server folder redirection is the correct posture for PHI-adjacent roles (accounting/admin). OneDrive requires a signed Microsoft HIPAA BAA, conditional access to block personal device sync, and Business Premium or E3 for full compliance tooling. Until BAA status is confirmed for cascadestucson.com tenant, PHI should stay on-prem.
---
### 6. Entra Connect — Expansion Plan
Entra Connect is live on CS-SERVER, production mode. Currently syncing OU=Caregivers + OU=Groups only. Not yet syncing Administrative or other department OUs.
Key facts for expansion:
- On-prem UPN suffix is `@cascades.local` (non-routable). Must add `cascadestucson.com` as alternate UPN suffix in AD before syncing any new dept OU.
- Change user UPNs to `@cascadestucson.com` → soft-match links to existing M365 cloud accounts.
- PHS makes on-prem password win — M365 password changes to Windows domain password on first sync. Notify users or align passwords first.
- Local Windows login behavior is unchanged. GPOs, group memberships, folder paths — all unchanged.
---
### 7. Department Migration Master Plan
Created comprehensive multi-day migration plan. Covers:
- Per-department template: pre-checks → machine prep → domain join → ProfWiz → prep-profile script → SG-FolderRedirect → Entra sync
- Department sequence (Admin → LE → Culinary → RS → Marketing → Care → Caregivers)
- Final switchover: SG-FolderRedirect removed, Authenticated Users restored — zero disruption to already-redirected users
- Clean machine end state: fresh domain join → all GPOs apply automatically, no manual steps
- Key guardrails from 2026-04-17 LE session (ProfWiz NTUSER.DAT poisoning, KFM conflict procedure)
- Prerequisites before Phase 3 GPO linking (SG membership, krbtgt rotation, Domain Admins cleanup)
**Plan file:** `C:\Users\Howard\.claude\plans\wise-discovering-panda.md`
**Resume command:** "resume the Cascades migration plan" at session start
**Syncro ticket:** https://computerguru.syncromsp.com/tickets/110680053
---
### Configuration Changes
| File | Action | Notes |
|------|--------|-------|
| `clients/cascades-tucson/session-logs/2026-05-20-howard-phase2.6-printers-gpos-account-cleanup.md` | Appended | This update |
| `C:\Users\Howard\.claude\plans\wise-discovering-panda.md` | Created | Master migration plan with save-point tracking |
| `.claude/memory/project-cascades-migration-plan.md` | Created | Memory entry for plan file + Syncro ticket |
| `.claude/memory/MEMORY.md` | Updated | Added Cascades migration plan pointer |
| `C:\claudetools\.claude\temp\check-frd-gpo.ps1` | Created | GPO inspection script |
| `C:\claudetools\.claude\temp\frd-prep.ps1` | Created | SG create + GPO filter setup |
| `C:\claudetools\.claude\temp\frd-link.ps1` | Created | GPO link to OU=Administrative |
| `C:\claudetools\.claude\temp\find-zachary.ps1` | Created | AD user lookup + OU=Administrative inventory |
**AD changes (via GuruRMM on CS-SERVER):**
- Created security group `SG-FolderRedirect` (CN=Users,DC=cascades,DC=local)
- Added Zachary.Nelson to SG-FolderRedirect
- Removed Authenticated Users from CSC - Folder Redirection security filter (done by Howard in GPMC)
- Linked CSC - Folder Redirection to OU=Administrative (Enabled, Order 1)
**GPMC changes (Howard on CS-SERVER directly):**
- Configured native folder redirection in CSC - Folder Redirection:
- Documents, Desktop, Downloads → `\\CS-SERVER\homes` (Basic, GrantExclusive, MoveContents)
- Policy removal: leave folder in new location
---
### Infrastructure & Servers
| Resource | Value |
|----------|-------|
| CS-SERVER agent ID | `6766e973-e703-47c1-be56-76950290f87c` |
| GuruRMM API | `http://172.16.3.30:3001` (now requires JWT auth) |
| GuruRMM API admin | `claude-api@azcomputerguru.com` / `ClaudeAPI2026!@#` |
| cascades.local GPO GUID | CSC - Folder Redirection = `{512B43A4-F049-4CE5-BFAC-860AD13E92BE}` |
| ACCT2-PC | Zachary.Nelson's machine — test folder redirection tonight |
| DESKTOP-H6QHRR7 | lauren.hasselman — OneDrive KFM active, Howard moves data manually first |
---
### Pending / Next Steps
| Item | Priority | Notes |
|------|----------|-------|
| Zachary folder redirection live test | High | Tonight on ACCT2-PC — gpupdate /force as zachary.nelson, verify \\CS-SERVER\homes\zachary.nelson\ populated |
| Lauren Hasselman | High | Howard moves OneDrive data manually first, then add to SG-FolderRedirect |
| Entra Connect: add OU=Administrative to sync | Medium | Set cascadestucson.com UPN suffix first, align passwords, then delta sync |
| Phase 3 domain joins | High | DESKTOP-KQSL232 first; MDIRECTOR-PC blocked on Win10 Pro upgrade |
| Phase 3 GPO linking | High | After first successful domain join: Security Baseline, Drive Mappings, Printer Deployment, Windows Update |
| SG-Mgmt-RW / SG-Sales-RW / SG-Activities-RW | Medium | Populate before Drive Mappings GPO linked |
| krbtgt password rotation | Medium | 569+ days old |
| Remove Meredith.Kuhn + John.Trozzi from Domain Admins | Low | Deferred |
| Update Syncro ticket #110680053 | Medium | Log today's work |