Загружать файлы с помощью FTP с помощью PowerShell
Я хочу использовать PowerShell для передачи файлов с FTP на анонимный FTP-сервер. Я бы не использовал никаких дополнительных пакетов. Как?
Не должно быть риска, что скрипт зависает или падает.
- Массовое преобразование фотографий в меньший размер?
- экземпляр с альтернативными учетными данными
- Использование Invoke-Command -ScriptBlock для функции с аргументами
- Лучший способ проверить, существует ли путь в PowerShell
- Изменение кодировки PowerShell по умолчанию для UTF-8
- Как сделать скрипт Powershell (или другой) для изменения разрешения экрана?
- Как запустить EXE-файл в PowerShell с параметрами с пробелами и кавычками
- Как заменить несколько строк в файле с помощью PowerShell
- Поиск текста на веб-страницах с указанием списка URL-адресов
- Какая версия PowerShell поставляется с Windows 7?
- Linux «Top» для Windows Powershell?
- Как установить PowerShell по умолчанию вместо cmd.exe
- $ string.Substring Индекс / длина исключения
Я не уверен, что вы можете на 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","[email protected]") $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:[email protected]/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?
Я не собираюсь утверждать, что это более элегантно, чем решение с наивысшим разрешением … но это classно (ну, по крайней мере, на мой взгляд, 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
Как вы можете видеть, он использует этот встроенный FTP-клиент Windows. Гораздо короче и прямолинейно. Да, я действительно использовал это, и он работает!
Недавно я написал для 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 }
}
Вы можете просто обрабатывать загрузки файлов через PowerShell, как это. Полный проект доступен на Github здесь 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 } } } }
Вот моя супер classная версия ПОТОМУ ЧТО ЭТО БУДЕТ ПРОГРЕСС 🙂
Я знаю, это совершенно бесполезная функция, но она все еще выглядит classной \ 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:[email protected]/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 }
PS. Помогает много, когда мне интересно: «Это прекратило работать, или это просто мое медленное соединение ASDL?»
Решение Goyuix отлично работает, но, как было представлено, оно дает мне эту ошибку: «Запрошенная команда FTP не поддерживается при использовании HTTP-прокси».
Добавление этой строки после $ftp.UsePassive = $true
исправило проблему для меня:
$ftp.Proxy = $null;
Самый тривиальный способ загрузки двоичного файла на FTP-сервер с помощью PowerShell – это использование 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 FileStream
в FTP с помощью Stream.CopyTo
:
$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) } $fileStream.CopyTo($ftpStream) $ftpStream.Dispose() $fileStream.Dispose()