Public/Test-PatLibraryPath.ps1
|
function Test-PatLibraryPath { <# .SYNOPSIS Tests whether a path exists on the Plex server's filesystem. .DESCRIPTION Validates that a specified filesystem path exists and is accessible to the Plex server. Optionally validates that the path falls within a library section's configured root paths. This cmdlet is useful for pre-validating paths before calling Update-PatLibrary to ensure the path exists and will be scanned. .PARAMETER Path The absolute filesystem path to test (e.g., /mnt/media/Movies/NewMovie). .PARAMETER SectionId Optional library section ID. When provided, also validates that the path is under one of the section's configured root paths. .PARAMETER SectionName Optional library section name (e.g., "Movies"). When provided, also validates that the path is under one of the section's configured root paths. .PARAMETER ServerUri The base URI of the Plex server (e.g., http://plex.example.com:32400) If not specified, uses the default stored server. .EXAMPLE Test-PatLibraryPath -Path '/mnt/media/Movies/NewMovie' Tests whether the path exists on the Plex server. .EXAMPLE Test-PatLibraryPath -Path '/mnt/media/Movies/NewMovie' -SectionName 'Movies' Tests whether the path exists AND is under one of the Movies library's configured root paths. .EXAMPLE if (Test-PatLibraryPath -Path $path -SectionName 'Movies') { Update-PatLibrary -SectionName 'Movies' -Path $path -SkipPathValidation } Pre-validates a path before triggering a library scan. .OUTPUTS System.Boolean .NOTES Always returns $true or $false, never throws errors. Returns $true if the path exists (and optionally is within library bounds). Returns $false if the path doesn't exist, is outside library bounds, or if there's an error communicating with the server. Use -Verbose to see diagnostic information about why validation failed. #> [CmdletBinding(DefaultParameterSetName = 'PathOnly')] [OutputType([bool])] param ( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Mandatory = $false, ParameterSetName = 'ByName')] [ValidateNotNullOrEmpty()] [string] $SectionName, [Parameter(Mandatory = $false, ParameterSetName = 'ById')] [ValidateRange(1, [int]::MaxValue)] [int] $SectionId, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -notmatch '^https?://[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*(:[0-9]{1,5})?$') { throw "ServerUri must be a valid HTTP or HTTPS URL (e.g., http://plex.local:32400)" } $true })] [string] $ServerUri ) # Build parameters for internal calls $serverParams = @{} if ($ServerUri) { $serverParams['ServerUri'] = $ServerUri } # If section is specified, validate path is under a configured root if ($SectionName -or $SectionId) { try { $pathParams = $serverParams.Clone() if ($SectionName) { $pathParams['SectionName'] = $SectionName } else { $pathParams['SectionId'] = $SectionId } $libraryPaths = Get-PatLibraryPath @pathParams -ErrorAction 'Stop' if (-not $libraryPaths) { Write-Verbose "No configured paths found for the specified library section" return $false } # Check if Path is under any of the library's root paths $isUnderRoot = $false foreach ($libPath in $libraryPaths) { # Normalize paths for comparison (handle both / and \ separators) $normalizedPath = $Path -replace '\\', '/' $normalizedRoot = $libPath.path -replace '\\', '/' # Ensure root path ends with / for proper prefix matching if (-not $normalizedRoot.EndsWith('/')) { $normalizedRoot += '/' } # Check if path equals root or is under root if ($normalizedPath -eq ($normalizedRoot.TrimEnd('/')) -or $normalizedPath.StartsWith($normalizedRoot)) { $isUnderRoot = $true Write-Verbose "Path '$Path' is under library root '$($libPath.path)'" break } } if (-not $isUnderRoot) { $sectionIdentifier = if ($SectionName) { "'$SectionName'" } else { "ID $SectionId" } Write-Verbose "Path '$Path' is not under any configured root path for section $sectionIdentifier" return $false } } catch { Write-Verbose "Could not validate library paths: $($_.Exception.Message)" return $false } } # Test if the path exists on the Plex server try { # Get parent directory to check if path exists # We check the parent because the path itself might be a file $parentPath = $Path $lastSlash = [Math]::Max($Path.LastIndexOf('/'), $Path.LastIndexOf('\')) if ($lastSlash -gt 0) { $parentPath = $Path.Substring(0, $lastSlash) $targetName = $Path.Substring($lastSlash + 1) } else { # Root path - check directly $targetName = $null } $browseParams = $serverParams.Clone() $browseParams['Path'] = $parentPath $items = Get-PatLibraryChildItem @browseParams -ErrorAction 'Stop' if ($targetName) { # Check if the target exists in the parent directory $found = $items | Where-Object { $itemPath = if ($_.PSObject.Properties['path']) { $_.path } elseif ($_.PSObject.Properties['Path']) { $_.Path } else { $null } $itemTitle = if ($_.PSObject.Properties['title']) { $_.title } elseif ($_.PSObject.Properties['Title']) { $_.Title } else { $null } # Match by path ending or title if ($itemPath) { $normalizedItemPath = $itemPath -replace '\\', '/' $normalizedTargetPath = $Path -replace '\\', '/' $normalizedItemPath -eq $normalizedTargetPath } elseif ($itemTitle) { $itemTitle -eq $targetName } else { $false } } if ($found) { Write-Verbose "Path '$Path' exists on the Plex server" return $true } else { Write-Verbose "Path '$Path' was not found in parent directory '$parentPath'" return $false } } else { # Just checking if we can browse the path (root level) Write-Verbose "Path '$Path' is accessible on the Plex server" return $true } } catch { # If browsing fails, the path likely doesn't exist or isn't accessible Write-Verbose "Path '$Path' is not accessible: $($_.Exception.Message)" return $false } } |