CS-SERVER post-reboot verification: time sync, TLS 1.2 enforcement, and Windows Server Backup feature all persisted cleanly. dcdiag clean. Ready for Entra Connect install. Synology cascadesDS permission inventory captured via DSM API (SSH disabled by default on Synology). 35 users, 4 groups, 10 shares. Analysis identifies 7 shared-account role logins (HIPAA violation), 8 departed-employee accounts to clean up, and 4 shares needing Meredith-side confirmation before migration (pacs most sensitive). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
133 lines
5.1 KiB
PowerShell
133 lines
5.1 KiB
PowerShell
# ============================================================================
|
|
# Synology Permission Discovery - cascadesDS (192.168.0.120)
|
|
# ----------------------------------------------------------------------------
|
|
# Runs on CS-SERVER via GuruRMM. Uses plink.exe (PuTTY) to SSH into the
|
|
# Synology and dump users, groups, share ACLs, and SMB share configs.
|
|
#
|
|
# Strictly read-only. No writes, no creates, no config changes.
|
|
# Output is captured and printed to stdout for the RMM command to return.
|
|
#
|
|
# Prepared: 2026-04-22 (Cascades Phase 4 Synology retirement prep)
|
|
# ============================================================================
|
|
|
|
$ErrorActionPreference = 'Continue'
|
|
$SynoHost = '192.168.0.120'
|
|
$SynoUser = 'admin'
|
|
# Password injected via command substitution at execution time.
|
|
# Do NOT hardcode here - see the submission wrapper.
|
|
$SynoPass = '__SYNO_PASSWORD__'
|
|
|
|
function Section($n) {
|
|
Write-Output ''
|
|
Write-Output ('=' * 72)
|
|
Write-Output "== $n"
|
|
Write-Output ('=' * 72)
|
|
}
|
|
|
|
# ----------------------------------------------------------------------------
|
|
Section 'Step 1: Connectivity'
|
|
# ----------------------------------------------------------------------------
|
|
$reach = Test-NetConnection -ComputerName $SynoHost -Port 22 -InformationLevel Detailed -WarningAction SilentlyContinue
|
|
Write-Output "SSH 192.168.0.120:22 reachable: $($reach.TcpTestSucceeded)"
|
|
if (-not $reach.TcpTestSucceeded) {
|
|
Write-Output 'ABORT: Cannot reach Synology over SSH. Check pfSense rules + Synology service state.'
|
|
exit 1
|
|
}
|
|
|
|
# ----------------------------------------------------------------------------
|
|
Section 'Step 2: Locate plink.exe'
|
|
# ----------------------------------------------------------------------------
|
|
$plink = $null
|
|
$candidates = @(
|
|
'C:\Program Files\PuTTY\plink.exe',
|
|
'C:\Program Files (x86)\PuTTY\plink.exe',
|
|
'C:\Tools\plink.exe'
|
|
)
|
|
foreach ($c in $candidates) { if (Test-Path $c) { $plink = $c; break } }
|
|
if (-not $plink) {
|
|
$plink = (Get-Command plink.exe -ErrorAction SilentlyContinue | Select-Object -First 1).Source
|
|
}
|
|
if (-not $plink) {
|
|
Write-Output 'ABORT: plink.exe not found. Install PuTTY or point at a plink.exe path.'
|
|
exit 1
|
|
}
|
|
Write-Output "plink.exe: $plink"
|
|
$plinkVer = & $plink -V 2>&1 | Select-Object -First 1
|
|
Write-Output "plink version: $plinkVer"
|
|
|
|
# ----------------------------------------------------------------------------
|
|
Section 'Step 3: Pre-accept SSH host key (first run)'
|
|
# ----------------------------------------------------------------------------
|
|
# plink with -batch refuses unknown host keys. Pre-accept by piping 'y' into a
|
|
# non-batch run that does a harmless probe. Subsequent calls use -batch.
|
|
$preaccept = 'y' | & $plink -ssh -pw $SynoPass "$SynoUser@$SynoHost" 'echo preaccept-ok' 2>&1
|
|
Write-Output ($preaccept -join "`n")
|
|
|
|
# ----------------------------------------------------------------------------
|
|
Section 'Step 4: Synology probe - identity + shares + ACLs'
|
|
# ----------------------------------------------------------------------------
|
|
# Single heredoc-style payload: one SSH session, captures everything.
|
|
# synogroup/synouser/synoacltool/synoshare often need sudo on DSM 7; admin is
|
|
# in administrators group but sudo may still prompt. Use 'sudo -S' with the
|
|
# password piped via echo to handle the prompt gracefully.
|
|
$probe = @'
|
|
PASS="__SUDO_PASSWORD__"
|
|
sudo_run() { echo "$PASS" | sudo -S -p '' "$@" 2>&1; }
|
|
|
|
echo "### date ###"
|
|
date
|
|
echo
|
|
echo "### dsm version ###"
|
|
cat /etc.defaults/VERSION 2>&1 || cat /etc/VERSION 2>&1
|
|
echo
|
|
echo "### synogroup --list ###"
|
|
sudo_run synogroup --list
|
|
echo
|
|
echo "### synogroup --enum global ###"
|
|
sudo_run synogroup --enum global
|
|
echo
|
|
echo "### synouser --enum all ###"
|
|
sudo_run synouser --enum all
|
|
echo
|
|
echo "### /volume1/ directory listing ###"
|
|
ls -la /volume1/ 2>&1
|
|
echo
|
|
echo "### /etc/samba/smb.share.conf ###"
|
|
sudo_run cat /etc/samba/smb.share.conf 2>&1 | head -200
|
|
echo
|
|
echo "### synoshare --enum all ###"
|
|
sudo_run synoshare --enum all
|
|
echo
|
|
for S in homes Management SalesDept Server chat Public Culinary IT Receptionist directoryshare Marketing; do
|
|
if [ -d /volume1/$S ]; then
|
|
echo "### synoshare --get $S ###"
|
|
sudo_run synoshare --get "$S"
|
|
echo
|
|
echo "### synoacltool -get /volume1/$S ###"
|
|
sudo_run synoacltool -get "/volume1/$S"
|
|
echo
|
|
echo "### ls -la /volume1/$S (first 15 entries) ###"
|
|
ls -la "/volume1/$S" 2>&1 | head -15
|
|
echo
|
|
fi
|
|
done
|
|
echo "### NET SESSIONS / SMB share access (smbstatus) ###"
|
|
sudo_run smbstatus -p 2>&1 | head -20
|
|
echo
|
|
echo "### EOF ###"
|
|
'@
|
|
|
|
# Splice in the sudo password (same as SSH password for admin account)
|
|
$probe = $probe -replace '__SUDO_PASSWORD__', [regex]::Escape($SynoPass) -replace '\\/','/'
|
|
# Proper way: use literal replacement without regex escape tricks
|
|
$probe = $probe.Replace('__SUDO_PASSWORD__', $SynoPass)
|
|
|
|
# Execute via plink; batch mode since host key is now cached
|
|
$result = $probe | & $plink -ssh -batch -pw $SynoPass "$SynoUser@$SynoHost" 'bash -s' 2>&1
|
|
$result | ForEach-Object { Write-Output $_ }
|
|
|
|
# ----------------------------------------------------------------------------
|
|
Section 'Done'
|
|
# ----------------------------------------------------------------------------
|
|
Write-Output "Completed at $(Get-Date)"
|