# ============================================================================ # 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)"