F1大好きな、インチキ技術者の日記

F1大好きなインチキ技術者が情報を発信して、自分を変えようとしている日記です

LinuxからWindowsにバッチでファイルを定期的に移動する方法(逆もできるよ!)

やりたいこと*1

ファイルをバックアップするときなど、LinuxからWindowsへ、WindowsからLinuxへファイルをコピーや 移動したい場合があります。

いろいろ方法はあると思うのですが、WinSCPでは.NET Assemblyが公開されているので使ってみることにしました。

必要なもの

説明

C#で作ろうかと思ったのですが、簡単にかけるPowerShellで作りました。 こちらの例では、Linuxのサーバ(sessionOptions.HostNameに指定)にあるファイルをWindowsのPC(PowerShellが動いているPC)に移動してます。

なお、パスワード(sessionOptions.Password)がコメントアウトしてあるのはpagentを用いてSSH鍵認証を行っているためです。必要であればパスワードを書いてください。

ほぼWinSCPのサイトにあるサンプルのままですけど(^_^)

try
{
    # Load Windows Form
    [void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    
    # Load WinSCP .NET assembly (パスは環境によって変更してください)
    [Reflection.Assembly]::LoadFrom("C:\Program Files\WinSCP\WinSCPnet.dll") | Out-Null
 
    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions
    $sessionOptions.Protocol = [WinSCP.Protocol]::Sftp
    $sessionOptions.HostName = "【接続先ホスト名】"
    $sessionOptions.UserName = "【ユーザ名】"
    #$sessionOptions.Password = "【パスワード】"
    $sessionOptions.SshHostKeyFingerprint = "【フィンガープリント 例: ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx】"
 
    $session = New-Object WinSCP.Session
 
    try
    {
        # Connect
        $session.Open($sessionOptions)
 
        # Upload files バイナリモードを設定
        $transferOptions = New-Object WinSCP.TransferOptions
        $transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
        
        #リモートマシンの"/tmp/backup/*"を"C:\tmp\backup\"に「移動」。 3つめの引数を$FALSEにするとコピー
        $transferResult = $session.GetFiles("/tmp/backup/*","C:\tmp\backup\", $TRUE, $transferOptions)
 
        # Throw on any error
        $transferResult.Check()
 
        # Print results
        foreach ($transfer in $transferResult.Transfers)
        {
            Write-Host ("Download of {0} succeeded" -f $transfer.FileName)
        }
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }
    
    exit 0
}
catch [Exception]
{
    #エラーが出たらダイアログを出して気がついてもらう
    [System.Windows.Forms.MessageBox]::Show($_.Exception.Message, "バックアップエラー!",[Windows.Forms.MessageBoxButtons]::OK,[Windows.Forms.MessageBoxIcon]::Error);
    exit 1
}

後日追記

PowerShellをVersion3にしたところ、[Reflection.Assembly]::LoadFrom("C:\Program Files\WinSCP\WinSCPnet.dll") でエラーが出るようになった。

ファイルまたはアセンブリ 'file:///C:\Program Files\WinSCP\WinSCPnet.dll'、またはその依存関係の 1 つが読み込 めませんでした。操作はサポートされません。 (HRESULT からの例外:0x80131515)

さっぱり原因がわかりませんでしたが、WinSCPのフォーラムで意外な解決策が提示されてました。 Topic "Powershell : Could not load file or assembly winscp.dll"

[Reflection.Assembly]::LoadFrom("C:\Program Files\WinSCP\WinSCPnet.dll")

[Reflection.Assembly]::LoadFrom("\\C:\Program Files\WinSCP\WinSCPnet.dll")

に・・・ファイルパスの前に"\\"追加したら動きました。

もっと後日追記(2018/07/20)

久々にPCを入れ替えたら実行されなくなっていた。いろいろ調べた結果、dllファイルの「ブロック解除」が必要でした。

*1:2018年07月20日にQiitaに投稿した記事です。