.NET VB FTPサーバーへファイル送信する際にPWDやOPTS等の特定コマンドを禁止されている場合の回避方法

最終更新日

.NET VBからFTPサーバーに接続するとき、「System.Net.FtpWebRequest」ライブラリを使用する場合が多いと思います。要件によってはFTPサーバー側でPWDやOPTSコマンドを禁止している場合がある。特にセキュリティ面でPUT(STORコマンド)やGET(RETRコマンド)のみ許可している場合は、PWDやOPTSコマンドも許可していないケースがあるので、その場合、.NET VBからFTPサーバーに接続する方法を記載しています。

結論としては、「System.Net.FtpWebRequest」ライブラリは使えないので、Windows標準のFTPコマンドをバッチ化し「.NET VB」から実行するという方法をとります。

vsftpdサーバーを利用している場合は、下記のコマンドで確認することができます。

$cat /var/log/vsftpd.log

.NET VBからFTPサーバーにファイル送信するソースコード

Dim urlFtp As New Uri(strFtpServerFilePath)
Dim ftpReq As System.Net.FtpWebRequest = CType(System.Net.WebRequest.Create(urlFtp), System.Net.FtpWebRequest)
'ログインユーザー名とパスワードを設定
ftpReq.Credentials = New System.Net.NetworkCredential(gstrFTPUser, gstrFTPPassWord)
'MethodにWebRequestMethods.Ftp.AppendFile("APPE")を設定
ftpReq.Method = System.Net.WebRequestMethods.Ftp.AppendFile
ftpReq.KeepAlive = False
ftpReq.UseBinary = False
ftpReq.UsePassive = False
ftpReq.Proxy = Nothing
Dim reqStrm As System.IO.Stream = ftpReq.GetRequestStream()
Dim fs As New System.IO.FileStream(strUpdFile, System.IO.FileMode.Open, System.IO.FileAccess.Read)
Dim buffer(999999999) As Byte
    While True
        Dim readSize As Integer = fs.Read(buffer, 0, buffer.Length)
        If readSize = 0 Then
            Exit While
        End If
        reqStrm.Write(buffer, 0, readSize)
    End While
fs.Close()
reqStrm.Close()
Dim ftpRes As System.Net.FtpWebResponse = CType(ftpReq.GetResponse(), System.Net.FtpWebResponse)

上記のソースコードでは、「System.Net.FtpWebRequest」ライブラリがFTPサーバーに接続しファイルをアップロードしています。その時、ライブラリは裏側で以下のFTPコマンドを実行しています。

USER、PASS、OPTS、PWD、TYPE、PORT、STOR、QUIT

もし、FTPサーバー側でコマンドを拒否する設定をしている場合は、プログラム内部で例外が発生してしまいます。

そこで、Windows標準のFTPコマンドを使用することで、PWDとOPTSを除いたコマンドだけでファイル送信することができます。

以下のコード、「.NET VB」から外部のプログラムを実行するソースコードです。

Dim processinfo = 
New ProcessStartInfo("cmd.exe", "/C " & 実行するコマンドパス(ftpsend.bat)) With 
    {.CreateNoWindow = True, .UseShellExecute = False, .WorkingDirectory = ""}

        Using proc = Process.Start(processinfo)
            proc.WaitForExit(5000)
            result = proc.ExitCode()
        End Using

ftpsend.batの処理内容

openコマンドでFTPサーバーに接続し、ユーザー名とパスワード、バイナリモードを設定してファイルを送信するという単純なバッチです。また、送信結果をログとして日時_ftpbat.logとして出力しています。

実行ログ内に「Ok to send data.」というワードが含まれていた場合は、ファイルのアップロードが正常のためバッチの実行結果に0をセットしています。正常にアップロードした以外は1を返すので、.NET VB側で0以外は例外の処理を書くと良いでしょう。

.NET VB実行時には、ホスト名とユーザー名、パスワード、送信するファイルパスをセットするだけです。

@echo off
rem FTPサーバー送信バッチ
rem ftpput.bat <host> <user> <password> <local-path> 
setlocal
set FTP_HOST=%1
set FTP_USER=%2
set FTP_PASSWORD=%3
set FTP_LOCAL_PATH=%4
set year=%date:~0,4%
set month=%date:~5,2%
set day=%date:~8,2%
set time2=%time: =0%
set hour=%time2:~0,2%
set minute=%time2:~3,2%
set second=%time2:~6,2%
set FTP_SCRIPT=ftpscript.txt
set FTP_SCRIPT_LOG=%year%%month%%day%%hour%%minute%%second%_ftpbat.log

rem FTPPUTコマンドのデフォルトの終了コードは1
set FTPPUT_EXITCODE=1

rem FTPコマンドに渡すためのスクリプトを作成
echo open %FTP_HOST%> %FTP_SCRIPT%
echo %FTP_USER%>> %FTP_SCRIPT%
echo %FTP_PASSWORD%>> %FTP_SCRIPT%
echo bin>> %FTP_SCRIPT%
echo send %FTP_LOCAL_PATH%>> %FTP_SCRIPT%
echo quit>> %FTP_SCRIPT%
ftp -s:%FTP_SCRIPT% > %FTP_SCRIPT_LOG%

rem FTP実行結果判定
for /F "delims=" %%j in ('findstr /R /C:"Ok to send data." %FTP_SCRIPT_LOG%') do (
        echo "ファイルアップロード完了" >> %FTP_SCRIPT_LOG%
        set FTPPUT_EXITCODE=0
)

rem ログファイル出力
echo "ftp -s:%FTP_SCRIPT% > %FTP_SCRIPT_LOG%"
for /F "delims=" %%i in (%FTP_SCRIPT_LOG%) do (
	echo " | %%i"
	
)

rem 一時ファイルを削除
del %FTP_SCRIPT%

echo exit /B %FTPPUT_EXITCODE%
exit /B %FTPPUT_EXITCODE% 

20240524125213_ftpbat.logの内容

ftp> open 192.168.0.10
192.168.0.10 に接続しました。
220 (vsFTPd 3.0.3)
ユーザー (192.168.0.5:(none)): 
331 Please specify the password.

230 Login successful.
ftp> bin
200 Switching to Binary mode.
ftp> send Temp\test.txt
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 Transfer complete.
ftp: 246 バイトが送信されました 0.00秒 123.00KB/秒。
ftp> quit
221 Goodbye.
"ファイルアップロード完了" 

FTPサーバーの要件が厳しい場合は、「System.Net.FtpWebRequest」ライブラリの使用ではなく外部のプログラムを使用することを検討しましょう。