Ich möchte PowerShell verwenden, um Dateien mit FTP auf einen anonymen FTP-Server zu übertragen. Ich würde keine zusätzlichen Pakete verwenden. Wie?
Es darf kein Risiko bestehen, dass das Skript hängt oder abstürzt.
Ich möchte PowerShell verwenden, um Dateien mit FTP auf einen anonymen FTP-Server zu übertragen. Ich würde keine zusätzlichen Pakete verwenden. Wie?
Es darf kein Risiko bestehen, dass das Skript hängt oder abstürzt.
Antworten:
Ich bin nicht sicher, ob Sie das Skript zu 100% kugelsicher machen können, damit es nicht hängt oder abstürzt, da es Dinge gibt, die außerhalb Ihrer Kontrolle liegen (was ist, wenn der Server während des Uploads die Stromversorgung verliert?) - aber dies sollte eine solide Grundlage für den Einstieg bieten:
# 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()
Es gibt auch andere Möglichkeiten. Ich habe das folgende Skript verwendet:
$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);
Mit dem folgenden Befehl können Sie ein Skript für das Windows-FTP-Befehlszeilenprogramm ausführen
ftp -s:script.txt
(Lesen Sie diesen Artikel )
Die folgende Frage zu SO beantwortet auch diese Frage: Wie schreibe ich FTP-Uploads und -Downloads?
$uri
ein Fehler ausgegeben. Ich ziehe es vor, die Anmeldeinformationen auf dem Client $webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)
Ich werde nicht behaupten, dass dies eleganter ist als die Lösung mit den höchsten Stimmen ... aber das ist auf seine eigene Weise cool (zumindest in meinen Augen 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
Wie Sie sehen können, wird dieser dinky integrierte Windows-FTP-Client verwendet. Viel kürzer und unkomplizierter. Ja, ich habe das tatsächlich benutzt und es funktioniert!
Die einfachste Möglichkeit, eine Binärdatei mit PowerShell auf einen FTP-Server hochzuladen, ist die Verwendung von 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")
Wenn Sie eine bessere Kontrolle benötigen, die WebClient
diese nicht bietet (wie TLS / SSL-Verschlüsselung usw.), verwenden Sie FtpWebRequest
. Einfache Möglichkeit ist, einfach eine Kopie FileStream
zu FTP - Stream unter Verwendung von 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()
Wenn Sie den Upload-Fortschritt überwachen müssen, müssen Sie den Inhalt selbst in Blöcke kopieren:
$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()
Wenn Sie alle Dateien aus einem Ordner hochladen möchten, lesen Sie
PowerShell Script, um einen gesamten Ordner auf FTP hochzuladen
Ich habe kürzlich für Powershell verschiedene Funktionen für die Kommunikation mit FTP geschrieben, siehe https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1 . Mit der zweiten Funktion unten können Sie einen ganzen lokalen Ordner an FTP senden. Im Modul befinden sich sogar Funktionen zum rekursiven Entfernen / Hinzufügen / Lesen von Ordnern und Dateien.
#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
}
}
ReadAllBytes
liest die gesamte Datei in den Speicher. Das wird bei großen Dateien nicht funktionieren. Und es ist selbst für mittelgroße Dateien ineffizient.
Hier ist meine super coole Version, WEIL ES EINE PROGRESS BAR HAT :-)
Das ist eine völlig nutzlose Funktion, ich weiß, aber sie sieht immer noch cool aus \ 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 }
PS. Hilft sehr, wenn ich mich frage: "Hat es nicht mehr funktioniert oder ist es nur meine langsame ASDL-Verbindung?"
Sie können einfach das Hochladen von Dateien über PowerShell wie folgt durchführen. Das vollständige Projekt finden Sie auf Github unter 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
}
}
}
}
Die Lösung von Goyuix funktioniert hervorragend, aber wie dargestellt wird folgende Fehlermeldung angezeigt : "Der angeforderte FTP-Befehl wird bei Verwendung des HTTP-Proxys nicht unterstützt."
Das Hinzufügen dieser Zeile nach dem $ftp.UsePassive = $true
Beheben des Problems für mich:
$ftp.Proxy = $null;
Sie können diese Funktion verwenden:
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"
}
}
Diese Funktion sendet die angegebene Datei per FTP . Sie müssen die Funktion mit folgenden Parametern aufrufen:
Zum Beispiel :
SendByFTP -userFTP "USERNAME" -passFTP "PASSWORD" -serverFTP "MYSERVER" -localFile "toto.zip" -remotePath "path/on/the/FTP/"
Join-Path
URL auf diese Weise nicht verwenden . Join-Path
Verwendet standardmäßig Backslashes, während URL Schrägstriche verwendet. + Sie müssen auch URL-codieren userFTP
und passFTP
.