Форум системных администраторов: Загрузка папок на FTP (PoSh) - Форум системных администраторов

Перейти к содержимому

Страница 1 из 1
  • Вы не можете начинать новые темы
  • Вы не можете отвечать в этой теме

Загрузка папок на FTP (PoSh) именно папок, а не просто файлов Оценить тему: -----

#1 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

  Отправлено 20 July 2010 - 15:18

ТЗ: требуется средствами ПоШ обеспечить загрузку папок вместе с их содержимым с локального диска на ftp-сервер.

Я нашел скрипт и немного модифицировал:

Цитата

$clnt = new-object System.Net.WebClient
$creds = "LOGIN:PASSWORD"
$server = "Serveradress"
# в моем скрипте происходит выборка всех файлов из папки
foreach ($filename in Get-ChildItem C:\test) {
$url = "ftp://" + $creds + "@" + $server + "/backup/" + $filename
$destfile = $filename.fullname
write-host Get-FTPUpdate: Uploading $filename from $destdir to $server
#ну и собсно их загрузка на фтп
$clnt.UploadFile($url,$destfile )}


Но меня это немного не устраивает, так как, если в filename попадает имя папки, а не файла, то скрипт прекращается с ошибкой

Цитата

Исключение при вызове "UploadFile" с "test\test1" аргументами: "An exception occurred during a WebClient request."
В :строке:16 позиция:16
+ $clnt.UploadFile <<<< ($url,$destfile )}


Как вариант если только писать несколько циклов для каждой подпапки, но это очень громоздко и неуниверсально. Искал в и-нете, но не смог найти скрипта, чтобы копировать именно папки целиком с содержимым, без подключения доп. библиотек.

#2 Пользователь не на сайте   Kazun 

  • Активный участник
  • PipPipPip

Отправлено 20 July 2010 - 15:33

http://www.itcommunity.ru/blogs/sie-wl/arc...0/19/80565.aspx и уже вдумчиво читать про .NET классы из статьи.Есть решение от NetCmdlets (send-ftp) или искать сторонние библиотеки с заданными требованиями.

#3 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 20 July 2010 - 15:44

Просмотреть сообщениеKazun, 20.7.2010, 16:33, сказал(а):

http://www.itcommunity.ru/blogs/sie-wl/arc...0/19/80565.aspx и уже вдумчиво читать про .NET классы из статьи.Есть решение от NetCmdlets (send-ftp) или искать сторонние библиотеки с заданными требованиями.


Уже смотрел статью эту:
1. стандартный ftp.exe не умеет папки копировать
2. System.Net.WebRequest я как раз и использовал, он тоже ругается на папочки :D
3. send-ftp аналогично... понимает только имена файлов
4. ну а сторонние библиотеки как-то не хотелось бы подключать.

#4 Пользователь не на сайте   Kazun 

  • Активный участник
  • PipPipPip

Отправлено 20 July 2010 - 16:22

Если вам не охота самому писать скрипт,то воспользоваться консольной программой http://www.ncftp.com/ncftp/.
ncftpput –R –v –u "FTP" ftp.server.ru /remotefolderftp /localfolder

#5 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 20 July 2010 - 16:34

Ну я сделал тот скрипт, что выше приведен и использовал его как функцию, где аргументом была папка, содержимое которой надо копировать. Конечно не слишком громоздко, но я думал, что можно короче, потому и написал.

#6 Пользователь не на сайте   Kazun 

  • Активный участник
  • PipPipPip

Отправлено 20 July 2010 - 20:53

Может кому пригодится скрипт. Скрипт создает каркас папок с последующей загрузкой файлов.Проблем в скрипте очень много,но свою задачу выполняет.

1)Нет проверки на ошибки.
2)Нет возможности до качать файл.
3)Не проверяет существование уже созданного объекта на FTP.
4)Нет поддержки прокси.
5)Еще куча всего =)

