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>
167 lines
7.2 KiB
PowerShell
167 lines
7.2 KiB
PowerShell
# ============================================================================
|
|
# Synology Permission Discovery via DSM API - cascadesDS (192.168.0.120)
|
|
# ----------------------------------------------------------------------------
|
|
# Runs on CS-SERVER via GuruRMM. Uses DSM's HTTP API (port 5000) instead of
|
|
# SSH since SSH is not enabled on this Synology.
|
|
#
|
|
# Strictly read-only. Login -> list users/groups/shares -> per-share
|
|
# permissions -> logout.
|
|
#
|
|
# Prepared: 2026-04-22 (Cascades Phase 4 Synology retirement prep)
|
|
# ============================================================================
|
|
|
|
$ErrorActionPreference = 'Continue'
|
|
$SynoBase = 'http://192.168.0.120:5000'
|
|
$SynoUser = 'admin'
|
|
$SynoPass = '__SYNO_PASSWORD__'
|
|
|
|
function Section($n) {
|
|
Write-Output ''
|
|
Write-Output ('=' * 72)
|
|
Write-Output "== $n"
|
|
Write-Output ('=' * 72)
|
|
}
|
|
|
|
function Dump($label, $obj) {
|
|
Write-Output ''
|
|
Write-Output "--- $label ---"
|
|
try {
|
|
$obj | ConvertTo-Json -Depth 8 | Write-Output
|
|
} catch {
|
|
$obj | Format-List * | Out-String | Write-Output
|
|
}
|
|
}
|
|
|
|
# TLS changes queued for tonight but not yet effective (reboot @ 18:00). This
|
|
# talks HTTP port 5000 so TLS state doesn't matter here.
|
|
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
|
|
|
|
# ----------------------------------------------------------------------------
|
|
Section 'Step 0: API version discovery'
|
|
# ----------------------------------------------------------------------------
|
|
try {
|
|
$info = Invoke-RestMethod -Uri "$SynoBase/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth,SYNO.Core.User,SYNO.Core.Group,SYNO.Core.Share,SYNO.Core.Share.Permission,SYNO.Core.Group.Member"
|
|
Dump 'SYNO.API.Info' $info
|
|
} catch {
|
|
Write-Output "API info probe failed: $_"
|
|
exit 1
|
|
}
|
|
|
|
# Derive authenticate path + max version
|
|
$authPath = $info.data.'SYNO.API.Auth'.path
|
|
$authMax = $info.data.'SYNO.API.Auth'.maxVersion
|
|
Write-Output "auth path: $authPath, maxVersion: $authMax"
|
|
|
|
# ----------------------------------------------------------------------------
|
|
Section 'Step 1: Login'
|
|
# ----------------------------------------------------------------------------
|
|
$loginUri = "$SynoBase/webapi/$authPath" +
|
|
"?api=SYNO.API.Auth&version=$authMax&method=login" +
|
|
"&account=$([uri]::EscapeDataString($SynoUser))" +
|
|
"&passwd=$([uri]::EscapeDataString($SynoPass))" +
|
|
"&session=FileStation&format=sid"
|
|
try {
|
|
$loginResp = Invoke-RestMethod -Uri $loginUri
|
|
Dump 'login response' $loginResp
|
|
if (-not $loginResp.success) {
|
|
Write-Output "LOGIN FAILED: $($loginResp | ConvertTo-Json -Depth 5)"
|
|
exit 1
|
|
}
|
|
$sid = $loginResp.data.sid
|
|
Write-Output "sid: $sid"
|
|
} catch {
|
|
Write-Output "Login exception: $_"
|
|
exit 1
|
|
}
|
|
|
|
try {
|
|
# ------------------------------------------------------------------------
|
|
Section 'Step 2: Users'
|
|
# ------------------------------------------------------------------------
|
|
# SYNO.Core.User list with all additional fields
|
|
$userResp = Invoke-RestMethod -Uri ("$SynoBase/webapi/entry.cgi?api=SYNO.Core.User&version=1&method=list" +
|
|
"&offset=0&limit=500&type=local" +
|
|
"&additional=%5B%22email%22%2C%22description%22%2C%22expired%22%2C%22cannot_chg_passwd%22%2C%22passwd_never_expire%22%2C%22passwd_last_change%22%2C%22passwd_must_change%22%2C%22groups%22%5D" +
|
|
"&_sid=$sid")
|
|
Dump 'SYNO.Core.User list' $userResp
|
|
|
|
# ------------------------------------------------------------------------
|
|
Section 'Step 3: Groups'
|
|
# ------------------------------------------------------------------------
|
|
$groupResp = Invoke-RestMethod -Uri ("$SynoBase/webapi/entry.cgi?api=SYNO.Core.Group&version=1&method=list" +
|
|
"&offset=0&limit=500&type=local" +
|
|
"&additional=%5B%22description%22%2C%22group_type%22%2C%22members%22%5D" +
|
|
"&_sid=$sid")
|
|
Dump 'SYNO.Core.Group list' $groupResp
|
|
|
|
# Group members (separate call in some DSM versions)
|
|
$groups = $groupResp.data.groups
|
|
foreach ($g in $groups) {
|
|
try {
|
|
$memResp = Invoke-RestMethod -Uri ("$SynoBase/webapi/entry.cgi?api=SYNO.Core.Group.Member&version=1&method=list" +
|
|
"&group_name=$([uri]::EscapeDataString($g.name))" +
|
|
"&offset=0&limit=500&_sid=$sid")
|
|
Dump "members of group '$($g.name)'" $memResp
|
|
} catch {
|
|
Write-Output "Group member lookup for '$($g.name)' failed: $_"
|
|
}
|
|
}
|
|
|
|
# ------------------------------------------------------------------------
|
|
Section 'Step 4: Shares'
|
|
# ------------------------------------------------------------------------
|
|
$shareResp = Invoke-RestMethod -Uri ("$SynoBase/webapi/entry.cgi?api=SYNO.Core.Share&version=1&method=list" +
|
|
"&shareType=all&offset=0&limit=200" +
|
|
"&additional=%5B%22hidden%22%2C%22encryption%22%2C%22share_quota%22%2C%22recyclebin%22%2C%22enable_share_cow%22%2C%22enable_share_compress%22%2C%22name%22%2C%22vol_path%22%2C%22desc%22%5D" +
|
|
"&_sid=$sid")
|
|
Dump 'SYNO.Core.Share list' $shareResp
|
|
|
|
# ------------------------------------------------------------------------
|
|
Section 'Step 5: Per-share permissions'
|
|
# ------------------------------------------------------------------------
|
|
$shares = $shareResp.data.shares
|
|
foreach ($sh in $shares) {
|
|
try {
|
|
# Permissions by user
|
|
$permUser = Invoke-RestMethod -Uri ("$SynoBase/webapi/entry.cgi?api=SYNO.Core.Share.Permission&version=1&method=list" +
|
|
"&name=$([uri]::EscapeDataString($sh.name))" +
|
|
"&user_group_type=local_user&offset=0&limit=500" +
|
|
"&_sid=$sid")
|
|
Dump "share '$($sh.name)' - local user permissions" $permUser
|
|
# Permissions by group
|
|
$permGroup = Invoke-RestMethod -Uri ("$SynoBase/webapi/entry.cgi?api=SYNO.Core.Share.Permission&version=1&method=list" +
|
|
"&name=$([uri]::EscapeDataString($sh.name))" +
|
|
"&user_group_type=local_group&offset=0&limit=500" +
|
|
"&_sid=$sid")
|
|
Dump "share '$($sh.name)' - local group permissions" $permGroup
|
|
} catch {
|
|
Write-Output "Permission lookup for '$($sh.name)' failed: $_"
|
|
}
|
|
}
|
|
|
|
# ------------------------------------------------------------------------
|
|
Section 'Step 6: SMB share config (supplementary)'
|
|
# ------------------------------------------------------------------------
|
|
# SMB exposure state per share via FileService.SMB.Share or similar
|
|
try {
|
|
$smb = Invoke-RestMethod -Uri "$SynoBase/webapi/entry.cgi?api=SYNO.Core.FileServ.SMB&version=1&method=get&_sid=$sid"
|
|
Dump 'SMB service config' $smb
|
|
} catch {
|
|
Write-Output "SMB service config lookup failed: $_"
|
|
}
|
|
|
|
} finally {
|
|
# ------------------------------------------------------------------------
|
|
Section 'Logout'
|
|
# ------------------------------------------------------------------------
|
|
try {
|
|
$logout = Invoke-RestMethod -Uri "$SynoBase/webapi/$authPath?api=SYNO.API.Auth&version=$authMax&method=logout&session=FileStation&_sid=$sid"
|
|
Dump 'logout' $logout
|
|
} catch {
|
|
Write-Output "Logout failed: $_"
|
|
}
|
|
}
|
|
|
|
Section 'Done'
|
|
Write-Output "Completed at $(Get-Date)"
|