У меня проблемы с FTP-скриптом Powershell. Я выдернул волосы из-за этого.
Недавно я установил «сервер автоматической сборки» для своих программных проектов. Все программные проекты собираются и объединяются в zip-файл. Теоретически этот zip-файл будет загружен через FTP на несколько разных серверов. Я пытаюсь создать сценарий PowerShell, который загрузит мой пакет и распакует его в нужные каталоги.
У меня проблема с загрузкой файла через FTP. Я могу получить доступ к исходному файлу, вручную войдя на FTP через командное окно DOS. Я могу загрузить файл без проблем, поэтому я знаю, что это не проблема брандмауэра. По крайней мере, я так не думаю.
Каждый раз, когда PowerShell начинает загрузку исходного файла .zip, он зависает. Я вижу, что файл появляется на жестком диске, но затем исчезает при сбое сценария. Он никогда не получает байтов от FTP-сервера. Затем я получаю эту ошибку:
Ошибка сценария FTP Powershell: удаленный сервер возвратил ошибку: 227 Переход в пассивный режим (10,255,130,77,231,5) Blockquote
Вот мой сценарий:
#create destination directory (this is where the build files will be dropped)
[IO.Directory]::CreateDirectory("C:\tempftp")
"Creating staging folder..."
#create staging folder for deployment package bundle unzip
[IO.Directory]::CreateDirectory("C:\FINALDEPLOYMENTFOLDER")
#create destination and source paths for FTP copy command
$File = "C:\tempftp\MyPackageT.zip"
$ftp = "ftp://AdminiUser:adm1n1pwd@255.255.255.255/MyPackage.zip"
"ftp url: $ftp"
$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftp)
"Downloading $File..."
#perform the actual data transfer via FTP
$webclient.DownloadFile($ftp, $File)
"Unzip build package..."
#unzip the file that was transferred via FTP
$shell_app=new-object -com shell.application
$zip_file = $shell_app.namespace("C:\tempftp\MyPackage.zip") #source
$destination = $shell_app.namespace("C:\FINALDEPLOYMENTFOLDER") #final destination
#unzip to destination folder
foreach ($item in $zip_file.Items())
{
$destination.CopyHere($item, 16)
}
Я могу запустить этот сценарий локально на моем сервере сборки, и он работает нормально. Я знаю, что этот сценарий работает. Моя проблема в том, почему этот скрипт не работает на моих серверах без сборки? Почему пассивный режим является такой проблемой для этого сценария и как ее исправить? Я пробовал правила адресов FTP IPv4, изменения поддержки FTP Firewall и т.д. Но безуспешно.
Примечательно, что я вижу предупреждающее сообщение в разделе поддержки брандмауэра FTP в IIS7. Здесь утверждается:
Чтобы принимать пассивные подключения, когда вы используете FTP через SSL (FTPS) или когда ваш брандмауэр не фильтрует пакеты, настройте внешний IPv4-адрес вашего брандмауэра.
^ Я не уверен, что это на самом деле означает, но я попробую. Есть идеи, почему пассивный режим - такая боль в моей шее? Разве мне не следует использовать WebClient? Я действительно хочу избежать загрузки другой программы / патча, чтобы эта работа работала. Я бы предпочел эту работу в родном Powershell ... так что нет, я не могу использовать библиотеки FTP-клиента !!
**** РЕДАКТИРОВАТЬ: мне удалось решить эту проблему, открыв «Все порты» на моем брандмауэре, но это кажется немного пугающим. Есть ли предложения по отслеживанию того, какие порты необходимы, чтобы эта ошибка пассивного режима исчезла? У меня уже было правило, разрешающее несколько конкретных портов, которые я думал, что FTP использует .... но как я могу увидеть, какие порты мне нужно включить? **
Когда вы подключаетесь к FTP-сайту из командной строки, вы используете активный FTP (доступен только один), что намного более предсказуемо со стороны брандмауэра. Когда вы подключаетесь с помощью System.Net.WebClient
, вы подключаетесь с помощью PASV, который принимает случайный порт из заранее определенного доступного диапазона. Эти запросы останавливаются на вашем брандмауэре. Вы также можете попробовать открыть диапазон портов на брандмауэре, если вам нужно придерживаться PASV. В противном случае вам нужно выяснить, как указать использование активного FTP-соединения. Это невозможно сделать с помощью System.Net.WebClient
.
Взгляни на System.Net.FtpWebRequest
, он может делать то, что вы хотите. Я вижу есть UsePassive
свойство.