使用 PowerShell 使用 FTP 上传文件

我想使用 PowerShell 将带有 FTP 的文件传输到匿名 FTP 服务器。我不会使用任何额外的包裹。怎么做到的?

215594 次浏览

我不确定你是否能100% 防止脚本挂起或崩溃,因为有些事情超出了你的控制范围(如果服务器在上传中断电怎么办?)但这应该为你的开始提供一个坚实的基础:

# create the FtpWebRequest and configure it
$ftp = [System.Net.FtpWebRequest]::Create("ftp://localhost/me.png")
$ftp = [System.Net.FtpWebRequest]$ftp
$ftp.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$ftp.Credentials = new-object System.Net.NetworkCredential("anonymous","anonymous@localhost")
$ftp.UseBinary = $true
$ftp.UsePassive = $true
# read in the file to upload as a byte array
$content = [System.IO.File]::ReadAllBytes("C:\me.png")
$ftp.ContentLength = $content.Length
# get the request stream, and write the bytes into it
$rs = $ftp.GetRequestStream()
$rs.Write($content, 0, $content.Length)
# be sure to clean up after ourselves
$rs.Close()
$rs.Dispose()

还有一些其他的方法,我使用了下面的脚本:

$File = "D:\Dev\somefilename.zip";
$ftp = "ftp://username:password@example.com/pub/incoming/somefilename.zip";


Write-Host -Object "ftp url: $ftp";


$webclient = New-Object -TypeName System.Net.WebClient;
$uri = New-Object -TypeName System.Uri -ArgumentList $ftp;


Write-Host -Object "Uploading $File...";


$webclient.UploadFile($uri, $File);

并且可以使用以下命令对 Windows FTP 命令行实用工具运行脚本

ftp -s:script.txt

(查看 这篇文章)

以下关于 SO 的问题也回答了这个问题: 如何脚本 FTP 上传和下载?

我不会说这个方案比投票最多的方案更优雅... ... 但是这个方案本身很酷(至少在我看来是哈哈大笑) :

$server = "ftp.lolcats.com"
$filelist = "file1.txt file2.txt"


"open $server
user $user $password
binary
cd $dir
" +
($filelist.split(' ') | %{ "put ""$_""`n" }) | ftp -i -in

正如您所看到的,它使用小巧的内置 Windows FTP 客户端。简洁明了得多。是的,我真的用过这个,而且很管用!

Goyuix 的解决方案 非常好用,但是如前所述,它给我带来了这个错误: “在使用 HTTP 代理时,不支持请求的 FTP 命令。”

$ftp.UsePassive = $true之后添加这一行为我解决了这个问题:

$ftp.Proxy = $null;

您可以通过 PowerShell 简单地处理文件上传,如下所示。 完整的项目可以在 Github 这里获得 < a href = “ https://Github.com/edouardkombo/PowerShellftp”rel = “ nofollow”> https://Github.com/edouardkombo/powershellftp

#Directory where to find pictures to upload
$Dir= 'c:\fff\medias\'


#Directory where to save uploaded pictures
$saveDir = 'c:\fff\save\'


#ftp server params
$ftp = 'ftp://10.0.1.11:21/'
$user = 'user'
$pass = 'pass'


#Connect to ftp webclient
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)


#Initialize var for infinite loop
$i=0


