Public/Storage/Set-VergeNASUser.ps1

function Set-VergeNASUser {
    <#
    .SYNOPSIS
        Modifies an existing local user on a NAS service in VergeOS.

    .DESCRIPTION
        Set-VergeNASUser updates the settings of an existing NAS local user account.
        Only the specified parameters will be modified. The username cannot be changed
        after creation.

    .PARAMETER NASUser
        A NAS user object from Get-VergeNASUser to modify.

    .PARAMETER NASServiceName
        The name of the NAS service containing the user.

    .PARAMETER NASServiceKey
        The unique key (ID) of the NAS service containing the user.

    .PARAMETER Name
        The username of the NAS user to modify.

    .PARAMETER Key
        The unique key (ID) of the NAS user to modify.

    .PARAMETER Password
        A new password for the user. Can be a SecureString or plain text string.

    .PARAMETER DisplayName
        The display name for the user.

    .PARAMETER Description
        A description of the user account.

    .PARAMETER HomeShare
        The name of a CIFS share to use as the user's home share.
        Use empty string to remove the home share.

    .PARAMETER HomeDrive
        The drive letter to map the home share to (e.g., "H").
        Must be a single letter A-Z. Use empty string to remove.

    .PARAMETER Enabled
        Enable or disable the user account.

    .PARAMETER PassThru
        Return the modified user object.

    .PARAMETER Server
        The VergeOS connection to use. Defaults to the current default connection.

    .EXAMPLE
        Set-VergeNASUser -NASServiceName "NAS01" -Name "backup" -Password (ConvertTo-SecureString "NewPass123!" -AsPlainText -Force)

        Changes the password for the backup user.

    .EXAMPLE
        Get-VergeNASUser -NASServiceName "NAS01" -Name "shareuser" | Set-VergeNASUser -DisplayName "Share Service User" -PassThru

        Updates the display name via pipeline and returns the modified user.

    .EXAMPLE
        Set-VergeNASUser -NASServiceName "NAS01" -Name "admin" -HomeShare "AdminDocs" -HomeDrive "Z"

        Sets the home share and drive letter for the admin user.

    .EXAMPLE
        Set-VergeNASUser -NASServiceName "NAS01" -Name "olduser" -Enabled $false

        Disables the user account.

    .OUTPUTS
        None by default. Verge.NASUser when -PassThru is specified.

    .NOTES
        Use Get-VergeNASUser to retrieve users.
        Use Enable-VergeNASUser and Disable-VergeNASUser for simple enable/disable operations.
        The username cannot be changed after creation.
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ByNASNameAndUserName')]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'ByObject')]
        [PSTypeName('Verge.NASUser')]
        [PSCustomObject]$NASUser,

        [Parameter(Mandatory, ParameterSetName = 'ByNASNameAndUserName')]
        [Parameter(Mandatory, ParameterSetName = 'ByNASNameAndUserKey')]
        [string]$NASServiceName,

        [Parameter(Mandatory, ParameterSetName = 'ByNASKeyAndUserName')]
        [Parameter(Mandatory, ParameterSetName = 'ByNASKeyAndUserKey')]
        [int]$NASServiceKey,

        [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByNASNameAndUserName')]
        [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByNASKeyAndUserName')]
        [ValidateNotNullOrEmpty()]
        [string]$Name,

        [Parameter(Mandatory, ParameterSetName = 'ByNASNameAndUserKey')]
        [Parameter(Mandatory, ParameterSetName = 'ByNASKeyAndUserKey')]
        [Alias('Id', 'UserKey')]
        [string]$Key,

        [Parameter()]
        [object]$Password,

        [Parameter()]
        [string]$DisplayName,

        [Parameter()]
        [ValidateLength(0, 2048)]
        [string]$Description,

        [Parameter()]
        [AllowEmptyString()]
        [string]$HomeShare,

        [Parameter()]
        [ValidatePattern('^[a-zA-Z]?$', ErrorMessage = 'Home drive must be a single letter A-Z or empty')]
        [AllowEmptyString()]
        [string]$HomeDrive,

        [Parameter()]
        [bool]$Enabled,

        [Parameter()]
        [switch]$PassThru,

        [Parameter()]
        [object]$Server
    )

    begin {
        # Resolve connection
        if (-not $Server) {
            $Server = $script:DefaultConnection
        }
        if (-not $Server) {
            throw [System.InvalidOperationException]::new(
                'Not connected to VergeOS. Use Connect-VergeOS to establish a connection.'
            )
        }
    }

    process {
        # Resolve the NAS user
        $targetUser = $null
        $targetService = $null

        switch -Wildcard ($PSCmdlet.ParameterSetName) {
            'ByObject' {
                $targetUser = $NASUser
                if (-not $Server -and $NASUser._Connection) {
                    $Server = $NASUser._Connection
                }
                # Get the service for home share resolution
                $targetService = Get-VergeNASService -Key $NASUser.NASServiceKey -Server $Server
            }
            'ByNASName*' {
                $targetService = Get-VergeNASService -Name $NASServiceName -Server $Server
                if (-not $targetService) {
                    Write-Error -Message "NAS service '$NASServiceName' not found." -ErrorId 'NASServiceNotFound'
                    return
                }
                if ($PSCmdlet.ParameterSetName -eq 'ByNASNameAndUserName') {
                    $targetUser = Get-VergeNASUser -NASServiceKey $targetService.Key -Name $Name -Server $Server
                }
                else {
                    $targetUser = Get-VergeNASUser -NASServiceKey $targetService.Key -Key $Key -Server $Server
                }
            }
            'ByNASKey*' {
                $targetService = Get-VergeNASService -Key $NASServiceKey -Server $Server
                if (-not $targetService) {
                    Write-Error -Message "NAS service with key '$NASServiceKey' not found." -ErrorId 'NASServiceNotFound'
                    return
                }
                if ($PSCmdlet.ParameterSetName -eq 'ByNASKeyAndUserName') {
                    $targetUser = Get-VergeNASUser -NASServiceKey $NASServiceKey -Name $Name -Server $Server
                }
                else {
                    $targetUser = Get-VergeNASUser -NASServiceKey $NASServiceKey -Key $Key -Server $Server
                }
            }
        }

        if (-not $targetUser) {
            $identifier = if ($Name) { $Name } elseif ($Key) { "Key $Key" } else { 'provided object' }
            Write-Error -Message "NAS user '$identifier' not found." -ErrorId 'NASUserNotFound' -Category ObjectNotFound
            return
        }

        # Build request body with only changed parameters
        $body = @{}

        if ($Password) {
            # Convert SecureString password if needed
            $plainPassword = if ($Password -is [System.Security.SecureString]) {
                [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
                    [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
                )
            }
            else {
                $Password.ToString()
            }
            $body['password'] = $plainPassword
        }

        if ($PSBoundParameters.ContainsKey('DisplayName')) {
            $body['displayname'] = $DisplayName
        }

        if ($PSBoundParameters.ContainsKey('Description')) {
            $body['description'] = $Description
        }

        if ($PSBoundParameters.ContainsKey('HomeShare')) {
            if ([string]::IsNullOrEmpty($HomeShare)) {
                # Clear the home share
                $body['home_share'] = $null
            }
            else {
                # Look up the CIFS share by name
                $shareQueryParams = @{
                    filter = "volume#service eq $($targetService.Key) and name eq '$HomeShare'"
                    fields = '$key,name'
                }
                Write-Verbose "Looking up home share '$HomeShare'"
                $shareResponse = Invoke-VergeAPI -Method GET -Endpoint 'volume_cifs_shares' -Query $shareQueryParams -Connection $Server

                $homeShareKey = $null
                if ($shareResponse -and $shareResponse.'$key') {
                    $homeShareKey = $shareResponse.'$key'
                }
                elseif ($shareResponse -is [array] -and $shareResponse.Count -gt 0) {
                    $homeShareKey = $shareResponse[0].'$key'
                }

                if (-not $homeShareKey) {
                    Write-Error -Message "Home share '$HomeShare' not found on NAS service '$($targetService.Name)'." -ErrorId 'HomeShareNotFound'
                    return
                }
                $body['home_share'] = $homeShareKey
            }
        }

        if ($PSBoundParameters.ContainsKey('HomeDrive')) {
            $body['home_drive'] = if ($HomeDrive) { $HomeDrive.ToUpper() } else { '' }
        }

        if ($PSBoundParameters.ContainsKey('Enabled')) {
            $body['enabled'] = $Enabled
        }

        # Check if there's anything to update
        if ($body.Count -eq 0) {
            Write-Warning "No parameters specified to update for NAS user '$($targetUser.Name)'"
            return
        }

        # Build description of changes
        $changes = ($body.Keys | Where-Object { $_ -ne 'password' }) -join ', '
        if ($body.ContainsKey('password')) {
            $changes = if ($changes) { "$changes, password" } else { 'password' }
        }

        if ($PSCmdlet.ShouldProcess("$($targetUser.Name) on $($targetUser.NASServiceName)", "Modify NAS User ($changes)")) {
            try {
                Write-Verbose "Updating NAS user '$($targetUser.Name)' (Key: $($targetUser.Key))"
                Invoke-VergeAPI -Method PUT -Endpoint "vm_service_users/$($targetUser.Key)" -Body $body -Connection $Server | Out-Null

                Write-Verbose "NAS user '$($targetUser.Name)' updated successfully"

                if ($PassThru) {
                    # Return the updated user
                    Start-Sleep -Milliseconds 500
                    Get-VergeNASUser -NASServiceKey $targetUser.NASServiceKey -Key $targetUser.Key -Server $Server
                }
            }
            catch {
                throw "Failed to update NAS user '$($targetUser.Name)': $($_.Exception.Message)"
            }
        }
    }
}