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