1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【PowerShell】WinSCPの.NETアセンブリを使ってSCP転送をスクリプト化する

Last updated at Posted at 2023-11-23

はじめに

WinSCPはGUIでファイル転送が可能なアプリケーションである。
一方で.Netのアセンブリが提供されており、
プログラムから呼び出すことができる。
※アセンブリはWinSCPの実行ファイルが格納されているフォルダにWinSCPnet.dllとして格納されている。

これを利用して、PowerShell上でWinSCPでSCPプロトコルを用いた転送スクリプトを作成する。

スクリプト

スクリプト
#パラメータ定義
param(
    [string]$HostName = "<デフォルトIPアドレス>",
    [string]$UserName = "(デフォルトユーザ名)",
    [string]$Password = "<デフォルトパスワード>",
    [Parameter(Mandatory=$True)]
    [ValidateSet("Get","Put")]
    $transferType = "",
    [Parameter(Position=0)]
    [string]$sourcePath = "",
    [Parameter(Position=1)]
    [string]$destPath = ""
)

try
{
    #ライブラリの読み込み
    Add-Type -Path "<WinSCPnet.dllのパス>"

    if([string]::IsNullOrEmpty($sourcePath)){
        $sourcePath = Read-Host "取得先のリモートホストのパスを入力" 
        $sourcePath = $sourcePath.Trim('"',"'")  
    }

    if([string]::IsNullOrEmpty($destPath)){
        $destPath = Read-Host "保存先のディレクトリを入力"
        $destPath =  $destPath.Trim('"',"'")
    }

    #ディレクトリパスの末尾に"\"記号が無い場合追加
    if( ! ($destPath.EndsWith("\") ) ){
        $destPath += "\"
    }

    #セッション情報の設定
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::Scp
        HostName = $HostName
        UserName = $UserName
        Password = $Password
        GiveUpSecurityAndAcceptAnySshHostKey = $True
    }

    #セッションを張る
    $session = New-Object WinSCP.Session
    $session.Open($sessionOptions)

    try
    {
        #put/getで分岐
        if( $transferType -eq "Get" ){#Get
            #リモートホストからファイルを取得する。
            $transferResult = $session.GetFiles($sourcePath, $destPath, $false)
        }else{#Put
            $fileName = Split-Path $sourcePath -Leaf
            $transferResult = $session.PutFiles($sourcePath, "${destPath}${fileName}", $false)
        }
        $transferResult.Check()

        #結果出力
        foreach($transfer in $transferResult.Transfers) {
            Write-Host "Source: $($transfer.FileName),succeeded"
            Write-Host "Destination:$($transfer.Destination) "
        }
    }
    finally
    {
        $session.Dispose()
    }
}
catch
{
    Write-Host "Error:$($_.Exception.Message)"
    exit 1
}

書式

書式
script [-HostName <System.String>] [-UserName <System.String>] [-Password <System.String>] -transferType <Get> | <Put> [[-sourcePath <System.String>] [-destPath <System.String>]]

制作時備忘

  • 転送後の終了処理でSession.Disposeの場合オブジェクトを破棄する(リソースを開放)
    Session.Closeを用いた場合、オブジェクトの再利用が可能。

  • WinSCPのGUIアプリで設定した「サイト」の情報は利用できない模様。
    公式リファレンスを見ても「サイト」からセッションオプションの値を取得する方法は特に載っていなかった...

  • SCPではputFileやgetFileメソッドはサポートされていない。
    転送を行う際は単一のファイルの場合でもputFileではなく、putfilesを使う。Getの場合も同様

  • ディレクトリのパスを指定する際に末尾にパス区切り文字がないとファイル名として認識されてしまうため、区切り文字を明示する必要有(最初この仕様に気づかず転送に成功したもののファイルが無いという現象が多発しました)

  • ファイル転送部分はtry-finallyで記述しエラーが発生した場合でも必ずオブジェクトが破棄されるようにしておく。

余談

今回のスクリプトまだちょっとプロトタイプ的な感じが強いです。
WinSCP自体は様々な転送プロトコルに対応しているので、
異なるプロトコルを画一された方法で利用できるという点は便利ですね。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?