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 }
关键修正点说明
- 拆分逻辑:先通过
Get-FTPFileList获取所有符合条件的文件名,再循环调用Download-FTPFile逐个下载,避免使用通配符直接发起下载请求。 - 本地路径处理:使用
Join-Path拼接本地目录和文件名,确保每个下载操作都指向具体的文件路径,而非目录。 - 资源释放:添加
finally块确保所有流和响应对象被正确关闭,避免资源泄漏。 - 目录检查:提前检查本地目录是否存在,不存在则自动创建,避免因目录缺失导致的错误。
内容的提问来源于stack exchange,提问作者Milan Patel
相关产品推荐
相关产品推荐

