PowerShellでファイルコピーしよう

PowerShell
PowerShell

PowerShellを使用したファイルコピーのサンプルスクリプト(備忘)

スクリプト本体

################################################################################
#処理概要
# 定義ファイルに記載されたファイルを所定のディレクトリにコピーする。
# 
#スクリプト仕様
# スクリプトファイル名 : FileCopy.ps1
# スクリプト名称       : ファイルコピースクリプト
# 引数                 : 1 … ファイルコピー定義ファイル名(<コビー元ファイル名>,<コピー先フォルダ/ファイル名>,<上書きフラグ(UP:上書き可/NU:上書き不可)>,<コメント>)
# 戻り値               : 0 … 正常終了
#                         1 … 異常終了
# ログファイル         : FileCopy.log
#  起動方法             : FileCopy.ps1 <ファイルコピー定義ファイル名>
#                         JP1/AJSジョブから呼び出し
#  前提                 : Windows Server 2022 (PowerShell 5.1以上) で動作確認を実施
#  備考                 : なし
#
#更新履歴
# Ver.     日付       コメント                                                     担当
# -------- ---------- ------------------------------------------------------------ ----------
# V 1.00.  2024/01/01 新規作成                                                     
#
################################################################################

#####  変数  #####
$ScriptFile   = Split-Path -Leaf $PSCommandPath                            # スクリプトファイル名
$ScriptDir    = $PSScriptRoot + "\"                                        # スクリプトファイルの格納ディレクトリ
$LogFile      = ${ScriptFile}.Split(".")[0] + ".log"                       # スクリプトログファイル名
$LogDir       = "C:\Script\Log\"                                           # スクリプトログの格納ディレクトリ
$Log          = ${LogDir} + ${LogFile}                                     # スクリプトログファイル
$LSize        = 10                                                         # ログローテーションを行う際のログサイズ(MByte)
$LGen         = 5                                                          # ログローテーションを行う際の保存世代数(カレントログファイル以外のファイル数)
$Conf         = ""                                                         # ファイルコピー定義ファイル

$NOW          = ""                                                         # システム日時
$InFile       = ""                                                         # カレント入力ファイル
$ReadLine     = ""                                                         # 読み込み行
$Word         = ""                                                         # 読み込み行($ReadLine)を区切り子で分割したオブジェクト
$CopyFileFrom = ""                                                         # コピー対象ファイル名
$CopyTo       = ""                                                         # コピー先ファイル名
$UpdateFlg    = ""                                                         # コピー先ファイルを上書きするかどうかのフラグ
$File1        = ""                                                         # コピー元ファイル名
$File2        = ""                                                         # コピー先ファイル名

#####  メッセージ  #####
$MSG01 = "【INFO】ファイルコピー処理(${ScriptFile})を開始します。"
$MSG02 = "【INFO】ファイルコピー処理(${ScriptFile})を終了します。"
$MSG03 = "【INFO】ファイルをコピーしました。"

$ERR01 = "【ERR】 ログファイルに書き込みできません。"
$ERR02 = "【ERR】 引数が設定されていません。"
$ERR03 = "【ERR】 ファイルコピー定義ファイルが存在しません。"
$ERR04 = "【ERR】 ファイルコピーに失敗しました。"

$WRN01 = "【WARN】定義ファイルの項目数が不足しています。コピー処理をスキップします。"
$WRN02 = "【WARN】コピー対象ファイルが存在しません。コピー処理をスキップします。"
$WRN03 = "【WARN】コピー先にファイルが存在します。コピー処理をスキップします。"
$WRN04 = "【WARN】複数のコピー元に対して、コピー先がフォルダではありません。コピー処理をスキップします。"
$WRN05 = "【WARN】コピー先フォルダが存在しません。コピー処理をスキップします。"


#####  関数  #####
##-----  メッセージ出力関数  -----
function PrintMSG
{
    param (
        $Words                                                              # 出力する文言
    )

    ##-----  変数  -----
    $NOW = ""                                                               # システム日時
    
    ##-----  出力処理 -----
    $NOW = (Get-DATE).ToString("yyyy/MM/dd HH:mm:ss")
    Write-Host ${Words}
    $NOW + " " + ${Words} >> ${Log}
}

