Files
claudetools/clients/cascades-tucson/scripts/setup-audit-drop-share.ps1
Howard Enos 4220b8f57c sync: auto-sync from ACG-TECH03L at 2026-04-17 15:05:26
Author: Howard Enos
Machine: ACG-TECH03L
Timestamp: 2026-04-17 15:05:26
2026-04-17 15:05:28 -07:00

157 lines
6.4 KiB
PowerShell

<#
.SYNOPSIS
Creates write-only audit drop share with service account and scheduled archive.
.DESCRIPTION
Provisions on CS-SERVER:
- AD service account svc-audit-upload (no interactive logon)
- AD group AuditUploaders (members get write-only access)
- D:\Shares\AuditDrop folder with NTFS write-only ACL
- Hidden SMB share \\CS-SERVER\AuditDrop$ (Change for AuditUploaders, Full for Domain Admins)
- Daily 3am scheduled task that moves yesterday's drops into D:\Shares\AuditDrop_Archive\YYYY-MM-DD\
Idempotent — safe to re-run.
.NOTES
Run as Domain Admin on CS-SERVER (or any system with AD tools + SMB management installed).
Verify the OUs in $svcOuPath and $groupOuPath exist before running, or change them.
#>
# === VARIABLES ===
$domainDN = "DC=cascades,DC=local"
$svcOuPath = "OU=ServiceAccounts,$domainDN"
$groupOuPath = "OU=Groups,$domainDN"
$svcUser = "svc-audit-upload"
$group = "AuditUploaders"
$drop = "D:\Shares\AuditDrop"
$archiveRoot = "D:\Shares\AuditDrop_Archive"
$scriptPath = "D:\Shares\Scripts\Archive-AuditDrop.ps1"
# === 0. Pre-flight: confirm target OUs exist ===
foreach ($ou in @($svcOuPath, $groupOuPath)) {
try {
Get-ADOrganizationalUnit -Identity $ou -ErrorAction Stop | Out-Null
Write-Host "[OK] OU exists: $ou"
} catch {
Write-Host "[ERROR] OU not found: $ou" -ForegroundColor Red
Write-Host " Create it first, or edit `$svcOuPath / `$groupOuPath in this script." -ForegroundColor Yellow
Write-Host " Example: New-ADOrganizationalUnit -Name 'ServiceAccounts' -Path '$domainDN' -ProtectedFromAccidentalDeletion `$true" -ForegroundColor Yellow
exit 1
}
}
# === 1. Create the dedicated upload service account ===
$svcPwd = Read-Host -AsSecureString -Prompt "Enter password for $svcUser (store in 1Password / SOPS vault)"
if (-not (Get-ADUser -Filter "SamAccountName -eq '$svcUser'" -ErrorAction SilentlyContinue)) {
New-ADUser `
-Name $svcUser `
-SamAccountName $svcUser `
-DisplayName "Service: Audit JSON Upload" `
-Description "Write-only access to \\CS-SERVER\AuditDrop$. Used by Syncro audit upload script. Do not use interactively." `
-Path $svcOuPath `
-AccountPassword $svcPwd `
-PasswordNeverExpires $true `
-CannotChangePassword $true `
-Enabled $true
Write-Host "[OK] Created service account: $svcUser"
} else {
Write-Host "[OK] Service account already exists: $svcUser"
}
# === 2. Create the AD group ===
if (-not (Get-ADGroup -Filter "SamAccountName -eq '$group'" -ErrorAction SilentlyContinue)) {
New-ADGroup `
-Name $group `
-SamAccountName $group `
-GroupScope Global `
-GroupCategory Security `
-Path $groupOuPath `
-Description "Members can WRITE-ONLY to \\CS-SERVER\AuditDrop$. No read/list."
Write-Host "[OK] Created group: $group"
} else {
Write-Host "[OK] Group already exists: $group"
}
# Add service account to group (idempotent)
Add-ADGroupMember -Identity $group -Members $svcUser -ErrorAction SilentlyContinue
Write-Host "[OK] Membership confirmed: $svcUser in $group"
# === 3. Create the drop folder ===
New-Item -Path $drop -ItemType Directory -Force | Out-Null
Write-Host "[OK] Drop folder ready: $drop"
# === 4. NTFS write-only permissions ===
icacls $drop /inheritance:r | Out-Null
icacls $drop /grant:r "CASCADES\Domain Admins:(OI)(CI)F" | Out-Null
icacls $drop /grant:r "SYSTEM:(OI)(CI)F" | Out-Null
icacls $drop /grant:r "CASCADES\${group}:(WD,AD,WA,WEA,RA,REA,RC,S,X)" | Out-Null
Write-Host "[OK] NTFS permissions applied. Listing:"
icacls $drop
# === 5. Create the hidden SMB share ===
if (-not (Get-SmbShare -Name "AuditDrop$" -ErrorAction SilentlyContinue)) {
New-SmbShare `
-Name "AuditDrop$" `
-Path $drop `
-FullAccess "CASCADES\Domain Admins" `
-ChangeAccess "CASCADES\${group}" `
-Description "Audit JSON drop-box. Hidden. Write-only for AuditUploaders group."
Write-Host "[OK] Created SMB share: AuditDrop$"
} else {
Write-Host "[OK] SMB share already exists: AuditDrop$"
}
Write-Host "[OK] Share access:"
Get-SmbShareAccess -Name "AuditDrop$"
# === 6. Generate the archive script ===
# IMPORTANT: backtick-escape any $ that must remain literal in the GENERATED file.
# - $drop and $archiveRoot expand NOW (they're fixed paths set above)
# - $src, $archive, $_, $(Get-Date ...) must be backtick-escaped so they expand at TASK RUN TIME
$archiveScript = @"
`$src = "$drop"
`$archive = "$archiveRoot\`$(Get-Date -Format yyyy-MM-dd)"
New-Item -Path `$archive -ItemType Directory -Force | Out-Null
Get-ChildItem -Path `$src -File | Where-Object { `$_.LastWriteTime -lt (Get-Date).AddHours(-2) } |
Move-Item -Destination `$archive -Force
"@
New-Item -ItemType Directory -Path (Split-Path $scriptPath) -Force | Out-Null
$archiveScript | Out-File $scriptPath -Encoding UTF8 -Force
Write-Host "[OK] Archive script written: $scriptPath"
Write-Host " Contents:"
Get-Content $scriptPath | ForEach-Object { Write-Host " $_" }
# === 7. Create scheduled task (daily 3am) ===
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -Daily -At 3am
if (-not (Get-ScheduledTask -TaskName "Archive-AuditDrop" -ErrorAction SilentlyContinue)) {
Register-ScheduledTask `
-TaskName "Archive-AuditDrop" `
-Action $action `
-Trigger $trigger `
-RunLevel Highest `
-User "SYSTEM"
Write-Host "[OK] Scheduled task created: Archive-AuditDrop (daily 3am)"
} else {
Write-Host "[OK] Scheduled task already exists: Archive-AuditDrop"
}
# === 8. Test instructions ===
Write-Host ""
Write-Host "=== TEST FROM A WORKSTATION ===" -ForegroundColor Cyan
Write-Host "Run these manually to verify write-only behavior:"
Write-Host ""
Write-Host " `$cred = Get-Credential cascades\$svcUser"
Write-Host " New-PSDrive -Name T -PSProvider FileSystem -Root '\\CS-SERVER\AuditDrop$' -Credential `$cred"
Write-Host " 'hello' | Out-File T:\test_`$(hostname).txt # SHOULD SUCCEED"
Write-Host " Get-ChildItem T:\ # SHOULD FAIL (Access Denied)"
Write-Host " Get-Content T:\test_`$(hostname).txt # SHOULD FAIL (Access Denied)"
Write-Host " Remove-PSDrive T"
Write-Host ""
Write-Host "If all three SHOULD-FAIL lines actually return Access Denied, the drop-box is correctly write-only." -ForegroundColor Green