使用PowerShell使用FTP上载文件

mag*_*gol 68 ftp powershell

我想使用PowerShell将文件与FTP一起传输到匿名FTP服务器.我不会使用任何额外的包.怎么样?

脚本必须没有挂起或崩溃的风险.

Goy*_*uix 80

我不确定你是否可以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()
Run Code Online (Sandbox Code Playgroud)

  • 这些都是与PowerShell脚本编写有关的非常好的个别问题,并且可以应用于更多场景,而不仅仅是处理ftp事务.我的建议:在这里浏览PowerShell标签并阅读错误处理.在这个脚本中出现问题的大多数都会引发异常,只需将脚本包装在可以处理它的内容中. (15认同)
  • 我如何捕获错误?如果我无法连接怎么办?无法发送文件?连接断开?我想处理错误并通知用户。 (2认同)
  • 对于大型zip文件来说不是一个好方法.当我尝试"$ content = gc -en byte C:\ mybigfile.zip"时,powershell花了很长时间来处理.@CyrilGupta提出的解决方案对我来说效果更好. (2认同)

Cyr*_*pta 45

还有其他一些方法.我使用了以下脚本:

$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);
Run Code Online (Sandbox Code Playgroud)

您可以使用以下命令对Windows FTP命令行实用程序运行脚本

ftp -s:script.txt 
Run Code Online (Sandbox Code Playgroud)

(看看这篇文章)

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

  • 如果您的密码包含 URL 中不允许的字符,则创建 `$uri` 会引发错误。我更喜欢在客户端设置凭据:`$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)` (2认同)

Dex*_*spi 29

我不会声称这比最高投票的解决方案更优雅......但这很酷(嗯,至少在我看来LOL)以自己的方式:

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

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

如您所见,它使用了那个极简的内置Windows FTP客户端.也更短,更直接.是的,我实际上已经使用了它,它的确有效!

  • 而且,如果您曾经使用过其他类型的FTP,那么您只是在管道传输到其他程序。真好 (2认同)
  • 这有点棘手(如果您将用户_user_ _pass_分成三行,则不起作用,与使用脚本文件不同),并且没有文档说明(ftp中的-in开关是什么),但确实有效! (2认同)

Mar*_*ryl 7

最简单的方法

使用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")
Run Code Online (Sandbox Code Playgroud)

高级选项

如果您需要更大的控制权WebClient(例如TLS / SSL加密等),则无法使用,请使用FtpWebRequest。简单的方法是FileStream使用Stream.CopyTo以下命令将a复制到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()
Run Code Online (Sandbox Code Playgroud)

进度监控

如果需要监视上传进度,则必须自己逐块复制内容:

$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)
}

$fileStream.CopyTo($ftpStream)

$ftpStream.Dispose()
$fileStream.Dispose()
Run Code Online (Sandbox Code Playgroud)

上载资料夹

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


Ast*_*ium 6

我最近为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
}
Run Code Online (Sandbox Code Playgroud)

}