Files
claudetools/clients/cascades-tucson/docs/migration/scripts/phase3-join-domain.ps1
Howard Enos 8d975c1b44 import: ingested 160 files from C:\Users\howar\Clients
Howard's personal MSP client documentation folder imported into shared
ClaudeTools repo via /import command. Scope:

Clients (structured MSP docs under clients/<name>/docs/):
- anaise       (NEW)  - 13 files
- cascades-tucson     - 47 files merged (existing had only reports/)
- dataforth           - 18 files merged (alongside incident reports)
- instrumental-music-center - 14 files merged
- khalsa       (NEW)  - 22 files, multi-site (camden, river)
- kittle       (NEW)  - 16 files incl. fix-pdf-preview, gpo-intranet-zone
- lens-auto-brokerage (NEW) - 3 files (name matches SOPS vault)
- _client_template    - 13-file scaffold for new clients

MSP tooling (projects/msp-tools/):
- msp-audit-scripts/ - server_audit.ps1, workstation_audit.ps1, README
- utilities/         - clean_printer_ports, win11_upgrade,
                       screenconnect-toolbox-commands

Credential handling:
- Extracted 1 inline password (Anaise DESKTOP-O8GF4SD / david)
  to SOPS vault: clients/anaise/desktop-o8gf4sd.sops.yaml
- Redacted overview.md with vault reference pattern
- Scanned all 160 files for keys/tokens/connection strings -
  no other credentials found

Skipped:
- Cascades/.claude/settings.local.json (per-machine config)
- Source-root CLAUDE.md (personal, claudetools has its own)
- scripts/server_audit.ps1 and workstation_audit.ps1 at source root
  (identical duplicates of msp-audit-scripts versions)

Memory updates:
- reference_client_docs_structure.md (layout, conventions, active list)
- reference_msp_audit_scripts.md (locations, ScreenConnect 80-char rule)

Session log: session-logs/2026-04-16-howard-client-docs-import.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 19:43:58 -07:00

152 lines
6.3 KiB
PowerShell