Запуск:
./Send -local C:\123 -remote test -server ftp.test.ru -username ftp


param ($local="C:\Test",$remote="/",$server="localhost",$username="ftp",$password)

#Создание директории на FTP сервере.
function CreateFolder($newfolder,$parentfolder="")
{
	$request = [System.Net.FtpWebRequest]::Create("ftp://"+$server+$remote+$parentfolder+$newfolder)
	$request.Credentials = New-Object System.Net.NetworkCredential([System.String]$username , [System.String]$password)
	$request.UsePassive = $true
	$request.UseBinary = $true
	$request.KeepAlive = $false
	$request.Method = [System.Net.WebRequestMethods+FTP]::MakeDirectory
	$makeDirectoryResponse = $request.GetResponse()
}

#Загрузка файла на FTP сервер.
function UploadFiles($file,$pfolder,$destfile)
{
	$clnt = new-object System.Net.WebClient
	$creds = $username+":"+$password
	$url = "ftp://" + $creds + "@" + $server +$remote+$pfolder+"/"+$file
	Write-Debug "$file ftp://$server/$pfolder"
	$clnt.UploadFile($url,$destfile)
}

$rootfolder = Join-Path (Resolve-Path $local).Path "\"
$folder = (Get-Item $rootfolder).Name
if ($remote -ne "/") {$remote = "/" + $remote + "/"}

#Создание корневой директории(по умолчанию Test)на FTP сервере.
CreateFolder $folder

#Формируем список директорий с последующим созданием на FTP сервере.
Get-ChildItem $rootfolder -Recurse | Where-Object {$_.PsIsContainer} | ForEach-Object {
		$f = $_.fullname -replace [regex]::escape($rootfolder)
		if ($f -notmatch "\\")
		{
			CreateFolder $f ($folder+"/")
		}
		else 
		{
			$pf = (Split-Path $f) -replace '\\','/'
			$f = Split-Path $f -Leaf
			CreateFolder $f ($folder+"/"+$pf+"/")
		}
}

#Формируем список файлов с последующей загрузкой на FTP.
Get-ChildItem $rootfolder -Recurse | Where-Object {!$_.PsIsContainer} | ForEach-Object {
		$f = $_.fullname -replace [regex]::escape($rootfolder)
		UploadFiles (Split-Path $f -Leaf) ($folder + "/" + ((Split-Path $f) -replace '\\','/')+"/") $_.fullname
}


#7 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 20 July 2010 - 21:25

Хм.... то есть скрипт берет папочку C:\Test, смотрит ее содержимое, далее воссоздает на фтп-сервере аналогичную структуру папок (если таковые имеются внутри C:\Test) и после разливает файлы по категориям, как на локалхосте?

#8 Пользователь не на сайте   Kazun 

  • Активный участник
  • PipPipPip

Отправлено 20 July 2010 - 23:23

Просмотреть сообщениеFry, 20.7.2010, 22:25, сказал(а):

Хм.... то есть скрипт берет папочку C:\Test, смотрит ее содержимое, далее воссоздает на фтп-сервере аналогичную структуру папок (если таковые имеются внутри C:\Test) и после разливает файлы по категориям, как на локалхосте?

Именно так.

#9 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 21 July 2010 - 06:17

Спасибо большое за скрипт, поковыряю его посижу, может себе прикручу :D У меня уникальная коробочка от тренднета - она форматирует диски в ext2 и при этом доступ к ней только по FTP :D

#10 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 21 July 2010 - 15:31

Тоже поковырялся, сделал свой скриптик загрузки папки со всем ее содержимым на ФТП-сервер (ну для изучения языка посчитал недостаточным взять и тупо скопировть чужой :D):

