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