#Requires -RunAsAdministrator
<#
.SYNOPSIS
Phase 3.1: Domain join a workstation.
.DESCRIPTION
Documents current state, creates local admin backup, verifies DNS,
and joins the machine to cascades.local domain.
Run on each target workstation via ScreenConnect.
.NOTES
Order: DESKTOP-KQSL232 -> CHEF-PC -> SALES4-PC -> MDIRECTOR-PC
Machine will REBOOT after domain join.
#>
param(
[string]$LocalAdminPassword = ""
)
$DomainName = "cascades.local"
$OUPath = "OU=Staff PCs,OU=Workstations,DC=cascades,DC=local"
$MigrationDir = "C:\IT-Migration"
Write-Host "=== Phase 3.1: Domain Join - $env:COMPUTERNAME ===" -ForegroundColor Cyan
Write-Host ""
# --- Step 1: Document current state ---
Write-Host "--- Step 1: Documenting current state ---" -ForegroundColor Yellow
New-Item -Path $MigrationDir -ItemType Directory -Force | Out-Null
$infoFile = "$MigrationDir\pre-join-info_$(Get-Date -Format 'yyyy-MM-dd_HHmm').txt"
"=== Pre-Join State for $env:COMPUTERNAME ===" | Out-File $infoFile
"Timestamp: $(Get-Date)" | Out-File $infoFile -Append
"" | Out-File $infoFile -Append
"--- SYSTEM INFO ---" | Out-File $infoFile -Append
systeminfo | Out-File $infoFile -Append
"--- IP CONFIG ---" | Out-File $infoFile -Append
ipconfig /all | Out-File $infoFile -Append
"--- PRINTERS ---" | Out-File $infoFile -Append
Get-Printer -ErrorAction SilentlyContinue | Format-List | Out-File $infoFile -Append
"--- MAPPED DRIVES ---" | Out-File $infoFile -Append
net use | Out-File $infoFile -Append
"--- LOCAL USERS ---" | Out-File $infoFile -Append
Get-LocalUser | Format-Table | Out-File $infoFile -Append
"--- INSTALLED SOFTWARE ---" | Out-File $infoFile -Append
Get-WmiObject Win32_Product | Select-Object Name, Version | Sort-Object Name | Format-Table | Out-File $infoFile -Append
Write-Host " [OK] State documented at $infoFile" -ForegroundColor Green
# --- Step 2: Create local admin backup ---
Write-Host "`n--- Step 2: Creating MSPAdmin local account ---" -ForegroundColor Yellow
$localAdmin = Get-LocalUser -Name "Localadmin" -ErrorAction SilentlyContinue
if (-not $localAdmin) {
if (-not $LocalAdminPassword) {
Write-Host " [INPUT NEEDED] Enter password for Localadmin account:" -ForegroundColor Yellow
$securePassword = Read-Host -AsSecureString
} else {
$securePassword = ConvertTo-SecureString $LocalAdminPassword -AsPlainText -Force
}
New-LocalUser -Name "Localadmin" -Password $securePassword -PasswordNeverExpires -AccountNeverExpires -Description "Local emergency admin - migration rollback" | Out-Null
Add-LocalGroupMember -Group "Administrators" -Member "Localadmin" | Out-Null
Write-Host " [OK] Localadmin local admin created" -ForegroundColor Green
} else {
Write-Host " [SKIP] Localadmin already exists" -ForegroundColor DarkGray
}
# --- Step 3: Verify DNS ---
Write-Host "`n--- Step 3: Verifying DNS resolution ---" -ForegroundColor Yellow
try {
$dns = Resolve-DnsName "cs-server.cascades.local" -ErrorAction Stop
Write-Host " [OK] cs-server.cascades.local resolves to: $($dns.IPAddress -join ', ')" -ForegroundColor Green
}
catch {
Write-Host " [FAIL] Cannot resolve cs-server.cascades.local" -ForegroundColor Red
$currentDns = (Get-DnsClientServerAddress -AddressFamily IPv4 | Where-Object { $_.ServerAddresses.Count -gt 0 })
Write-Host " Current DNS servers:" -ForegroundColor Yellow
foreach ($adapter in $currentDns) {
Write-Host " $($adapter.InterfaceAlias): $($adapter.ServerAddresses -join ', ')" -ForegroundColor Yellow
}
Write-Host ""
Write-Host " Options:" -ForegroundColor Cyan
Write-Host " [F] Fix DNS — set primary DNS to 192.168.2.254 (CS-SERVER) and retry" -ForegroundColor Cyan
Write-Host " [A] Abort — exit and fix manually" -ForegroundColor Cyan
$choice = Read-Host " Enter F or A"
if ($choice -eq 'F') {
# Get the active adapter (the one with a default gateway)
$activeAdapter = Get-NetIPConfiguration | Where-Object { $_.IPv4DefaultGateway -ne $null } | Select-Object -First 1
if (-not $activeAdapter) {
Write-Host " [FAIL] No active adapter with a gateway found. Fix manually." -ForegroundColor Red
exit 1
}
$ifIndex = $activeAdapter.InterfaceIndex
$ifName = $activeAdapter.InterfaceAlias
Write-Host " Setting DNS on '$ifName' to 192.168.2.254 (CS-SERVER)..." -ForegroundColor Yellow
Set-DnsClientServerAddress -InterfaceIndex $ifIndex -ServerAddresses @('192.168.2.254')
Clear-DnsClientCache
# Retry resolution
Start-Sleep -Seconds 2
try {
$dns = Resolve-DnsName "cs-server.cascades.local" -ErrorAction Stop
Write-Host " [OK] DNS fixed. cs-server.cascades.local resolves to: $($dns.IPAddress -join ', ')" -ForegroundColor Green
}
catch {
Write-Host " [FAIL] Still cannot resolve after DNS change. Check network connectivity to 192.168.2.254" -ForegroundColor Red
exit 1
}
}
else {
Write-Host " [ABORT] Fix DNS and re-run the script." -ForegroundColor Yellow
exit 1
}
}
# --- Step 4: Confirm and join ---
Write-Host "`n--- Step 4: Domain Join ---" -ForegroundColor Yellow
Write-Host " Computer: $env:COMPUTERNAME" -ForegroundColor Cyan
Write-Host " Domain: $DomainName" -ForegroundColor Cyan
Write-Host " OU: $OUPath" -ForegroundColor Cyan
Write-Host ""
Write-Host " Machine will REBOOT after joining." -ForegroundColor Yellow
Write-Host ""
$confirm = Read-Host " Type 'JOIN' to proceed (anything else to abort)"
if ($confirm -ne "JOIN") {
Write-Host " [ABORT] Domain join cancelled by user" -ForegroundColor Yellow
exit 0
}
try {
Write-Host " Enter domain admin credentials..." -ForegroundColor Yellow
Add-Computer -DomainName $DomainName -OUPath $OUPath -Credential (Get-Credential) -Restart -Force
Write-Host " [OK] Domain join initiated - machine is restarting..." -ForegroundColor Green
}
catch {
Write-Host " [ERROR] Domain join failed: $_" -ForegroundColor Red
Write-Host " Troubleshooting:" -ForegroundColor Yellow
Write-Host " - Verify credentials (domain admin)" -ForegroundColor Yellow
Write-Host " - Check firewall rules allow AD ports from this subnet" -ForegroundColor Yellow
Write-Host " - Run phase3-pre-join-verify.ps1 for diagnostics" -ForegroundColor Yellow
exit 1
}