#Infinite loop
while($i -eq 0){


#Pause 1 seconde before continue
Start-Sleep -sec 1


#Search for pictures in directory
foreach($item in (dir $Dir "*.jpg"))
{
#Set default network status to 1
$onNetwork = "1"


#Get picture creation dateTime...
$pictureDateTime = (Get-ChildItem $item.fullName).CreationTime


#Convert dateTime to timeStamp
$pictureTimeStamp = (Get-Date $pictureDateTime).ToFileTime()


#Get actual timeStamp
$timeStamp = (Get-Date).ToFileTime()


#Get picture lifeTime
$pictureLifeTime = $timeStamp - $pictureTimeStamp


#We only treat pictures that are fully written on the disk
#So, we put a 2 second delay to ensure even big pictures have been fully wirtten   in the disk
if($pictureLifeTime -gt "2") {


#If upload fails, we set network status at 0
try{


$uri = New-Object System.Uri($ftp+$item.Name)


$webclient.UploadFile($uri, $item.FullName)


} catch [Exception] {


$onNetwork = "0"
write-host $_.Exception.Message;
}


#If upload succeeded, we do further actions
if($onNetwork -eq "1"){
"Copying $item..."
Copy-Item -path $item.fullName -destination $saveDir$item


"Deleting $item..."
Remove-Item $item.fullName
}




}
}
}

我最近为 Powershell 编写了几个用于与 FTP 通信的函数,请参见 https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1。下面的第二个函数,您可以将整个本地文件夹发送到 FTP。模块中甚至还有递归删除/添加/读取文件夹和文件的函数。

#Add-FtpFile -ftpFilePath "ftp://myHost.com/folder/somewhere/uploaded.txt" -localFile "C:\temp\file.txt" -userName "User" -password "pw"
function Add-FtpFile($ftpFilePath, $localFile, $username, $password) {
$ftprequest = New-FtpRequest -sourceUri $ftpFilePath -method ([System.Net.WebRequestMethods+Ftp]::UploadFile) -username $username -password $password
Write-Host "$($ftpRequest.Method) for '$($ftpRequest.RequestUri)' complete'"
$content = $content = [System.IO.File]::ReadAllBytes($localFile)
$ftprequest.ContentLength = $content.Length
$requestStream = $ftprequest.GetRequestStream()
$requestStream.Write($content, 0, $content.Length)
$requestStream.Close()
$requestStream.Dispose()
}


#Add-FtpFolderWithFiles -sourceFolder "C:\temp\" -destinationFolder "ftp://myHost.com/folder/somewhere/" -userName "User" -password "pw"
function Add-FtpFolderWithFiles($sourceFolder, $destinationFolder, $userName, $password) {
Add-FtpDirectory $destinationFolder $userName $password
$files = Get-ChildItem $sourceFolder -File
foreach($file in $files) {
$uploadUrl ="$destinationFolder/$($file.Name)"
Add-FtpFile -ftpFilePath $uploadUrl -localFile $file.FullName -username $userName -password $password
}
}


#Add-FtpFolderWithFilesRecursive -sourceFolder "C:\temp\" -destinationFolder "ftp://myHost.com/folder/" -userName "User" -password "pw"
function Add-FtpFolderWithFilesRecursive($sourceFolder, $destinationFolder, $userName, $password) {
Add-FtpFolderWithFiles -sourceFolder $sourceFolder -destinationFolder $destinationFolder -userName $userName -password $password
$subDirectories = Get-ChildItem $sourceFolder -Directory
$fromUri = new-object System.Uri($sourceFolder)
foreach($subDirectory in $subDirectories) {
$toUri  = new-object System.Uri($subDirectory.FullName)
$relativeUrl = $fromUri.MakeRelativeUri($toUri)
$relativePath = [System.Uri]::UnescapeDataString($relativeUrl.ToString())
$lastFolder = $relativePath.Substring($relativePath.LastIndexOf("/")+1)
Add-FtpFolderWithFilesRecursive -sourceFolder $subDirectory.FullName -destinationFolder "$destinationFolder/$lastFolder" -userName $userName -password $password
}
}

这是我的超级酷的版本,因为它有一个进度条: -)

这是一个完全无用的功能,我知道,但它看起来仍然很酷 m/m/

$webclient = New-Object System.Net.WebClient
Register-ObjectEvent -InputObject $webclient -EventName "UploadProgressChanged" -Action { Write-Progress -Activity "Upload progress..." -Status "Uploading" -PercentComplete $EventArgs.ProgressPercentage } > $null


