PowerShellスクリプトの起動バッチつくってみた

# はじめに

自分はPowerScriptで簡単なツールを作るさいにバッチファイルのクリックから実行できるようにすることが多いです。

こうすることで、ショートカット化してスタートメニューに置いておくことで簡単に呼び出せたり、コンソールを自分で開いたり閉じたりする必要がなくなるのでそこそこ便利だと思います。

ただ毎回0からバッチファイルやフォルダ構成を準備するのは面倒だな～、ということでテンプレート構成を作ってみました。

https://github.com/www-tacos/powershell-app-template

この記事では構成や中身について詳しく書いてみようかなと思います。

# 構成

テンプレートの構成は以下のような形にしてみました。

```plaintext:テンプレート構成
<アプリ名フォルダ>
├ main.lnk
├ README.txt
├ src
│ ├ main.bat
│ └ main.ps1
├ lib
│ └ hoge.ps1
└ img
  └ favicon.ico
```

`main.bat` が起動バッチで、PowerShellスクリプトのエントリーポイントが `main.ps1` です。

実際の処理内容は直接 `main.ps1` に書くか、別スクリプトにまとめて呼び出すことになるかなと思います。
まあ、複雑な処理を書くことは少ないと思うので `lib` にスクリプトモジュールをいくつか入れて `main.ps1` でそれを使って何かする、みたいなコードになることが多い気がします。

## main.lnk, src/main.bat

`main.lnk` は `src/main.bat` のショートカットです。
アプリっぽくするためにbatファイルにアイコンを設定したかったのですが直接はできないようなので、代わりにショートカットを作ってそれにアイコンを設定する方法をとることにしました。（完全におまけです）

> 2021-09-21追記
main.ps1の中で管理者権限が必要な処理を記述する場合はmain.batを管理者権限で実行する必要がありますが、main.lnkを管理者権限で実行することはできないので、その時はmain.batをそのままルートディレクトリに配置するとよいと思います。

配布の可能性を考慮して、ショートカットのリンク先は以下のように環境変数・Explorer・相対パスを使って記述しました。こうすることで環境に依存しないショートカットにすることができます。

```plaintext:main.lnkのリンク先
%windir%\explorer.exe ".\src\main.bat"
```

`main.bat` の中身は PowerShell で`main.ps1`を実行する処理だけです。

```bat:main.bat
cd %~dp0/../
powershell -ExecutionPolicy Unrestricted -NoProfile -WindowStyle Hidden ./src/main.ps1
```

`cd %~dp0/../` ではカレントディレクトリをツールのルートディレクトリに設定しています。これによってスクリプト内では `Get-Location` でツールのルートディレクトリを取得できます。

`-ExecutionPolicy Unrestricted` ではPowerShellスクリプトの実行ポリシーを制限なしに設定しています。デフォルトの実行ポリシーではスクリプトを実行できないようになっているのでそれをアプリの実行時のみ解除しています。
ちなみに実行ポリシーの種類については [こちらの記事](https://qiita.com/Targityen/items/3d2e0b5b0b7b04963750) なんかが詳しいです。

`-NoProfile` では既存プロファイルの読み込みをスキップしています。プロファイルに自作コマンドなどを設定している場合、それがアプリに干渉する可能性があるので念のため設定しています。

`-WindowStyle Hidden` ではbatとPowerShellを実行するコマンドプロンプトを表示しないよう設定しています。
もし処理内容がコマンドラインベース（コマンドラインの入力を読み取る、コマンドラインにログを表示するなど）の場合はこのオプションを外してください。`Start-Progress` や `Invoke-WebRequest` のように進捗がコンソール上に表示されるコマンドを使う場合もこのオプションを外さないと何も表示されないので注意してください。（1敗）

~~`%~dp0/main.ps1`~~ `./src/main.ps1` はエントリーポイントなるPowerShellスクリプトです。~~1行目でカレントディレクトリを設定しているので `./src/main.ps1` でも十分ですね。~~

> 2021-09-21追記
main.ps1を指定するときのパスは相対パスに変更しました。
ツールのパスにスペースが入っている場合、cdは正常に動きますがpowershellの引数はスペースまでの部分しか認識してくれないようでした。他にダブルクォートで囲むなどの対策もある気がします。

## README.txt

`README.txt` はアプリのドキュメントです。

自分の場合、とりあえず以下のことを書くように意識しています。

- About : どんなアプリなのか
- Usage : どうやって使うのか

また、ライセンス表記や変更履歴も必要に応じて記述するとよいと思います。（GitHubで管理する場合はコミットログやLICENSEファイルがあるので不要ですね）

## src/main.ps1

`main.ps1` は `main.bat` から呼び出されるエントリーポイントです。

`main.ps1` からsrc配下のファイルやlib配下のファイルを読み込むときはカレントディレクトリから取得することができます。

```powershell:lib配下のスクリプト実行例
$ROOT = (Get-Location).Path
. "${ROOT}/lib/hoge.ps1"
```

## img/favicon.ico

アプリっぽさを出すためのおまけ要素です(笑)。

アイコンをオリジナルなものに変更することでアプリっぽさが格段に向上します。

アイコンは [ここ](https://www.flaticon.com/) とか [ここ](https://icooon-mono.com/) で処理内容がわかるような画像を入手して、[ここ](https://ao-system.net/alphaicon/) でico形式に変換する、というのが自分がよくやる手段です。
（アイコンサイズは最低でも16x16と32x32があったほうがいいらしい）

> 2021-09-21追記
アイコンのパスは絶対パス指定で、対象アイコンを移動させても自動で参照先が変わらないです。なのでディレクトリ名を変えたりツールを配布したときにアイコンが外れてしまいます。それでももし面倒でなければ、個人的に使う場合は適宜アイコンを設定して下さい。また配布を考えている場合は設定したパス名（≒自分のユーザ名など）が配布相手に伝わることに気を付けてください。

# さいごに

今回作ったテンプレート構成をベースに自分でもいろいろと作っていて、ある程度まとまった段階でGitHubに挙げているので気になる方はぜひチェックしてみてください。

あと、アプリを作る際に使えそうなスクリプトモジュールもぽつぽつと作っているのでこちらもよろしければどうそ。

https://github.com/www-tacos/powershell-scripts