##-----  ログローテーション関数  -----
function LogRotation
{
    param (
        [string]$Log,                                                        # ログローテーション対象ログファイル
        [int]$LSize,                                                         # ログローテーションを行う際のログサイズ(MByte)
        [int]$LGen                                                           # ログローテーションを行う際の保存世代数(カレントログファイル以外のファイル数)
    )

    ##-----  変数 -----
    $TargetLogFile1 = ""                                                     # リネーム前ログファイル、もしくは、削除対象ログファイル
    $TargetLogFile2 = ""                                                     # リネーム後ログファイル
    
    ##-----  メッセージ  -----
    $MSG01 = "【INFO】ログローテーションを開始します。"
    $MSG02 = "【INFO】ログローテーションを終了します。"
    $MSG03 = "【INFO】保存世代より古いログファイルを削除しました。"
    $MSG04 = "【INFO】ログファイルをリネームします。"
    $ERR01 = "【ERR】 ログファイルの削除に失敗しました。"
    $ERR02 = "【ERR】 ログファイルのリネームに失敗しました。"

    ##-----  ファイルサイズが指定値以上の場合、ログローテーションを行う  -----
    if ((Get-Item ${Log}).length -ge (${LSize} * 1024 * 1024)) {
        PrintMSG (${MSG01} + "[ログファイル: " + ${Log} + "]")
        ##-----  ログローテーションの実施  -----
        ##-----  最も古い世代のログファイルの削除  -----
        $TargetLogFile1 = ${log} + "." + ${LGen}
        $TargetLogFile2 = ${log} + "." + (${LGen} - 1)
        if (((Test-Path ${TargetLogFile1}) -eq $True) -and ((Test-Path ${TargetLogFile2}) -eq $True)) {
            try {
                Remove-Item ${TargetLogFile1}
                PrintMSG (${MSG03} + "[ログファイル: " + ${TargetLogFile1} + "]")
            } catch {
                PrintMSG (${ERR01} + "[ログファイル: " + ${TargetLogFile1} + "]")
                exit 1
            }
        }
        ##-----  途中の世代のログファイルのリネーム  -----
        for ($i=${LGen}; $i -gt 1; $i--) {
            $TargetLogFile1 = ${log} + "." + $i
            $TargetLogFile2 = ${log} + "." + ($i - 1)
            ##-----  若い世代のログファイルが存在する場合、リネームする  -----
            if ((Test-Path ${TargetLogFile2}) -eq $True) {
                try {
                    Rename-Item -Path ${TargetLogFile2} -NewName ${TargetLogFile1}
                    PrintMSG (${MSG04} + "[ログファイル名 変更前: " + ${TargetLogFile2} + "][ログファイル名 変更後: " + ${TargetLogFile1} + "]")
                } catch {
                    PrintMSG (${ERR02} + "[ログファイル名 変更前: " + ${TargetLogFile2} + "][ログファイル名 変更後: " + ${TargetLogFile1} + "]")
                    exit 1
                }
            }
        }
        ##-----  カレントログファイルのリネーム  -----
        $TargetLogFile1 = ${log} + ".1"
        $TargetLogFile2 = ${log}
        ##-----  若い世代のログファイルが存在する場合、リネームする  -----
        if ((Test-Path ${TargetLogFile2}) -eq $True) {
            try {
                Rename-Item -Path ${TargetLogFile2} -NewName ${TargetLogFile1}
                PrintMSG (${MSG04} + "[ログファイル名 変更前: " + ${TargetLogFile2} + "][ログファイル名 変更後: " + ${TargetLogFile1} + "]")
            } catch {
                PrintMSG (${ERR02} + "[ログファイル名 変更前: " + ${TargetLogFile2} + "][ログファイル名 変更後: " + ${TargetLogFile1} + "]")
                exit 1
            }
        }
        PrintMSG ${MSG02}
    }
}


#####  メイン処理  #####
##-----  ログファイルへの区切りの書き込み  -----
try {
    "----------" >> ${Log}
} catch {
    PrintMSG (${ERR01} + "[ログファイル: " + ${Log} + "]")
    Write-Host ${MSG02}
    exit 1
}

##-----  ログローテーションの実施  -----
LogRotation ${Log} ${LSize} ${LGen}

##-----  処理開始メッセージ出力  -----
PrintMSG (${MSG01} + "[引数: " + ${args} + "]")

##-----  引数チェック  -----
if (${args}.Length -eq 0) {
    PrintMSG (${ERR02})
    PrintMSG (${MSG02})
    exit 1
} else {
    $Conf = ${args}[0]
}