$server = "xx.xx.xx.xx"
$base = "backup"
$clnt = new-object System.Net.WebClient
$creds = "user:password"
#Функция копирования папки на ФТП:
function CrDir {
	param ($url)
	$WR = [System.Net.FTPWebRequest]::Create($url)
	$WR.Credentials = New-Object System.Net.NetworkCredential("user", "password")
	$WR.UsePassive = $true
	$WR.UseBinary = $True
	$WR.KeepAlive = $false
	$WR.Method = [System.Net.WebRequestMethods+FTP]::MakeDirectory
	$WRResponse = $WR.GetResponse()
}
#Функция создания папки и кпирования файлов:
function upload {
param ($path)
foreach ($a in (Get-ChildItem $path  -Exclude *.*)) 
{
	$dest = "ftp://"+$server+"/"+$base
	$destcopy = "ftp://"+$creds + "@"+$server+"/"+$base
	$b = $a
	while ($b -ne $null) 
	{
		foreach ($c in $b) 
		{
			$dest = $dest+"/"+ $c.name
			CrDir ($dest)
			$destcopy = $destcopy+"/"+$c.name
			foreach ($k in (gci $c.fullname -force |where {$_.attributes -ne "Directory"}))
				{
				$copyname=$destcopy+"/"+$k.name
				$clnt.UploadFile($copyname,$k.fullname)
				}
			$b = (Get-ChildItem $c.fullname  -Exclude *.*) 
		}
	}
}
}
upload ("C:\1\")



Более примитивный может, зато мне так понятнее xDD

Правда скрипт в таком виде меня не устаривает до конца по причинам, указанным в посте выше:
1)Нет проверки на ошибки.
2)Не проверяет существование уже созданного объекта на FTP.

Как получить список файлов с фтп-сервера?

Я смог это сделать с помощью команды

Цитата

$server = "xx.xx.xx.xx"
$filename = "backup/subfolder"
$url = "ftp://"+$server+"/"+$filename
[System.Net.FtpWebRequest]$WR = [System.Net.WebRequest]::Create($url)
$WR.Method = [System.Net.WebRequestMethods+FTP]::ListDirectoryDetails
$WR.Proxy = $null
$WR.Credentials = New-Object System.Net.NetworkCredential("user", "password")
$WRStream = $WR.GetResponse();
$responseStream = $WRStream.GetResponseStream()
$readStream = new-object System.IO.StreamReader($responseStream, [System.Text.Encoding]::UTF8)
$FileList =$readStream.ReadToEnd()
$FileList = $FileList.Split("`n`r")
$FileList = $FileList | Where {-not $_.StartsWith("d")} | Where {$_.Contains("Dec 22 2005")} | %{ $_.SubString(49) }
foreach ($kl in $FileList)
{Write-Host $kl}


Мне на это выдает :

Цитата

drwxrwxrwx 3 user nobody 4096 Jul 22 06:47 2
drwxrwxrwx 2 user nobody 4096 Jul 22 06:47 3
drwxrwxrwx 5 nobody nobody 4096 Jul 21 08:15 EventLog
drwxrwxrwx 5 nobody nobody 4096 Jul 21 08:22 SystemState

там и вправду есть папки 2, 3, EventLog и SystemState
Но это просто строки! То есть оттуда имя просто так не выцарапать, только если в тупую брать например конец строки... Есть какой-нить способ получить список наподобие простой команды get-childitem на локалке? Чтобы была возможность работать с параметрами типа Name, Type и тп...

#11 Пользователь не на сайте   Kazun 

  • Активный участник
  • PipPipPip

Отправлено 21 July 2010 - 15:57

Цитата

Но это просто строки! То есть оттуда имя просто так не выцарапать, только если в тупую брать например конец строки... Есть какой-нить способ получить список наподобие простой команды get-childitem на локалке? Чтобы была возможность работать с параметрами типа Name, Type и тп...


Сделать свою обвязку,только ,как был это текстом так и будет,по другому нельзя.

"drwxrwxrwx 3 user nobody 4096 Jul 22 06:47 2" | select @{l='Name';e={$_.split()[-1]}},@{l="Type";e={$_.split()[0][0] }}
Name Type
---- ----
2	   d


