PowerShellスクリプトモジュールのテンプレートをつくってみた

# はじめに

PowerShellのスクリプトモジュールをいくつか作ってみたことで、ある程度テンプレート構成がまとまったので記事にしてみます。

あくまで自分流のテンプレートなので「これが最適解」というものではなく、また今後も随時アップデートされていくと思うのでご了承ください。

# スクリプトモジュールとは

PowerShellのモジュールについての詳しくて正確な情報は[Microsoftの公式ドキュメント](https://docs.microsoft.com/ja-jp/powershell/scripting/developer/module/understanding-a-windows-powershell-module?view=powershell-7.1)に書いてありますが、この記事で扱う範囲について簡単に言えば関数ライブラリみたいなものと思っていただければ十分です。

`psm1` 形式のファイルに関数と `Export-ModuleMember` コマンドを書いておき、それを `Import-Module` コマンドで読み込むことで、既存のコマンドレットと同様に任意の場所（スクリプト内、コンソール上）で実行可能なコマンドを作ることができます。

# スクリプトモジュールテンプレート

さっそくですが今回作ったテンプレートは下記のようなものです。

```powershell
function TemplateModule {
  <#
  .SYNOPSIS
    <コマンドの概要>

  .DESCRIPTION
    <コマンドの説明>

  .PARAMETER Help|h
    ヘルプを表示する

  .PARAMETER <Parameter>
    <Parameterの意味>

  .PARAMETER CommonParameters
    サポートしていません

  .INPUTS
    <入力の仕様>

  .OUTPUTS
    <出力の仕様>

  .EXAMPLE
    PS> TemplateModule
      <コマンドのみ実行時の処理内容>

  .EXAMPLE
    PS> TemplateModule -Help
      ヘルプを表示します

  .EXAMPLE
    PS> TemplateModule <Parameter>
      <Parameter指定時の処理内容>

  .LINK
    参考: <参考サイト概要>
      <URL>
#>
  Param(
    [Alias('h')][switch] $Help
  )
  if($Help){ Get-Help TemplateModule; return }

  #------------------------------
  # Main処理
  #------------------------------
}
Export-ModuleMember -Function TemplateModule

# Aliasも設定してExportする場合
# Set-Alias <alias> TemplateModule
# Export-ModuleMember -Function TemplateModule -Alias <alias>
```

なお、このテンプレートを作るうえで以下のサイトを参考にさせていただきました。

>
http://www.vwnet.jp/Windows/PowerShell/SupportGetHelp.htm
https://docs.microsoft.com/ja-jp/powershell/scripting/developer/module/how-to-write-a-powershell-script-module

## 解説

### 全体構成

まず、スクリプトモジュールの全体構成としては関数定義とexportの2つになります。この辺はJavaScriptのexportと似ていますね。

exportがない場合はモジュールファイル内のすべての関数がexportされるので明示的に指定した方がよいでしょう。
ちなみに変数もexportできますが、変数の場合は明示的に指定したものとグローバル変数 (`$global:hogehoge`) しかexportされないです。なのでモジュール内のトップレベルで変数を宣言しても影響はなさそうですね。

### ヘルプコメント

関数の最初に書かれているやたら長いコメントブロックはヘルプドキュメントで、`Get-Help` コマンドを実行したときに表示される内容です。

`Get-Help` コマンドをオプションなしで実行したときはこの中の SYNOPSIS, DESCRIPTION, LINK 項目と自動生成の NAME, SYNTAX 項目しか表示されませんが、`-Detailed` や `-Full` をつけるとほかの情報も見ることができます。

また自動生成関連でいうと、自動生成される SYNTAX 項目は関数の `Param()` を解析して自動で作ってくれますが、そこには CommonParameters というパラメータも追記されてしまいます。なのでパラメータ説明の1つにサポートしてない旨を注釈的に書いておくとよいと思います。（って参考サイトの筆者さんも言ってた）

### ヘルプオプションの追加

せっかくヘルプを標準装備にしたのでヘルプを表示するオプションもテンプレートに加えてみました。

コマンドを実行する際に `-Help` または '-h' で自コマンドに対して `Get-Help` を実行するようにしました。

ほかにもパラメータが1つでも仕様にマッチしていなければヘルプに飛ばすという処理を入れてもいいかもしれないですね。

## モジュールのImport

上記のテンプレートで作成したモジュールは `Import-Module` コマンドで読み込むことができます。

ちなみに自分が開発中にハマった点として、モジュールの内容を更新して再読み込みさせたい場合は `-Force` オプションをつけると上書きしてくれます。

## VSCodeスニペット登録

上記のテンプレートを使うために毎回コピペをするのは面倒なので自分はVSCodeのスニペットに登録しました。

スニペットとは、例えばJavaファイルで `sysout` と打つと `System.out.println()` が入力されたり、HTMLファイルで `html` と打つとHTMLのひな型が入力される機能のことです。

VSCodeでは言語ごとに自作のスニペットを追加できるのでPowerShellのスニペットに上記のテンプレートを追加してみました。

```json:ps1.code-snippets
{
  "PowerShell Module": {
    "scope": "powershell",
    "prefix": "module",
    "body": [
      "function $1 {",
      "  <#",
      "  .SYNOPSIS",
      "    <コマンドの概要>",
      "  ",
      "  .DESCRIPTION",
      "    <コマンドの説明>",
      "  ",
      "  .PARAMETER Help|h",
      "    ヘルプを表示する",
      "  ",
      "  .PARAMETER <PARAM>",
      "    <パラメータの説明>",
      "  ",
      "  .PARAMETER CommonParameters",
      "    サポートしていません",
      "  ",
      "  .INPUTS",
      "    <入力の仕様>",
      "  ",
      "  .OUTPUTS",
      "    <出力の仕様>",
      "  ",
      "  .EXAMPLE",
      "    PS> $1",
      "      <コマンドのみ実行時の処理内容>",
      "  ",
      "  .EXAMPLE",
      "    PS> $1 -Help",
      "      ヘルプを表示する",
      "  ",
      "  .EXAMPLE",
      "    PS> $1 <PARAM>",
      "      <パラメータを指定したときの処理内容>",
      "  ",
      "  .LINK",
      "    参考: <参考サイト概要>",
      "    <URL>",
      "  #>",
      "  Param(",
      "    [Alias('h')][switch] $$Help",
      "  )",
      "  if($$Help){ Get-Help $1; return }",
      "",
      "  #------------------------------",
      "  # Main処理",
      "  #------------------------------",
      "  $2",
      "}",
      "# 関数をそのままExportする場合",
      "Export-ModuleMember -Function $1",
      "",
      "# Aliasも設定してExportする場合",
      "# Set-Alias <alias> $1",
      "# Export-ModuleMember -Function $1 -Alias <alias>",
      ""
    ],
    "description": "PowerShell Module Template"
  }
}
```

上記の内容を既存のPowerShellスニペットに追加するか、プロジェクトローカルのVSCode設定に上記設定ファイルを追加することで `module` と入力して候補からテンプレートを1発で入力することができます。
関数名の部分を`$1`で入力値を受け取るようにしているのでヘルプ内のExampleやExportコマンド部分にまとめて関数名を指定できます。

# さいごに

今回はスクリプトモジュールを1ファイルにまとめて作成しましたが、モジュールマニフェストファイル（`psd1`）にバージョンやExport範囲を指定する方法もあるみたいです。（むしろモジュールとしてはそちらのほうが標準セット？）

モジュールマニフェストも含めて作ることで PowerShell Gallery に公開して `Install-Module` でインストール可能になるみたいです。（PythonでいうところのpipやJavaScriptでいうところのnpmみたいなものですかね）
その辺は[こちらの記事](https://blog.shibata.tech/entry/2016/12/03/001019)が参考になりそうなのでいずれは自分も公開して記事にしたいですね。

最後に、今回作成したテンプレートを使って作ったいろいろなスクリプトモジュールをGitHubで公開しています。
あくまで自分が欲しい機能をモジュール化したものの詰め合わせなので万人に使えるかというと微妙ですが、興味があれば覗いてみてください。

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