Public/ApiKeys/Set-JIMApiKey.ps1

# Copyright (c) Tetron Limited. All rights reserved.
# Licensed under the Tetron Commercial License. See LICENSE file in the project root.

function Set-JIMApiKey {
    <#
    .SYNOPSIS
        Updates an existing API Key in JIM.
 
    .DESCRIPTION
        Updates an API Key's name, description, roles, expiry, or enabled status.
        The key value itself cannot be changed.
 
    .PARAMETER Id
        The unique identifier (GUID) of the API Key to update.
 
    .PARAMETER Name
        The new name.
 
    .PARAMETER Description
        The new description.
 
    .PARAMETER RoleIds
        The IDs of the Roles the API Key has, replacing those it had. Omit it to keep its Roles.
 
    .PARAMETER ExpiresAt
        When the API Key expires. $null removes the expiry.
 
    .PARAMETER Enable
        Enables the API Key.
 
    .PARAMETER Disable
        Disables the API Key without removing it.
 
    .PARAMETER ChangeReason
        Optional reason for the change, recorded on the audit Activity and shown in the API Key's
        Configuration Change History.
 
    .PARAMETER PassThru
        Returns the API Key as updated.
 
    .OUTPUTS
        With -PassThru, the API Key as updated; otherwise nothing.
 
    .EXAMPLE
        Set-JIMApiKey -Id $keyId -Name "New Name" -PassThru
 
        Updates the API Key name and returns the result.
 
    .EXAMPLE
        Set-JIMApiKey -Id $keyId -Disable
 
        Disables the API Key.
 
    .EXAMPLE
        Set-JIMApiKey -Id $keyId -Enable -ExpiresAt (Get-Date).AddDays(90)
 
        Enables the API Key and sets a new expiry date.
 
    .EXAMPLE
        Get-JIMApiKey | Where-Object { $_.name -like "Test*" } | Set-JIMApiKey -Disable
 
        Disables all API Keys with names starting with "Test".
 
    .LINK
        Get-JIMApiKey
        New-JIMApiKey
        Remove-JIMApiKey
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType('JIM.ApiKeyDto')]
    param(
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [Guid]$Id,

        [string]$Name,

        [string]$Description,

        [int[]]$RoleIds,

        [Nullable[datetime]]$ExpiresAt,

        [switch]$Enable,

        [switch]$Disable,

        [ValidateNotNullOrEmpty()]
        [string]$ChangeReason,

        [switch]$PassThru
    )

    process {
        # Check connection first
        if (-not $script:JIMConnection) {
            Write-Error "You are not connected to JIM. Run Connect-JIM -Url <your JIM URL> to authenticate, then try again."
            return
        }

        if ($Enable -and $Disable) {
            Write-Error "Cannot specify both -Enable and -Disable"
            return
        }

        if ($PSCmdlet.ShouldProcess($Id, "Update API Key")) {
            Write-Verbose "Updating API Key: $Id"

            # Get existing key to preserve values not being updated
            $existing = Invoke-JIMApi -Endpoint "/api/v1/apikeys/$Id"
            if (-not $existing) {
                Write-Error "API Key not found: $Id"
                return
            }

            # Assigned through a typed variable in a plain statement: an if-expression's output is
            # enumerated on assignment, which collapses a one-element array to a scalar and @() to
            # $null, and ConvertTo-Json then sends {"roleIds":3} / null instead of [3] / [] (#1531).
            # Named distinctly from the $RoleIds parameter: variable names are case-insensitive, so
            # a local $roleIds would overwrite the bound value.
            [int[]]$roleIdsToSend = @()
            if ($PSBoundParameters.ContainsKey('RoleIds')) {
                $roleIdsToSend = $RoleIds
            } else {
                $roleIdsToSend = @($existing.roles | ForEach-Object { $_.id })
            }

            $body = @{
                name = if ($Name) { $Name } else { $existing.name }
                description = if ($PSBoundParameters.ContainsKey('Description')) { $Description } else { $existing.description }
                roleIds = $roleIdsToSend
                isEnabled = $existing.isEnabled
            }

            if ($PSBoundParameters.ContainsKey('ExpiresAt')) {
                $body.expiresAt = if ($ExpiresAt) { $ExpiresAt.ToUniversalTime().ToString('o') } else { $null }
            } else {
                $body.expiresAt = $existing.expiresAt
            }

            if ($Enable) {
                $body.isEnabled = $true
            } elseif ($Disable) {
                $body.isEnabled = $false
            }

            if ($ChangeReason) {
                $body.changeReason = $ChangeReason
            }

            try {
                $response = Invoke-JIMApi -Endpoint "/api/v1/apikeys/$Id" -Method 'PUT' -Body $body

                Write-Verbose "Updated API Key: $Id"

                if ($PassThru) {
                    $response
                }
            }
            catch {
                Write-Error "Failed to update API Key: $_"
            }
        }
    }
}