首页 文章

PowerShell FTP下载文件和子文件夹

提问于
浏览
6

我想写一个PowerShell脚本从我的FTP服务器下载 all filessubfolders . 我找到了从一个特定文件夹下载所有文件的脚本,但我也想下载子文件夹及其文件 .

#FTP Server Information - SET VARIABLES
$ftp = "ftp://ftp.abc.ch/" 
$user = 'abc' 
$pass = 'abc'
$folder = '/'
$target = "C:\LocalData\Powershell\"

#SET CREDENTIALS
$credentials = new-object System.Net.NetworkCredential($user, $pass)

function Get-FtpDir ($url,$credentials) {
    $request = [Net.WebRequest]::Create($url)
    $request.Method = [System.Net.WebRequestMethods+FTP]::ListDirectory
    if ($credentials) { $request.Credentials = $credentials }
    $response = $request.GetResponse()
    $reader = New-Object IO.StreamReader $response.GetResponseStream() 
    $reader.ReadToEnd()
    $reader.Close()
    $response.Close()
}

#SET FOLDER PATH
$folderPath= $ftp + "/" + $folder + "/"

$Allfiles=Get-FTPDir -url $folderPath -credentials $credentials
$files = ($Allfiles -split "`r`n")

$files 

$webclient = New-Object System.Net.WebClient 
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass) 
$counter = 0
foreach ($file in ($files | where {$_ -like "*.*"})){
    $source=$folderPath + $file  
    $destination = $target + $file 
    $webclient.DownloadFile($source, $target+$file)

    #PRINT FILE NAME AND COUNTER
    $counter++
    $counter
    $source
}

谢谢你的帮助 (:

3 回答

  • 2

    .NET框架或PowerShell对递归文件操作(包括下载)没有任何明确的支持 . 你必须自己实现递归:

    • 列出远程目录

    • 迭代条目,下载文件并递归到子目录(再次列出它们等)

    棘手的部分是识别子目录中的文件 . 使用.NET框架( FtpWebRequestWebClient )以便携方式无法做到这一点 . 遗憾的是,.NET框架不支持 MLSD 命令,这是在FTP协议中使用文件属性检索目录列表的唯一可移植方式 . 另见Checking if object on FTP server is file or directory .

    你的选择是:

    • 对文件名执行操作,该文件名肯定会对文件失败并对目录成功(反之亦然) . 即你可以尝试下载"name" . 如果成功,它是一个文件,如果失败,它就是一个目录 .

    • 您可能很幸运,在您的具体情况下,您可以通过文件名告诉目录中的文件(即所有文件都有扩展名,而子目录则没有)

    • 您使用长目录列表( LIST command = ListDirectoryDetails method)并尝试解析特定于服务器的列表 . 许多FTP服务器使用* nix样式列表,您可以在条目的最开头通过 d 识别目录 . 但是许多服务器使用不同的格式 . 以下示例使用此方法(假设为* nix格式)

    function DownloadFtpDirectory($url, $credentials, $localPath)
    {
        $listRequest = [Net.WebRequest]::Create($url)
        $listRequest.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails
        $listRequest.Credentials = $credentials
    
        $lines = New-Object System.Collections.ArrayList
    
        $listResponse = $listRequest.GetResponse()
        $listStream = $listResponse.GetResponseStream()
        $listReader = New-Object System.IO.StreamReader($listStream)
        while (!$listReader.EndOfStream)
        {
            $line = $listReader.ReadLine()
            $lines.Add($line) | Out-Null
        }
        $listReader.Dispose()
        $listStream.Dispose()
        $listResponse.Dispose()
    
        foreach ($line in $lines)
        {
            $tokens = $line.Split(" ", 9, [StringSplitOptions]::RemoveEmptyEntries)
            $name = $tokens[8]
            $permissions = $tokens[0]
    
            $localFilePath = Join-Path $localPath $name
            $fileUrl = ($url + $name)
    
            if ($permissions[0] -eq 'd')
            {
                if (!(Test-Path $localFilePath -PathType container))
                {
                    Write-Host "Creating directory $localFilePath"
                    New-Item $localFilePath -Type directory | Out-Null
                }
    
                DownloadFtpDirectory ($fileUrl + "/") $credentials $localFilePath
            }
            else
            {
                Write-Host "Downloading $fileUrl to $localFilePath"
    
                $downloadRequest = [Net.WebRequest]::Create($fileUrl)
                $downloadRequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
                $downloadRequest.Credentials = $credentials
    
                $downloadResponse = $downloadRequest.GetResponse()
                $sourceStream = $downloadResponse.GetResponseStream()
                $targetStream = [System.IO.File]::Create($localFilePath)
                $buffer = New-Object byte[] 10240
                while (($read = $sourceStream.Read($buffer, 0, $buffer.Length)) -gt 0)
                {
                    $targetStream.Write($buffer, 0, $read);
                }
                $targetStream.Dispose()
                $sourceStream.Dispose()
                $downloadResponse.Dispose()
            }
        }
    }
    

    使用如下功能:

    $credentials = New-Object System.Net.NetworkCredential("user", "mypassword") 
    $url = "ftp://ftp.example.com/directory/to/download/"
    DownloadFtpDirectory $url $credentials "C:\target\directory"
    

    代码是从C# Download all files and subdirectories through FTP中的C#示例翻译而来的 .


    如果要避免解析特定于服务器的目录列表格式的麻烦,请使用支持 MLSD 命令和/或解析各种 LIST 列表格式的第三方库;和递归下载 .

    例如,使用WinSCP .NET assembly,只需一次调用Session.GetFiles即可下载整个目录:

    # Load WinSCP .NET assembly
    Add-Type -Path "WinSCPnet.dll"
    
    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::Ftp
        HostName = "ftp.example.com"
        UserName = "user"
        Password = "mypassword"
    }
    
    $session = New-Object WinSCP.Session
    
    try
    {
        # Connect
        $session.Open($sessionOptions)
    
        # Download files
        $session.GetFiles("/directory/to/download/*", "C:\target\directory\*").Check()
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }
    

    在内部,如果服务器支持,WinSCP使用 MLSD 命令 . 如果没有,它使用 LIST 命令并支持许多不同的列表格式 .

    Session.GetFiles method默认是递归的 .

    (我是WinSCP的作者)

  • 3

    为了通过powerShell从FTP检索文件/文件夹我编写了一些函数,你甚至可以从FTP中获取隐藏的东西 .

    获取特定文件夹中的所有文件和子文件夹(甚至是隐藏文件夹)的示例:

    Get-FtpChildItem -ftpFolderPath "ftp://myHost.com/root/leaf/" -userName "User" -password "pw" -Directory -File
    

    您只需复制以下模块中的函数,而无需安装任何第3个库:https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

  • 0

    AstralisSomnium

    为了通过powerShell从FTP检索文件/文件夹我编写了一些函数,你甚至可以从FTP中获取隐藏的东西 . 获取特定文件夹中的所有文件和子文件夹(甚至隐藏文件夹)的示例:Get-FtpChildItem -ftpFolderPath“ftp://myHost.com/root/leaf/” - userName“User”-password“pw”-Directory -File您只需复制以下模块中的函数,无需安装任何第3个库:https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

    是的,但是我在哪里写下载文件的目的地?

    Martin Prikryl

    您可能很幸运,在您的具体情况下,您可以通过文件名告诉目录中的文件(即所有文件都有扩展名,而子目录则没有)

    我认为使用此选项,但是我可以制作类似“ . *”的内容来选择所有扩展名吗?

相关问题