【PowerShell】テンプレートファイルを、名前リスト分リネームしてコピーする

仕事に使えそうだなあ、というか仕事に使いたいシチュエーションがあるなあと思い、日付が変わってるのにPCに向き合っています。もう今日から仕事だよ!

目次

ツールの仕様

  • テンプレートファイル をもとに
  • ファイル名リスト(.txt、改行区切り) に書かれた名前で複製を作成し
  • 指定した出力フォルダ に一括生成する PowerShell GUI ツール

なので、Windows環境であればとりあえず動くはずです。

コード(makefiles.ps1)

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# -------- 共通ダイアログ関数 --------
function Select-File {
    param(
        [string]$Title = "ファイルを選択",
        [string]$Filter = "すべてのファイル (*.*)|*.*"
    )
    $dlg = New-Object System.Windows.Forms.OpenFileDialog
    $dlg.Title  = $Title
    $dlg.Filter = $Filter
    $dlg.Multiselect = $false
    if ($dlg.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { return $dlg.FileName }
    return $null
}

function Select-Folder {
    param([string]$Description = "出力先フォルダを選択")
    $dlg = New-Object System.Windows.Forms.FolderBrowserDialog
    $dlg.Description = $Description
    if ($dlg.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { return $dlg.SelectedPath }
    return $null
}

# -------- 画面構築 --------
$form                 = New-Object System.Windows.Forms.Form
$form.Text            = "テンプレート複製ツール"
$form.ClientSize      = New-Object System.Drawing.Size(680,260)
$form.StartPosition   = "CenterScreen"
$form.TopMost         = $false

$font = New-Object System.Drawing.Font("Yu Gothic UI", 10)

# ラベル/テキスト/ボタン(テンプレート)
$lblT = New-Object System.Windows.Forms.Label
$lblT.Text = "テンプレートファイル(拡張子は問わない):"
$lblT.Location = '12,18'; $lblT.AutoSize = $true; $lblT.Font=$font

$txtT = New-Object System.Windows.Forms.TextBox
$txtT.Location = '16,42'; $txtT.Size = '560,24'; $txtT.Font=$font

$btnT = New-Object System.Windows.Forms.Button
$btnT.Text = "参照..."; $btnT.Location='586,40'; $btnT.Size='80,28'; $btnT.Font=$font
$btnT.Add_Click({
    $p = Select-File -Title "テンプレートファイルを選択" -Filter "すべてのファイル (*.*)|*.*"
    if ($p) { $txtT.Text = $p }
})

# ラベル/テキスト/ボタン(リスト)
$lblL = New-Object System.Windows.Forms.Label
$lblL.Text = "ファイル名リスト(.txtのみ。ファイル内は改行区切り、拡張子は付けない):"
$lblL.Location = '12,78'; $lblL.AutoSize = $true; $lblL.Font=$font

$txtL = New-Object System.Windows.Forms.TextBox
$txtL.Location = '16,102'; $txtL.Size = '560,24'; $txtL.Font=$font

$btnL = New-Object System.Windows.Forms.Button
$btnL.Text = "参照..."; $btnL.Location='586,100'; $btnL.Size='80,28'; $btnL.Font=$font
$btnL.Add_Click({
    $p = Select-File -Title "ファイル名リスト(.txt)を選択" -Filter "テキスト ファイル (*.txt)|*.txt|すべてのファイル (*.*)|*.*"
    if ($p) { $txtL.Text = $p }
})

# ラベル/テキスト/ボタン(出力先)
$lblO = New-Object System.Windows.Forms.Label
$lblO.Text = "出力先フォルダ(存在しない場合は作成):"
$lblO.Location = '12,138'; $lblO.AutoSize = $true; $lblO.Font=$font

$txtO = New-Object System.Windows.Forms.TextBox
$txtO.Location = '16,162'; $txtO.Size = '560,24'; $txtO.Font=$font

$btnO = New-Object System.Windows.Forms.Button
$btnO.Text = "参照..."; $btnO.Location='586,160'; $btnO.Size='80,28'; $btnO.Font=$font
$btnO.Add_Click({
    $p = Select-Folder -Description "出力先フォルダを選択"
    if ($p) { $txtO.Text = $p }
})

# 実行ボタン(右下寄せ+余白20px、キャストあり)
$btnRun = New-Object System.Windows.Forms.Button
$btnRun.Text = "開始"
$btnRun.Size = '106,34'
$btnRun.Font = $font
$btnRun.Location = New-Object System.Drawing.Point(
    [int]($form.ClientSize.Width - $btnRun.Width - 20),
    [int]($form.ClientSize.Height - $btnRun.Height - 20)
)
$btnRun.Anchor = "Bottom,Right"

# 画面に追加
$form.Controls.AddRange(@($lblT,$txtT,$btnT,$lblL,$txtL,$btnL,$lblO,$txtO,$btnO,$btnRun))

# -------- 実行ロジック --------
$btnRun.Add_Click({
    $template = $txtT.Text.Trim()
    $listFile = $txtL.Text.Trim()
    $outDir   = $txtO.Text.Trim()

    if ([string]::IsNullOrWhiteSpace($template) -or -not (Test-Path -LiteralPath $template)) {
        [System.Windows.Forms.MessageBox]::Show("テンプレートファイルが不正です。","エラー","OK","Error") | Out-Null
        return
    }
    if ([string]::IsNullOrWhiteSpace($listFile) -or -not (Test-Path -LiteralPath $listFile)) {
        [System.Windows.Forms.MessageBox]::Show("ファイル名リスト(.txt)が不正です。","エラー","OK","Error") | Out-Null
        return
    }
    if ([string]::IsNullOrWhiteSpace($outDir)) {
        [System.Windows.Forms.MessageBox]::Show("出力先フォルダを指定してください。","エラー","OK","Error") | Out-Null
        return
    }

    try {
        if (-not (Test-Path -LiteralPath $outDir)) {
            New-Item -Path $outDir -ItemType Directory -Force | Out-Null
        }
    } catch {
        [System.Windows.Forms.MessageBox]::Show("出力先フォルダを作成できませんでした。`n$($_.Exception.Message)","エラー","OK","Error") | Out-Null
        return
    }

    $ext = [IO.Path]::GetExtension($template)
    $log = Join-Path $outDir "error.log"
    $okCount = 0
    $ngCount = 0

    try {
        $names = Get-Content -LiteralPath $listFile -Encoding UTF8 -ErrorAction Stop |
                 Where-Object { $_.Trim() -ne "" }
    } catch {
        [System.Windows.Forms.MessageBox]::Show("リストの読み込みに失敗しました。`n$($_.Exception.Message)","エラー","OK","Error") | Out-Null
        return
    }

    foreach ($name in $names) {
        $dest = Join-Path $outDir ($name.Trim() + $ext)
        try {
            Copy-Item -LiteralPath $template -Destination $dest -Force -ErrorAction Stop
            $okCount++
        } catch {
            $ngCount++
            $msg = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') : [$name] 作成失敗 → $($_.Exception.Message)"
            Add-Content -Path $log -Value $msg
        }
    }

    $summary = "完了しました。`n成功: $okCount 件 / 失敗: $ngCount 件`n出力先: $outDir"
    if ($ngCount -gt 0) { $summary += "`nエラーログ: $log" }
    [System.Windows.Forms.MessageBox]::Show($summary, "結果", "OK", "Information") | Out-Null
})

# -------- フォーム起動 --------
[void]$form.ShowDialog()

ツールの利用イメージ

GUI

もう少し整えても良かったと思いますが、早く睡眠しなければマズイため、諦めました。

入力項目は

  • テンプレートファイル
  • ファイル名リスト
  • 出力先フォルダ

の3つです。

なお、テンプレートファイルとファイル名リストは予め準備が必要です。

ディレクトリ構成

出力先は同じところに「output」とかで配置するのがいいと思います。なお、存在しないディレクトリを指定した場合は、ツール側でディレクトリ作成を実施します。

入力ファイル(テンプレートファイル、ファイル名リスト)は好きなとこで大丈夫です。また、ファイル名の規約はありません。ファイル名リストについては、拡張子.txtだけ制約としてます。

ファイル名リスト

改行区切りで、作成したいファイルの名称を記載します。拡張子はテンプレートファイルから拾うため、ここには記載不要です。

出力結果

こんな感じで出力されます。なお、同名ファイルが既にある場合は上書き保存されます。

やまぐろ
この記事を書いた人
業務アプリケーション開発、エンドユーザ向け機能などの開発に携わっている文系(経営学)卒エンジニア。
当サイトでは読書記録を残したり、ガジェットのレビューをしたりしています。
たまにエンジニアっぽい記事を書いたりすることも。

コメント

コメントする

このサイトは reCAPTCHA によって保護されており、Google のプライバシーポリシー および 利用規約 に適用されます。

reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

目次