You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell FTP下载异常求助:有权限仍触发550错误及本地权限拒绝

解决PowerShell FTP下载.810OUT文件的错误问题

错误原因分析

  • FTP 550错误:System.Net.FtpWebRequest的DownloadFile方法不支持直接使用通配符(如*.810OUT)指定多个文件,必须针对单个文件的完整URI发起下载请求。你的目录列表脚本能正常运行,是因为ListDirectoryDetails方法支持通配符过滤文件列表,但下载操作不支持。
  • 本地路径权限错误:你设置的$targetpath是一个目录路径,但IO.FileStream需要指定具体的文件名,直接传入目录会导致系统尝试将目录作为文件创建,从而触发权限拒绝错误。

修正后的完整脚本

结合你的目录列表逻辑,先获取目标目录下所有.810OUT文件的列表,再逐个下载到本地指定目录:

# 1. 定义获取FTP文件列表的函数
Function Get-FTPFileList { 
    Param (
        [System.Uri]$server,
        [string]$username,
        [string]$password,
        [string]$directory
    )

    try {
        # 拼接完整URI
        $uri =  "$server$directory" 
        $FTPRequest = [System.Net.FtpWebRequest]::Create($uri)
        $FTPRequest.Credentials = New-Object System.Net.NetworkCredential($username, $password)
        $FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails
        
        $FTPResponse = $FTPRequest.GetResponse() 
        $ResponseStream = $FTPResponse.GetResponseStream()
        $StreamReader = New-Object System.IO.StreamReader $ResponseStream  
        
        $files = New-Object System.Collections.ArrayList
        While ($fileLine = $StreamReader.ReadLine()) {
            # 提取文件名(根据FTP服务器返回的列表格式,取最后一段作为文件名)
            $fileName = ($fileLine -split '\s+')[-1]
            # 只保留.810OUT后缀的文件
            if ($fileName -like "*.810OUT") {
                [void]$files.Add($fileName)
            }
        }
    }
    catch {
        Write-Host -Message "获取文件列表失败: $($_.Exception.InnerException.Message)"
    }
    finally {
        # 确保资源被释放
        if ($StreamReader) { $StreamReader.Close() }
        if ($ResponseStream) { $ResponseStream.Close() }
        if ($FTPResponse) { $FTPResponse.Close() }
    }
    Return $files
}

# 2. 定义单个FTP文件下载函数
Function Download-FTPFile {
    Param (
        [System.Uri]$server,
        [string]$username,
        [string]$password,
        [string]$remoteFileName,
        [string]$localFilePath
    )

    try {
        $remoteUri = "$server$remoteFileName"
        $ftprequest = [System.Net.FtpWebRequest]::Create($remoteUri)
        $ftprequest.Credentials = New-Object System.Net.NetworkCredential($username,$password)
        $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
        $ftprequest.UseBinary = $true
        $ftprequest.KeepAlive = $false

        $ftpresponse = $ftprequest.GetResponse()
        $responsestream = $ftpresponse.GetResponseStream()

        # 创建本地文件流
        $targetfile = New-Object IO.FileStream ($localFilePath,[IO.FileMode]::Create)
        [byte[]]$readbuffer = New-Object byte[] 1024

        # 写入文件内容
        do {
            $readlength = $responsestream.Read($readbuffer,0,1024)
            $targetfile.Write($readbuffer,0,$readlength)
        } while ($readlength -ne 0)

        Write-Host "成功下载文件: $remoteFileName"
    }
    catch {
        Write-Host "下载文件失败 $remoteFileName : $($_.Exception.Message)"
    }
    finally {
        # 释放资源
        if ($targetfile) { $targetfile.Close() }
        if ($responsestream) { $responsestream.Close() }
        if ($ftpresponse) { $ftpresponse.Close() }
    }
}

# 3. 配置参数并执行下载
$server = 'ftp://1.1.1.1/' # 替换为实际FTP服务器地址
$username = "username"     # 替换为实际用户名
$password = "pswd"         # 替换为实际密码
$remoteDirectory = 'Orders/OutboxFolder/' # 目标远程目录
$localDirectory = "C:\Users\myname\Downloads\test" # 本地保存目录

# 确保本地目录存在,不存在则创建
if (-not (Test-Path -Path $localDirectory)) {
    New-Item -ItemType Directory -Path $localDirectory | Out-Null
}

# 获取远程目录下的.810OUT文件列表
$fileList = Get-FTPFileList -server $server -username $username -password $password -directory $remoteDirectory

# 逐个下载文件
foreach ($fileName in $fileList) {
    $localFilePath = Join-Path -Path $localDirectory -ChildPath $fileName
    Download-FTPFile -server $server -username $username -password $password -remoteFileName "$remoteDirectory$fileName" -localFilePath $localFilePath
}

关键修正点说明

  1. 拆分逻辑:先通过Get-FTPFileList获取所有符合条件的文件名,再循环调用Download-FTPFile逐个下载,避免使用通配符直接发起下载请求。
  2. 本地路径处理:使用Join-Path拼接本地目录和文件名,确保每个下载操作都指向具体的文件路径,而非目录。
  3. 资源释放:添加finally块确保所有流和响应对象被正确关闭,避免资源泄漏。
  4. 目录检查:提前检查本地目录是否存在,不存在则自动创建,避免因目录缺失导致的错误。

内容的提问来源于stack exchange,提问作者Milan Patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:50:32