И уже работать с полями Name,Type

#12 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 21 July 2010 - 22:53

Большое спасибо, Kazun! Буду ковыряться с этим! Вы мне очень помогаете постигать павершелл xD

#13 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 29 July 2010 - 16:40

Соорудил функцию, определяющую наличие определенных папок на ФТП сервере. Проблема именно в создании папок, так как если папка существует, то при попытке создать такую же выскакивает ошибка и скрипт прерывается. С файлами же проще - они просто перезаписываются поверх без ошибок.

function ifexist ($dest,$directory)
{
	[System.Net.FtpWebRequest]$WR = [System.Net.WebRequest]::Create($dest)
	$WR.Method = [System.Net.WebRequestMethods+FTP]::ListDirectoryDetails 
	$WR.UsePassive = $true
	$WR.UseBinary = $True
	$WR.KeepAlive = $false
	$WR.Proxy = $null
	$WR.Credentials = New-Object System.Net.NetworkCredential("user", "user")
	$WRStream = $WR.GetResponse()
	$responseStream = $WRStream.GetResponseStream()
	$readStream = new-object System.IO.StreamReader($responseStream, [System.Text.Encoding]::UTF8)
	$FileList =$readStream.ReadToEnd()
	$FileList = $FileList.Split("`n`r")# все что выше - вход на фтп-сервер и листинг находящихся там файлов и папок.
	$exist = $null
	while ($exist -eq $null) # сам цикл сверки имен папок на сервере и на локальной машине
	{	
		foreach ($k in $FileList)# $k - строчка вида "-rw-rw-rw-   1 nobody   nobody     865400 Jul 29 07:29 file"
	{
		$x = $k -split '[\s]+' # $x - из $k получили массив из слов -rw-rw-rw-, 1, nobody, nobody и тп
		if ($directory.Name -eq $x[8]) # сравниваем имя директории и последний элемент массива x, который и будет именем папки на фтп.
		{
			$exist=$true
			break
		} 
		else {$exist=$false} 
	}
	}
	$readStream.Close()
	$responseStream.Close()
	$WRStream.Close()
	return $exist # указывает, что результатом выполнения функции будет переменна $exist
}


Надеюсь, пригодится кому-нибудь, а еще лучше, чтобы его упростить\укоротить. Буду рад любым комментариям и критике тоже. Позже выложу более-менее причесанный скрипт по заливке папок на фтп вместе с их содержимым :)

Кстати с разбором строк на составные части и тп очень помогли статьи Xaegr'a. Почитать можно здесь: http://xaegr.wordpre...regexp-1-intro/

Сообщение изменено: Fry (29 July 2010 - 16:41 )


#14 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 29 July 2010 - 16:46

Вот выложу скрипт копировая папок со вложенными файлами и подпапками на ФТП. Там видно как туда всталена функция проверки существования папки на сервере (попозже распишу комментариями):

$server = "xxx.xxx.xxx.xxx" # адрес нашего сервера
$base = "BASE" #родительская папка на сервере, с которой начнем работу
$clnt = new-object System.Net.WebClient
$creds = "user:user" # логин:пароль для входа на фтп

# функция создания папки
function CrDir {
	param ($url)
	$WR = [System.Net.FTPWebRequest]::Create($url)
	$WR.Credentials = New-Object System.Net.NetworkCredential("user", "user")
	$WR.UsePassive = $true
	$WR.UseBinary = $True
	$WR.KeepAlive = $false
	$WR.Method = [System.Net.WebRequestMethods+FTP]::MakeDirectory
	$WRResponse = $WR.GetResponse()
	$WRResponse.Close()
}

