メモの日々


2021年11月29日(月) [長年日記]

[windows] Zipファイルを作るPowerShellスクリプト

初めてPowerShellスクリプトを書いた。フォルダパスとZipファイルパスを指定すると、フォルダ内の.exeと.dllをアーカイブしたZipファイルを作成するスクリプト。

param(
    [Parameter(Mandatory=$true)][String]$srcDir,
    [Parameter(Mandatory=$true)][String]$zipFile
)

try {
    # エラーが発生したら処理を止める
    $ErrorActionPreference = "Stop"

    Write-Host "$srcDir --> $zipFile"

    # 一時フォルダを作成
    $tmpDir = New-TemporaryFile |
        % { Remove-Item $_; New-Item -ItemType Directory $_-d }

    # 一時フォルダへ必要なファイルだけをコピー
    Copy-Item -Include *.exe,*.dll $srcDir\* $tmpDir

    # zipファイルが存在している場合はそれを削除
    if (Test-Path $zipFile) { Remove-Item $zipFile }

    # zipファイルを作成
    Compress-Archive $tmpDir/* $zipFile

    # zipファイルの内容を出力
    Add-Type -AssemblyName System.IO.Compression.FileSystem
    [System.IO.Compression.ZipFile]::OpenRead($zipFile).Entries |
        Format-Table -Property FullName,LastWriteTime
} finally {
    # 一時フォルダを削除
    if ($tmpDir) { Remove-Item -Recurse $tmpDir }
}

PowerShellスクリプトの実行方法

PowerShellスクリプトはデフォルトの設定だとセキュリティエラーになり実行できない。

PowerShellコマンドExecutionPolicyオプションと共にスクリプトを指定すれば実行できる。

> powershell -ExecutionPolicy unrestricted ./make-zip.ps1 test test.zip
test --> test.zip

FullName LastWriteTime
-------- -------------
a.exe    2021/11/29 16:26:54 +09:00
b.dll    2021/11/29 16:20:18 +09:00

スクリプトのパラメータ

スクリプトのパラメータはparamで指定できる。ちゃんとした説明を見つけられないがParameters in scriptsで少し説明されている。

上のスクリプトではParameter属性を使って2つのパラメータ(srcDirとzipFile)を必須に設定している。

エラー時にスクリプトを終了する

処理中にエラーが発生したらそこでスクリプトは止まってほしい。それを実現するには、$ErrorActionPreferenceにStopを設定すればいいようだ。

メッセージの出力

メッセージを出力するにはWrite-HostまたはWrite-Outputが使える。

一時フォルダの作成と削除

PowerShellには一時フォルダを作成する機能はなさそう。上のスクリプトではStack Overflowにあった例を真似して、一時ファイルを生成 → その一時ファイルのパスを利用して一時フォルダを作成、という手順で作っている。

なお、一時フォルダ作成処理内にある「%」はForEach-Objectのエイリアス。

作成した一時フォルダの削除はtry/finallyステートメントのfinally内で行うようにしている。

Zipファイルの作成

Zipファイルの作成にはCompress-Archiveが使える。

Zipファイル内のファイル一覧を出力

Zipファイルの作成は上述のCompress-Archiveでできるが、Zipファイル内のファイル一覧を得るコマンドレットは無いみたい。Zipファイルを展開するのならExpand-Archiveを使えるのだけれど。

ファイル一覧を得るには、.NETのライブラリを使う必要がありそう。System.IO.Compression.ZipFileというクラスが使える。

PowerShellでは、Add-Typeを使うとDLLを読み込んで.NETのクラスを使えるようになる。上のスクリプトではSystem.IO.Compression.FileSystem.dllを読み込んで ZipFile#OpenRead() を呼び出し、更にFormat-Tableを使って出力を行っている。