##-----  定義ファイルの存在確認  -----
if ((Test-Path ${Conf}) -ne $True) {
    PrintMSG (${ERR03})
    PrintMSG (${MSG02})
    exit 1
}

##-----  定義ファイルの読み込み  -----
$InFile = (Get-Content ${Conf}) -as [String[]]
foreach ($ReadLine in ${InFile}) {
    ##-----  行頭が"#"以外の文字列のみ処理する  -----
    if ((${ReadLine}[0] -ne "#") -and (${ReadLine}[0].count -ne 0)) {
        $Word = (${ReadLine} -Split ",")
        ##-----  読み込んだ行の項目数チェック  -----
        if (${Word}.Length -lt 3) {
            PrintMSG (${WRN01} + "[読み込み行: " + ${Word} + "]")
        }
        $CopyFileFrom = ${Word}[0].Trim('"')
        $CopyTo       = ${Word}[1].Trim('"')
        $UpdateFlg    = ${Word}[2]

        ##-----  コピー元ファイルの一覧取得(ワイルドカード指定を想定)  -----
        if ((Test-Path ${CopyFileFrom}) -eq $False) {
            ##-----  コピー元ファイルが存在しない場合はコピー処理をスキップする  -----
            PrintMSG (${WRN02} + "[コピー対象ファイル: " + ${CopyFileFrom} + "]")
        } elseif (((Get-Item ${CopyFileFrom}).count -ge 2) -and ((Test-Path ${CopyTo}) -eq $True) -and ((Get-Item ${CopyTo}).PSIsContainer -eq $False)) {
            ##-----  コピー元ファイルが2つ以上存在し、かつ、コピー先パスがフォルダでない場合はコピー処理をスキップする  -----
                PrintMSG (${WRN04} + "[コピー対象ファイル: " + ${CopyFileFrom} + "][コピー先: " + ${CopyTo} + "]")
        } else {
            foreach ( $File1 in (Get-Item ${CopyFileFrom}) ) {
                ##-----  コピー先ファイルフルパスのセット  -----
                if (((Test-Path ${CopyTo}) -eq $True) -and ((Get-Item ${CopyTo}).PSIsContainer -eq $True)) {
                    ##-----  コピー先がフォルダの場合  -----
                    $File2 = Join-Path ${CopyTo} ${File1}.name
                } else {
                    ##-----  コピー先がファイルの場合  -----
                    $File2 = ${CopyTo}
                    if ((Test-Path (Split-Path -Parent ${File2})) -eq $False) {
                        ##-----  コピー先ファイルを内包するフォルダが存在しない場合、処理をスキップ  -----
                        PrintMSG (${WRN05} + "[コピー先: " + ${File2} + "]")
                        continue
                    }
                }
                ##-----  ファイル上書きフラグが指定されていない、かつ、コピー先にファイルが存在する場合はコピーを行わない  -----
                if ((${UpdateFlg} -ne "UP") -and ((Test-Path ${File2}) -eq $True)) {
                    PrintMSG (${WRN03} + "[コピー対象ファイル: " + ${File1} + "][コピー先: " + ${File2} + "]")
                } else {
                    ##-----  ファイルコピー  -----
                    try {
                        Copy-Item -Path ${File1} -Destination ${File2}
                        PrintMSG (${MSG03} + "[コピー対象ファイル: " + ${File1} + "][コピー先: " + ${File2} + "]")
                    } catch {
                        PrintMSG ($Error[0])
                        PrintMSG (${ERR04} + "[コピー対象ファイル: " + ${File1} + "][コピー先: " + ${File2} + "]")
                    }
                }
            }
        }
    }
}

##-----  処理終了メッセージ出力 -----
PrintMSG (${MSG02})

exit 0

ファイルコピー定義ファイル

#ファイルコピー定義ファイル
#<コビー元ファイル名>,<コピー先フォルダ/ファイル名>,<上書きフラグ(UP:上書き可/NU:上書き不可)>,<コメント>
#コピー元ファイル名にはワイルドカードの指定が可能
C:\Script\Test\From\File1.txt,C:\Script\Test\To\File1.txt,UP,aaaa
C:\Script\Test\From\File2.txt,C:\Script\Test\To\File2.txt,NU,aaaa
C:\Script\Test\From\File3*.txt,C:\Script\Test\To,UP,aaaa

コメント