# функция проверки наличия указанной папки на фтп
function ifexist
{
	[System.Net.FtpWebRequest]$WR = [System.Net.WebRequest]::Create($dest)
	$WR.Method = [System.Net.WebRequestMethods+FTP]::ListDirectoryDetails 
	$WR.UsePassive = $true
	$WR.UseBinary = $True
	$WR.KeepAlive = $false
	$WR.Proxy = $null
	$WR.Credentials = New-Object System.Net.NetworkCredential("user", "user")
	$WRStream = $WR.GetResponse()
	$responseStream = $WRStream.GetResponseStream()
	$readStream = new-object System.IO.StreamReader($responseStream, [System.Text.Encoding]::UTF8)
	$FileList =$readStream.ReadToEnd()
	$FileList = $FileList.Split("`n`r")
	$exist = $null
	while ($exist -eq $null)
	{	
		foreach ($kl in $FileList)
	{
		$x = $kl -split '[\s]+'
		if ($c.Name -eq $x[8]) 
		{
			$exist=$true
			break
		} 
		else {$exist=$false} 
	}
	}
	$readStream.Close()
	$responseStream.Close()
	$WRStream.Close()
	return $exist
}

# сама функция загрузки папок и файлов
function upload {
param ($path)
foreach ($a in (Get-ChildItem $path  -Exclude *.*)) # выбираем по очереди все папки в указанной директории (включая подпапки)
{
	$dest = "ftp://"+$server+"/"+$base
	$destcopy = "ftp://"+$creds + "@"+$server+"/"+$base
	$b = $a
	while ($b -ne $null) # пока папки не кончатся выполнять:
	{
		foreach ($c in $B) 
		{
			$exist = ifexist ($c,$dest)# вот сюда мы вставили функцию, проверяем наличие каждой папки по очереди на сервере
			if ($exist -eq $true) 
			{
				Write-host $c.name is already exist
				$dest = $dest+"/"+ $c.name
			} else
			{
				CrDir ($dest+"/"+ $c.name) # если нет папки, то создаем
				Write-Host $c.name directory created
				$dest = $dest+"/"+ $c.name # меняем путь на только что созданную папку и выполняем предыдущий цикл для нее, словно она родительская и тп.
			}
			$destcopy = $destcopy+"/"+$c.name
			foreach ($k in (gci $c.fullname -force |where {$_.attributes -ne "Directory"})) # выбираем из папок все объекты кроме папок (вообщем все файлы)
				{
				$copyname=$destcopy+"/"+$k.name
				$clnt.UploadFile($copyname,$k.fullname) # копируем файлы
				}
			$b = (Get-ChildItem $c.fullname  -Exclude *.*) 
		}
	}
}
}
upload ("C:\1\")

Сообщение изменено: Fry (29 July 2010 - 18:51 )


#15 Пользователь не на сайте   Kazun 

  • Активный участник
  • PipPipPip

Отправлено 29 July 2010 - 19:05

Все же кому надо работать с FTP,лучше воспользоваться CLI клиентом http://www.ncftp.com . По мощности и возможностям скрипт рядом не стоит.

#16 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 29 July 2010 - 19:31

Ну... все же вопрос стоял именно в написании скрипта powershell. Спасибо за помощь.

#17 Пользователь не на сайте   Kazun 

  • Активный участник
  • PipPipPip

Отправлено 29 July 2010 - 19:34

Просмотреть сообщениеFry, 29 July 2010 - 19:31 , сказал(а):

Ну... все же вопрос стоял именно в написании скрипта powershell. Спасибо за помощь.

Не только на вас свет клином сошелся,есть и другие.Кому надо эффективное и лучшее По во всех отношениях то лучше воспользоваться http://www.ncftp.com.

#18 Пользователь не на сайте   Fry 

  • Участник
  • PipPip

Отправлено 29 July 2010 - 19:41

Никто и не спорит, что ПО, написанное профессионалами для решения конкретной задачи, намного лучше скрипта любителя.

Страница 1 из 1
  • Вы не можете начинать новые темы
  • Вы не можете отвечать в этой теме

1 пользователей читают эту тему
0 зарегистрированных, 1 гостей, 0 скрытых