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:
@@ -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/.
|
||||
|
||||
18
.claude/memory/project-cascades-migration-plan.md
Normal file
18
.claude/memory/project-cascades-migration-plan.md
Normal 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.
|
||||
37
.claude/temp/check-frd-gpo.ps1
Normal file
37
.claude/temp/check-frd-gpo.ps1
Normal 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"
|
||||
}
|
||||
19
.claude/temp/find-zachary.ps1
Normal file
19
.claude/temp/find-zachary.ps1
Normal 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
42
.claude/temp/frd-link.ps1
Normal 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
72
.claude/temp/frd-prep.ps1
Normal 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)"
|
||||
}
|
||||
17
.claude/temp/frd-remove-authedusers.ps1
Normal file
17
.claude/temp/frd-remove-authedusers.ps1
Normal 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)"
|
||||
}
|
||||
30
.claude/temp/frd-remove-authedusers2.ps1
Normal file
30
.claude/temp/frd-remove-authedusers2.ps1
Normal 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)"
|
||||
}
|
||||
44
.claude/temp/frd-remove-authedusers3.ps1
Normal file
44
.claude/temp/frd-remove-authedusers3.ps1
Normal 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)"
|
||||
}
|
||||
56
.claude/temp/frd-scope-zachary.ps1
Normal file
56
.claude/temp/frd-scope-zachary.ps1
Normal 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)"
|
||||
}
|
||||
51
.claude/temp/gpo-inspect-le.ps1
Normal file
51
.claude/temp/gpo-inspect-le.ps1
Normal 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"
|
||||
}
|
||||
30
.claude/temp/gpo-inspect2.ps1
Normal file
30
.claude/temp/gpo-inspect2.ps1
Normal 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"
|
||||
}
|
||||
40
.claude/temp/kfm-check.ps1
Normal file
40
.claude/temp/kfm-check.ps1
Normal 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)" }
|
||||
}
|
||||
21
.claude/temp/read-regxml.ps1
Normal file
21
.claude/temp/read-regxml.ps1
Normal 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)"
|
||||
@@ -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 |
|
||||
|
||||
Reference in New Issue
Block a user