Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
SCP002 opened this issue Oct 18, 2024 · 4 comments

Comments

@SCP002
Copy link

SCP002 commented Oct 18, 2024

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.

@darkoperator
Copy link
Owner

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

@darkoperator
Copy link
Owner

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{}
}

@SCP002
Copy link
Author

SCP002 commented Oct 23, 2024

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
Copy link
Author

SCP002 commented Oct 23, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants