Skip to main content

Join-MultiplePaths joins an ordered list of path segments using Join-Path to ensure cross-platform correctness. The function validates input and emits concise verbose messages for tracking. PowerShell Desktop 5.1 does not support Join-Path's -AdditionalChildPath parameter. This function provides equivalent functionality for all PowerShell editions.

function Join-MultiplePaths
{
    <#
    .SYNOPSIS
        Join multiple path segments into a single cross-platform path.

    .DESCRIPTION
        Join-MultiplePaths joins an ordered list of path segments using Join-Path to ensure
        cross-platform correctness. The function validates input and emits concise verbose
        messages for tracking.

        PowerShell Desktop 5.1 does not support Join-Path's -AdditionalChildPath parameter.
        This function provides equivalent functionality for all PowerShell editions.

    .PARAMETER Segments
        An array of path segments to join. At least one segment is required.

    .EXAMPLE
        Join-MultiplePaths -Segments @('C:\Users','Public','Documents','file.txt')

        Returns: C:\Users\Public\Documents\file.txt (on Windows)

    .EXAMPLE
        Join-MultiplePaths -Segments @('usr','local','bin')

        Returns: usr/local/bin (on macOS/Linux) or usr\local\bin (on Windows)

    .EXAMPLE
        $parts = @('usr','local','bin'); Join-MultiplePaths -Segments $parts

        Returns: usr/local/bin (on macOS/Linux) or usr\local\bin (on Windows)

    .EXAMPLE
        Join-MultiplePaths -Segments @($PSScriptRoot, 'Public', '*.ps1')

        Returns: /path/to/module/Public/*.ps1 (cross-platform)

    .NOTES
        Compatible with PowerShell Desktop 5.1 and PowerShell Core 6.2+.
    #>
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateScript({
                if ($null -eq $_) { throw 'Segments array cannot be null' }
                if ($_.Count -eq 0) { throw 'Segments array cannot be empty' }
                $validSegments = $_ | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
                if ($validSegments.Count -eq 0) { throw 'At least one non-empty segment is required' }
                return $true
            })]
        [string[]]$Segments
    )

    begin
    {
        $prefix = 'Join-MultiplePaths>'
    }

    process
    {
        # Filter out null, empty, or whitespace-only segments (same as ValidateScript validation)
        $validSegments = $Segments | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }

        # Join all segments using Join-Path with explicit parameters
        $currentPath = $validSegments[0]
        for ($i = 1; $i -lt $validSegments.Count; $i++)
        {
            $currentPath = Join-Path -Path $currentPath -ChildPath $validSegments[$i]
        }

        Write-Verbose "$prefix Joined $($validSegments.Count) segments: $currentPath"
        Write-Output $currentPath
    }
}