プログラミング

PowerShellとWinSCPを使ってSFTPでファイル転送

PowerShellとWinSCPを使ってSFTPでファイル転送を行う方法をメモしておきます。

WinSCP(WinSCP .NET Assembly)の導入

WinSCPををダウンロードします。(詳細略)

今回は「C:\WinSCP」にダウンロードした前提で進めます。

インストール」フォルダを開いて「WinSCPnet.dll」が含まれていることを確認します。

WinSCPnet.dllとは

FTP/SFTP クライアント「WinSCP」を .NET アプリケーション(C#、VB.NET、PowerShell など)から操作するためのライブラリ(.NET アセンブリ)。

GUI 操作の自動化や、プログラミングからファイル転送をしたい時に、WinSCP の実行ファイル(WinSCP.exe)と同じフォルダに配置して使用します。 

主な特徴

  • WinSCP のスクリプトインターフェース(コマンド)を 「.NET コード」で利用可能にする。
  • PowerShell や C# でサーバーへの接続やファイルのアップロード/ダウンロードを自動化する。
  • 条件付き処理やループ処理など複雑なタスクを実行できる。
  • Mozilla Public License 2.0 で配布されている無料のライブラリ。 

PowerShellからの使い方

実際のサンプルコードです。

ファイルアップロード

# WinSCPの.NET Assemblyをロード(WinSCPnet.dllのフルパスを指定)
Add-Type -Path "C:\WinSCP\WinSCPnet.dll"

# セッションオプションを設定
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Sftp
    HostName = "example.com" # ホスト名
    UserName = "username" # ユーザ名
    Password = "password" # パスワード
    SshHostKeyFingerprint = "XXX"  # フィンガースクリプト(初回接続時に取得)
}

$session = New-Object WinSCP.Session

try {
    # 接続
    $session.Open($sessionOptions)
    
    # ファイルをアップロード
    $transferOptions = New-Object WinSCP.TransferOptions
    $transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
    
    $transferResult = $session.PutFiles("C:\local\file.txt", "/remote/path/", $False, $transferOptions)
    
    # エラーチェック
    $transferResult.Check()
    
    # 成功したファイルを表示
    foreach ($transfer in $transferResult.Transfers) {
        Write-Host "アップロード完了: $($transfer.FileName)"
    }
}
catch [Exception] {
    Write-Error "エラーが発生しました: $($_.Exception.Message)"
    Write-Error "スタックトレース: $($_.Exception.StackTrace)"
    exit 1
}
finally {
    # セッションを閉じる
    $session.Dispose()
}

ファイルダウンロード

# WinSCPの.NET Assemblyをロード(WinSCPnet.dllのフルパスを指定)
Add-Type -Path "C:\WinSCP\WinSCPnet.dll"

# セッションオプションを設定
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Sftp
    HostName = "example.com" # ホスト名
    UserName = "username" # ユーザ名
    Password = "password" # パスワード
    SshHostKeyFingerprint = "XXX"  # フィンガースクリプト(初回接続時に取得)
}

$session = New-Object WinSCP.Session

try {
    # 接続
    Write-Host "接続中..."
    $session.Open($sessionOptions)
    Write-Host "接続成功"
    
    # ファイルをダウンロード
    $remotePath = "/remote/path/file.txt"
    $localPath = "C:\local\"
    
    Write-Host "ダウンロード開始: $remotePath"
    
    $transferResult = $session.GetFiles($remotePath, $localPath, $False)
    
    # 転送結果をチェック
    if ($transferResult.IsSuccess) {
        Write-Host "ダウンロード成功" -ForegroundColor Green
        
        # 成功したファイルの詳細を表示
        foreach ($transfer in $transferResult.Transfers) {
            Write-Host "  ファイル: $($transfer.FileName)"
            Write-Host "  保存先: $($transfer.Destination)"
        }
    }
    else {
        Write-Host "ダウンロードに失敗しました" -ForegroundColor Red
        
        # 失敗したファイルの詳細を表示
        foreach ($failure in $transferResult.Failures) {
            Write-Error "  失敗: $($failure.FileName)"
            Write-Error "  理由: $($failure.Message)"
        }
    }
}
catch [Exception] {
    Write-Error "エラーが発生しました: $($_.Exception.Message)"
    Write-Error "スタックトレース: $($_.Exception.StackTrace)"
    exit 1
}
finally {
    # セッションを必ず閉じる
    if ($session) {
        $session.Dispose()
        Write-Host "セッションをクローズしました"
    }
}

SSHキーを使いたい場合

$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Sftp
    HostName = "example.com"
    UserName = "username"
    SshPrivateKeyPath = "C:\path\to\private_key.ppk"  # PuTTY形式の秘密鍵
    SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:..."
}

フィンガープリント(Fingerprint)とは

SSH Host Key Fingerprintは、接続先サーバーの公開鍵の「指紋」です。中間者攻撃を防ぐために、初回接続時にサーバーの身元を確認するために使用されます。

検証環境等では、以下のように無視させることもできますが、本番では非推奨です。

とはいえ、分からない事もあるかと思うので、確認方法も載せておきます。

$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Sftp
    HostName = "example.com"
    UserName = "username"
    Password = "password"
    GiveUpSecurityAndAcceptAnySshHostKey = $True  
}

フィンガープリント(Fingerprint)の確認方法

GUIで確認

WinSCPを開いて、SFTP接続初回接続時に表示される警告ダイアログに表示されるため、表示されたフィンガープリント(Fingerprint)をメモります。

プログラムで確認

一時的にすべてのホストキーを許可した上で、PoweShellでフィンガープリント(Fingerprint)取得します。

取得したフィンガープリント(Fingerprint)を使います。

# WinSCPの.NET Assemblyをロード(WinSCPnet.dllのフルパスを指定)
Add-Type -Path "C:\WinSCP\WinSCPnet.dll"

# 2. セッションオプションの設定
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.Protocol = [WinSCP.Protocol]::Sftp
$sessionOptions.HostName = "example.com"
$sessionOptions.UserName = "username"
$sessionOptions.Password = "password"

# 一時的にすべてのホストキーを許可する(取得のため)
$sessionOptions.GiveUpSecurityAndAcceptAnySshHostKey = $True

$session = New-Object WinSCP.Session

try {
    # 3. 接続を開く
    $session.Open($sessionOptions)

    # 4. 接続先サーバーのフィンガープリントを表示
    $fingerprint = $session.Info.SshHostKey
    Write-Host "取得したフィンガープリント: $fingerprint" -ForegroundColor Cyan
}
finally {
    $session.Dispose()
}

まとめ

PowerShellとWinSCPを組み合わせることで簡単にSFTP接続を実現できます。

PowerShellを用いたSFTP接続を検討している方の助力になると嬉しいです。

-プログラミング