Public/Remove-PatPlaylist.ps1

function Remove-PatPlaylist {
    <#
    .SYNOPSIS
        Removes a playlist from a Plex server.
 
    .DESCRIPTION
        Deletes a playlist from the Plex server. Can identify the playlist by ID or name.
        This action is irreversible - the playlist and its item associations will be
        permanently deleted.
 
    .PARAMETER PlaylistId
        The unique identifier of the playlist to remove.
 
    .PARAMETER PlaylistName
        The name of the playlist to remove. Supports tab completion.
 
    .PARAMETER ServerUri
        The base URI of the Plex server (e.g., http://plex.example.com:32400).
        If not specified, uses the default stored server.
 
    .PARAMETER PassThru
        If specified, returns the playlist object that was removed.
 
    .EXAMPLE
        Remove-PatPlaylist -PlaylistId 12345
 
        Removes the playlist with ID 12345 after confirmation.
 
    .EXAMPLE
        Remove-PatPlaylist -PlaylistName 'Old Playlist' -Confirm:$false
 
        Removes the playlist named 'Old Playlist' without confirmation prompt.
 
    .EXAMPLE
        Get-PatPlaylist -PlaylistName 'Temp*' | Remove-PatPlaylist
 
        Removes all playlists starting with 'Temp' via pipeline.
 
    .EXAMPLE
        Remove-PatPlaylist -PlaylistName 'Test Playlist' -WhatIf
 
        Shows what would be removed without actually removing it.
 
    .EXAMPLE
        Remove-PatPlaylist -PlaylistId 12345 -PassThru
 
        Removes the playlist and returns the removed playlist object for logging.
 
    .OUTPUTS
        PlexAutomationToolkit.Playlist (when -PassThru is specified)
 
        Returns the removed playlist object for auditing purposes.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSReviewUnusedParameter',
        'commandName',
        Justification = 'Standard ArgumentCompleter parameter, not always used'
    )]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSReviewUnusedParameter',
        'parameterName',
        Justification = 'Standard ArgumentCompleter parameter, not always used'
    )]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSReviewUnusedParameter',
        'commandAst',
        Justification = 'Standard ArgumentCompleter parameter, not always used'
    )]
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High', DefaultParameterSetName = 'ById')]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'ById', ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [ValidateRange(1, [int]::MaxValue)]
        [int]
        $PlaylistId,

        [Parameter(Mandatory = $true, ParameterSetName = 'ByName')]
        [ValidateNotNullOrEmpty()]
        [ArgumentCompleter({
            param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)

            $quoteChar = ''
            $strippedWord = $wordToComplete
            if ($wordToComplete -match "^([`"'])(.*)$") {
                $quoteChar = $Matches[1]
                $strippedWord = $Matches[2]
            }

            $getParams = @{ ErrorAction = 'SilentlyContinue' }
            if ($fakeBoundParameters.ContainsKey('ServerUri')) {
                $getParams['ServerUri'] = $fakeBoundParameters['ServerUri']
            }

            $playlists = Get-PatPlaylist @getParams

            foreach ($playlist in $playlists) {
                if ($playlist.Title -ilike "$strippedWord*") {
                    $title = $playlist.Title
                    if ($quoteChar) {
                        $text = "$quoteChar$title$quoteChar"
                    }
                    elseif ($title -match '\s') {
                        $text = "'$title'"
                    }
                    else {
                        $text = $title
                    }

                    [System.Management.Automation.CompletionResult]::new(
                        $text,
                        $title,
                        'ParameterValue',
                        $title
                    )
                }
            }
        })]
        [string]
        $PlaylistName,

        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({ Test-PatServerUri -Uri $_ })]
        [string]
        $ServerUri,

        [Parameter(Mandatory = $false)]
        [switch]
        $PassThru
    )

    begin {
        # Use default server if ServerUri not specified
        $server = $null
        $effectiveUri = $ServerUri
        if (-not $ServerUri) {
            try {
                $server = Get-PatStoredServer -Default -ErrorAction 'Stop'
                if (-not $server) {
                    throw "No default server configured. Use Add-PatServer with -Default or specify -ServerUri."
                }
                $effectiveUri = $server.uri
                Write-Verbose "Using default server: $effectiveUri"
            }
            catch {
                throw "Failed to get default server: $($_.Exception.Message)"
            }
        }
        else {
            Write-Verbose "Using specified server: $effectiveUri"
        }

        # Build headers with authentication
        $headers = if ($server) {
            Get-PatAuthHeaders -Server $server
        }
        else {
            @{ Accept = 'application/json' }
        }
    }

    process {
        try {
            # Resolve playlist ID if using name
            $resolvedId = $PlaylistId
            $playlistInfo = $null

            if ($PSCmdlet.ParameterSetName -eq 'ByName') {
                $playlist = Get-PatPlaylist -PlaylistName $PlaylistName -ServerUri $effectiveUri -ErrorAction 'Stop'
                if (-not $playlist) {
                    throw "No playlist found with name '$PlaylistName'"
                }
                $resolvedId = $playlist.PlaylistId
                $playlistInfo = $playlist
            }
            else {
                # Get playlist info for ShouldProcess message and PassThru
                try {
                    $playlistInfo = Get-PatPlaylist -PlaylistId $PlaylistId -ServerUri $effectiveUri -ErrorAction 'Stop'
                }
                catch {
                    Write-Verbose "Could not retrieve playlist info for ID $PlaylistId"
                }
            }

            # Build descriptive target for confirmation
            $target = if ($playlistInfo) {
                "'$($playlistInfo.Title)' (ID: $resolvedId, $($playlistInfo.ItemCount) items)"
            }
            else {
                "Playlist ID $resolvedId"
            }

            if ($PSCmdlet.ShouldProcess($target, 'Delete playlist')) {
                $endpoint = "/playlists/$resolvedId"
                $uri = Join-PatUri -BaseUri $effectiveUri -Endpoint $endpoint

                Write-Verbose "Deleting playlist $resolvedId from $effectiveUri"

                $null = Invoke-PatApi -Uri $uri -Method 'DELETE' -Headers $headers -ErrorAction 'Stop'

                if ($PassThru -and $playlistInfo) {
                    $playlistInfo
                }
            }
        }
        catch {
            throw "Failed to remove playlist: $($_.Exception.Message)"
        }
    }
}