Posh-SSH icon indicating copy to clipboard operation
Posh-SSH copied to clipboard

Get-SFTPChildItem does not list files on linux if path uses windows-like (\) delimiters

Open SCP002 opened this issue 1 year ago • 4 comments

Probably a bug: In v3.2.4, Get-SFTPChildItem no longer lists files in a directory if path is written like (note path separators):

Get-SFTPChildItem -SessionId $sess.SessionId -Path "\home\vlad\*"

In v3.2.3, Get-SFTPChildItem would return file list.

SCP002 avatar Oct 18 '24 10:10 SCP002

what server are you using that uses backslashes as path separators?

darkoperator avatar Oct 21 '24 21:10 darkoperator

Can you test this function to see if it will work? dont have a target where I can at the moment

function Get-SFTPChildItem
{
    [CmdletBinding(DefaultParameterSetName='Index')]
    param(
        [Parameter(Mandatory=$true,
                   ParameterSetName = 'Index',
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [Alias('Index')]
        [Int32[]]
        $SessionId,
        [Parameter(Mandatory=$true,
                   ParameterSetName = 'Session',
                   ValueFromPipeline=$true,
                   Position=0)]
        [Alias('Session')]
        [SSH.SFTPSession[]]
        $SFTPSession,
        [Parameter(Mandatory=$false,
                   Position=1)]
        [string]
        $Path = "",
        [Parameter(Mandatory=$false,
                   Position=2)]
        [Alias('Recursive')]
        [switch]
        $Recurse,
        [Parameter(Mandatory=$false,
                   Position=3)]
        [switch]
        $Directory,
        [Parameter(Mandatory=$false,
                   Position=4)]
        [switch]
        $File
     )
     Begin
     {
        function Get-SFTPItems
        {
            param($CurrentPath, $SFTPSession, [bool]$IsRecursive)
            
            try {
                Write-Verbose "Listing items in path: $CurrentPath"
                $items = $SFTPSession.Session.ListDirectory($CurrentPath)
                
                foreach ($item in $items) {
                    if (@('.','..') -notcontains $item.Name) {
                        if ((!$File -and !$Directory) -or ($File -and !$item.IsDirectory) -or ($Directory -and $item.IsDirectory))
                        {
                            $item
                        }
                        
                        if ($IsRecursive -and $item.IsDirectory) {
                            $subPath = Join-SFTPPath $CurrentPath $item.Name
                            Get-SFTPItems -CurrentPath $subPath -SFTPSession $SFTPSession -IsRecursive $true
                        }
                    }
                }
            }
            catch {
                Write-Error "Error listing items in $($CurrentPath): $_"
            }
        }

        function Split-SFTPPath
        {
            param([string]$Path)
            
            $Path = $Path -replace '\\', '/'
            if ($Path -eq '/') {
                return @('/', '')
            }
            
            if ($Path -match '^(.*)/([^/]+)$') {
                $parentPath = if ($Matches[1] -eq '') { '/' } else { $Matches[1] }
                return @($parentPath, $Matches[2])
            }
            else {
                return @('/', $Path)
            }
        }

        function Join-SFTPPath
        {
            param($Path1, $Path2)
            
            $Path1 = $Path1 -replace '\\', '/'
            $Path2 = $Path2 -replace '\\', '/'
            
            if ($Path1 -eq '/') {
                return "/$Path2"
            }
            else {
                return "$Path1/$Path2"
            }
        }

        $ToProcess = @()
        switch($PSCmdlet.ParameterSetName)
        {
            'Session'
            {
                $ToProcess = $SFTPSession
            }
            'Index'
            {
                foreach($session in $Global:SFTPSessions)
                {
                    if ($SessionId -contains $session.SessionId)
                    {
                        $ToProcess += $session
                    }
                }
            }
        }
     }
     Process
     {
        foreach($Sess in $ToProcess)
        {
            if ($Path -eq "") {
                $Path = $Sess.Session.WorkingDirectory
            }

            # Normalize path separators
            $Path = $Path -replace '\\', '/'

            # Handle wildcards
            if ($Path -like "*[*?]*") {
                $pathParts = Split-SFTPPath -Path $Path
                $parentPath = $pathParts[0]
                $leafPattern = $pathParts[1]
                
                $items = Get-SFTPItems -CurrentPath $parentPath -SFTPSession $Sess -IsRecursive $false
                $items | Where-Object { $_.Name -like $leafPattern } | ForEach-Object {
                    if ($_.IsDirectory) {
                        $dirPath = Join-SFTPPath $parentPath $_.Name
                        Get-SFTPItems -CurrentPath $dirPath -SFTPSession $Sess -IsRecursive $Recurse
                    } else {
                        $_
                    }
                }
            }
            else {
                # Regular path (including root)
                Get-SFTPItems -CurrentPath $Path -SFTPSession $Sess -IsRecursive $Recurse
            }
        }
     }
     End{}
}

darkoperator avatar Oct 21 '24 22:10 darkoperator

what server are you using that uses backslashes as path separators?

No, target machine uses normal linux-like path separators (/), command is executed from windows 11 targeting regular ubuntu server. You might ask why I used windows-like path separators to get contents of linux machine?

  • It was output from Split-Path cmdlet, which surprisingly converts slashes to backslashes.

Not trying to state this is a bug in new version, only saying such trick worked in v3.2.3 and dont work anymore in v3.2.4.

SCP002 avatar Oct 23 '24 07:10 SCP002

Can you test this function to see if it will work? dont have a target where I can at the moment

This one works, returning file list.

SCP002 avatar Oct 23 '24 07:10 SCP002