$File = "filename.zip"
$ftp = "ftp://user:password@server/filename.zip"
$uri = New-Object System.Uri($ftp)
try{
$webclient.UploadFileAsync($uri, $File)
}
catch  [Net.WebException]
{
Write-Host $_.Exception.ToString() -foregroundcolor red
}
while ($webclient.IsBusy) { continue }

另外,当我在想“它是不是停止工作了,还是只是我的 ASDL 连接速度太慢了?”

最简单的方法

使用 PowerShell 将二进制文件上传到 FTP 服务器的最简单方法是使用 WebClient.UploadFile:

$client = New-Object System.Net.WebClient
$client.Credentials =
New-Object System.Net.NetworkCredential("username", "password")
$client.UploadFile(
"ftp://ftp.example.com/remote/path/file.zip", "C:\local\path\file.zip")

高级选择

如果您需要一个更大的控制,该 WebClient不提供(如 TLS/SSL 加密等) ,使用 FtpWebRequest。简单的方法是使用 Stream.CopyToFileStream复制到 FTP 流:

$request = [Net.WebRequest]::Create("ftp://ftp.example.com/remote/path/file.zip")
$request.Credentials =
New-Object System.Net.NetworkCredential("username", "password")
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile


$fileStream = [System.IO.File]::OpenRead("C:\local\path\file.zip")
$ftpStream = $request.GetRequestStream()


$fileStream.CopyTo($ftpStream)


$ftpStream.Dispose()
$fileStream.Dispose()

进度监测

如果你需要监控上传过程,你必须自己把内容分块复制:

$request = [Net.WebRequest]::Create("ftp://ftp.example.com/remote/path/file.zip")
$request.Credentials =
New-Object System.Net.NetworkCredential("username", "password")
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile


$fileStream = [System.IO.File]::OpenRead("C:\local\path\file.zip")
$ftpStream = $request.GetRequestStream()


$buffer = New-Object Byte[] 10240
while (($read = $fileStream.Read($buffer, 0, $buffer.Length)) -gt 0)
{
$ftpStream.Write($buffer, 0, $read)
$pct = ($fileStream.Position / $fileStream.Length)
Write-Progress `
-Activity "Uploading" -Status ("{0:P0} complete:" -f $pct) `
-PercentComplete ($pct * 100)
}


$ftpStream.Dispose()
$fileStream.Dispose()

上传文件夹

如果要从文件夹上载所有文件,请参见
PowerShell 脚本将整个文件夹上传到 FTP

你可以使用这个函数:

function SendByFTP {
param (
$userFTP = "anonymous",
$passFTP = "anonymous",
[Parameter(Mandatory=$True)]$serverFTP,
[Parameter(Mandatory=$True)]$localFile,
[Parameter(Mandatory=$True)]$remotePath
)
if(Test-Path $localFile){
$remoteFile = $localFile.Split("\")[-1]
$remotePath = Join-Path -Path $remotePath -ChildPath $remoteFile
$ftpAddr = "ftp://${userFTP}:${passFTP}@${serverFTP}/$remotePath"
$browser = New-Object System.Net.WebClient
$url = New-Object System.Uri($ftpAddr)
$browser.UploadFile($url, $localFile)
}
else{
Return "Unable to find $localFile"
}
}

此函数通过 FTP发送指定的文件。 您必须使用以下参数调用该函数:

  • 默认情况下,userFTP = “匿名”或您的用户名
  • PassFTP = 默认情况下为“匿名”或您的密码
  • ServerFTP = FTP 服务器的 IP 地址
  • LocalFile = 要发送的文件
  • RemotePath = FTP 服务器上的路径

例如:

SendByFTP -userFTP "USERNAME" -passFTP "PASSWORD" -serverFTP "MYSERVER" -localFile "toto.zip" -remotePath "path/on/the/FTP/"

简单的解决方案,如果你可以安装旋度。

curl.exe -p --insecure  "ftp://<ftp_server>" --user "user:password" -T "local_file_full_path"