PowerShellスクリプトの引数設計とモジュール化 ── 「動くスクリプト」から「人に渡せるスクリプト」へ

· · PowerShell, Windows, スクリプト, 自動化, 運用改善, 業務効率化, 既存資産活用, コマンドライン

「担当者が書いたPowerShellスクリプトが動いているが、その人しか触れない」「サーバー名やパスがコードのあちこちに直書きされていて、環境が変わるたびに本体を書き換えている」「引数を間違えて渡しても黙って動いてしまい、後で気づいた」── 運用自動化の相談で、スクリプトそのものよりも「スクリプトの渡し方・育て方」が問題になっているケースは非常に多いです。

個人の手元で動かすだけなら、変数直書きの「動くスクリプト」で困りません。しかし、タスクスケジューラに載せる、同僚に渡す、複数サーバーで使い回す、となった瞬間に、引数の設計と共通処理の整理が品質を決めます。幸いPowerShellには、この「人に渡せるスクリプト」への道具立てが言語機能として最初から用意されています。paramブロック、検証属性、コメントベースヘルプ、そしてモジュールです。

この記事では、中小企業の情シスや運用担当者がすでに持っている「動くスクリプト」を出発点に、引数設計 → 入力検証 → ヘルプと-WhatIf対応 → .psm1モジュール化 → 社内共有、という順で段階的に品質を引き上げる実務手順を整理します。PowerShell 7.xを基準にしつつ、Windows PowerShell 5.1しか使えない現場での注意点も都度補足します。

1. まず結論

  • 引数はparamブロックで宣言し、[CmdletBinding()]を付けて「高度な関数」にするのが出発点です。共通パラメーター(-Verbose、-ErrorActionなど)が自動で付き、未定義のパラメーターを渡すとバインドエラーになるため、タイプミスが黙って無視される事故を防げます。1
  • 必須の引数は[Parameter(Mandatory)]で宣言し、型を必ず付けます。必須指定を忘れた呼び出しは実行前に止まり、型が合わない値も実行前に弾かれます。2
  • 形式チェックはif文ではなく検証属性(ValidateSet/ValidateRange/ValidateScript/ValidateNotNullOrEmpty)に寄せます。検証に失敗すると関数は呼び出されず、「途中まで実行してから壊れる」を構造的に消せます。エラーは入口で早く出すのが原則です。2
  • オン/オフの引数は[switch]で宣言します。$trueや$falseを文字列で受け取る自己流のフラグ引数は、呼び出し側の事故のもとです。2
  • コメントベースヘルプ(.SYNOPSIS/.EXAMPLE)を書けば、自作コマンドにもGet-Helpが効きます。「使い方はコードを読んで」からの脱却が、人に渡す最低条件です。3
  • 変更系の関数はSupportsShouldProcessを宣言して-WhatIf/-Confirmに対応させます。呼び出し側が実行前に影響範囲を確認できることは、運用スクリプトの安全装置として費用対効果が最大です。4
  • 複数スクリプトで使い回す関数は.psm1モジュールに切り出し、$env:PSModulePath配下に置きます。置き場所さえ正しければImport-Module不要で自動読み込みされます。psd1マニフェストは「配る段階」で追加すれば十分です。5678
  • モジュールとスクリプトはGitでバージョン管理し、共有フォルダ配布では実行ポリシーとの関係に注意します。UNCパス上のスクリプトはRemoteSignedで実行を拒否されることがあります。9

2. paramブロックと[CmdletBinding()] ── 「高度な関数」への入口

まず、現場でよく見る「動くスクリプト」の典型はこうです。

# よくある例: 変数直書き。環境が変わるたびに本体を書き換えることになる
$logDir = "D:\Logs\AppA"
$days = 90
Get-ChildItem $logDir -Filter *.log |
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$days) }

これをparamブロックと[CmdletBinding()]で書き直します。

[CmdletBinding()]
param(
    # 必須。指定し忘れた呼び出しは実行前に止まる
    # (注: [string]は意図の明示であって拒否ではない。数値などは文字列へ自動変換されて
    #  渡ってくるため、厳密に弾きたい条件は後述の検証属性で書く)
    [Parameter(Mandatory)]
    [string]$LogDir,

    # 省略可能な引数には業務上安全な既定値を持たせる
    [int]$Days = 90
)

Get-ChildItem -LiteralPath $LogDir -Filter *.log -File |
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$Days) }

[CmdletBinding()]は「この関数(スクリプト)をコンパイル済みコマンドレットと同じ流儀で動かす」という宣言で、これを付けた関数は高度な関数(advanced function)になります。効果は3つあります。1

  • 共通パラメーターが自動で付く。-Verbose、-Debug、-ErrorAction、-ErrorVariableなどを自分で実装しなくても、呼び出し側が使えるようになります。スクリプト内のWrite-Verboseが-Verbose指定時だけ表示される、という標準的な振る舞いがそのまま手に入ります。
  • 引数の間違いが実行前に止まる。高度な関数では、未定義のパラメーター名や、対応する位置パラメーターのない余分な引数を渡すとパラメーターバインドが失敗します。-Dyas 30のようなタイプミスが黙って無視されて既定値で動いてしまう、という事故がなくなります。1
  • $PSCmdletが使える。後述するShouldProcessなど、コマンドレット向けの機能への入口です。10

Mandatoryを付けた引数が省略されると、PowerShellは実行前に入力を促します。「必須なのに渡し忘れたまま既定値で動いた」を防ぐ、最初の安全装置です。2 ひとつ注意があるとすれば、この「入力を促す」動きは無人実行と相性が悪いことです。タスクスケジューラからの起動で必須引数が漏れていると、誰も答えられないプロンプトでジョブが止まったままになりえます。無人実行では -NonInteractive を付けて起動し、プロンプトの代わりに即エラーで失敗させるのが定石です。

なお、関数名を付けて公開するときはVerb-Noun形式にし、動詞はGet-Verbで確認できる承認済み動詞から選びます。未承認の動詞でも動きますが、モジュールのインポート時に警告が出ます。11

3. 入力検証は入口で ── Validate属性で「エラーを早く」

引数の形式チェックを関数本体のif文で書くと、チェック漏れや「チェックより前に副作用が走る」バグが混入しがちです。PowerShellでは検証属性でパラメーター宣言に検証を同居させられます。検証は関数が呼び出される前に行われ、失敗すれば本体は1行も実行されません。2

[CmdletBinding()]
param(
    # 存在するフォルダーだけを受け付ける。$_ が検証対象の値
    [Parameter(Mandatory)]
    [ValidateScript({ Test-Path -LiteralPath $_ -PathType Container })]
    [string]$LogDir,

    # 保持日数は1〜3650日に制限。0や負数で「全ファイル対象」になる事故を防ぐ
    [ValidateRange(1, 3650)]
    [int]$Days = 90,

    # 選択肢を固定。タブ補完も効くようになる
    [ValidateSet('Zip', 'Move', 'ReportOnly')]
    [string]$Mode = 'ReportOnly',

    # 空文字・$nullを弾く。文字列引数の基本装備
    [ValidateNotNullOrEmpty()]
    [string]$ReportName = 'log-report',

    # オン/オフはswitch。指定すれば$true、省略すれば$false
    [switch]$IncludeSubfolders
)

使い分けの目安を整理します。

属性 用途 現場での典型例
ValidateSet 値を固定の選択肢に制限し、タブ補完を効かせる2 動作モード、環境名(Dev/Test/Prod)
ValidateRange 数値・日付の範囲制限2 保持日数、リトライ回数、ポート番号
ValidateScript 任意のスクリプトで検証。$falseか例外で失敗2 パスの存在確認、日付の前後関係
ValidateNotNullOrEmpty $null・空文字・空コレクションを拒否2 ほぼすべての文字列引数
ValidatePattern 正規表現での形式チェック2 伝票番号、ホスト名の命名規則

2点補足します。第一に、検証属性は宣言順に注意が必要です。型より後に検証属性を書くと、型変換前の値が検証されて予期しない失敗を招くことがあるため、属性 → 型 → 変数名の順で書くのが公式ドキュメント推奨のベストプラクティスです。2 第二に、ValidateScriptのErrorMessage引数(独自エラーメッセージ)はPowerShell 6以降の機能で、Windows PowerShell 5.1では使えません。2 5.1混在環境では、検証スクリプト内でthrowして自前のメッセージを出すか、既定メッセージのままにしておくのが無難です。

ValidateScriptで凝った検証を書き始めたら、それはテストを書くサインでもあります。検証ロジック自体の動作確認は「PesterによるPowerShellのテスト整備」で整理した型に載せると壊れにくくなります。

4. パイプライン入力の基本 ── ValueFromPipelineとprocessブロック

自作関数もGet-Content servers.txt | Test-AppServerのようにパイプラインで使えると、PowerShellの標準コマンドと同じ感覚で組み合わせられます。必要なのはValueFromPipelineの宣言と、processブロックの2つです。2

function Test-AppServer {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [string[]]$ComputerName
    )
    begin   { $results = @() }   # パイプライン処理の前に1回だけ実行
    process {
        # パイプラインから流れてくる要素ごとに実行される
        foreach ($name in $ComputerName) {
            $results += [pscustomobject]@{
                ComputerName = $name
                # -ComputerNameは5.1と7の両方で使える(7で追加された-TargetNameは5.1に無い)
                Reachable    = Test-Connection -ComputerName $name -Count 1 -Quiet
            }
        }
    }
    end     { $results }         # 最後に1回だけ実行
}

押さえるべき点は1つだけです。パイプライン入力を受けるならprocessブロックに処理を書くこと。processブロックがないと、パイプラインで複数の値を流しても最後の1件しか処理されない、という典型的なバグになります。10 beginとendは省略可能なので、迷ったら「processに本体、集計が要るならbegin/end」と覚えておけば実務では十分です。

5. Get-Helpと-WhatIfを効かせる ── 人に渡す最低条件

5.1. コメントベースヘルプ

PowerShell使いは、知らないコマンドに出会ったらまずGet-Helpを叩きます。自作関数がその文化に乗れるかどうかは、コメントベースヘルプを書いてあるかで決まります。特殊なキーワード付きコメントを書いておくだけで、Get-Helpが標準コマンドレットと同じ形式でヘルプを表示してくれます。3

5.2. SupportsShouldProcessと-WhatIf

削除・移動・設定変更を行う関数には、[CmdletBinding(SupportsShouldProcess)]を宣言します。これだけで-WhatIfと-Confirmパラメーターが自動で追加され、本体では$PSCmdlet.ShouldProcess()の戻り値で実際に変更を実行するかを分岐します。4

両方を組み込んだ、渡せる品質の関数の完成形はこうなります。

function Remove-OldAppLog {
    <#
    .SYNOPSIS
    指定フォルダーから保持期限を過ぎたログファイルを削除します。

    .DESCRIPTION
    LastWriteTimeが保持日数より古い*.logファイルを削除します。
    -WhatIfで削除対象の確認のみ行えます。

    .EXAMPLE
    Remove-OldAppLog -LogDir 'D:\Logs\AppA' -Days 90 -WhatIf
    削除対象を表示するだけで、実際には削除しません。
    #>
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory)]
        [ValidateScript({ Test-Path -LiteralPath $_ -PathType Container })]
        [string]$LogDir,

        [ValidateRange(1, 3650)]
        [int]$Days = 90
    )
    process {
        $limit = (Get-Date).AddDays(-$Days)
        # -Fileでフォルダーを除外する(".log"で終わる名前のフォルダーを誤って消さない)
        Get-ChildItem -LiteralPath $LogDir -Filter *.log -File |
            Where-Object { $_.LastWriteTime -lt $limit } |
            ForEach-Object {
                # ShouldProcessが$falseを返すのは -WhatIf 時と -Confirm で拒否された時
                if ($PSCmdlet.ShouldProcess($_.FullName, "削除")) {
                    Remove-Item -LiteralPath $_.FullName
                }
            }
    }
}

Remove-OldAppLog -LogDir D:\Logs\AppA -WhatIfと打てば「What if: …」の一覧が出るだけで何も消えません。変更系スクリプトを人に渡すときは、-WhatIfでのリハーサル手順をセットで渡す── これが当サイトで繰り返し勧めている運用の型です。実際のログ整理スクリプトへの組み込み例は「PowerShellスクリプト応用 ── ログ調査・アーカイブ・レポート化を安全に自動化する」で詳述しています。

なお、呼び出した先のコマンドまで-WhatIfが常に伝播することを過信しない、という注意も公式の解説記事にあります。確実を期すなら内側のRemove-Itemなどに-WhatIf:$WhatIfPreferenceを明示的に渡します。4

6. 共通処理を.psm1モジュールにする

6.1. .psm1とExport-ModuleMember

関数が育ってくると、複数のスクリプトから同じ関数を使いたくなります。コピペで増やすと修正が全コピーに波及しなくなるので、共通関数はスクリプトモジュール(.psm1)に切り出します。作り方は拍子抜けするほど簡単で、関数を書いたファイルを.psm1拡張子で保存するだけです。5

# AppOpsTools.psm1 ── 社内運用ツールの共通モジュール
function Remove-OldAppLog { <# 前章の関数 #> }
function Get-AppLogSummary { <# 集計関数 #> }

# 内部ヘルパー関数。外には見せない
function ConvertTo-InternalPath { <# ... #> }

# 公開する関数を明示する。書かなければ全関数が公開される
Export-ModuleMember -Function Remove-OldAppLog, Get-AppLogSummary

Export-ModuleMemberを書かない場合、モジュール内の関数とエイリアスはすべてエクスポートされます(変数はされません)。省略可能ですが、公開範囲を明示するのがベストプラクティスとされています。12 内部ヘルパーを隠しておけば、後で自由にリファクタリングできる余地が残ります。

6.2. 置き場所 ── $env:PSModulePathと自動読み込み

モジュールは$env:PSModulePathに列挙されたフォルダー配下に、モジュール名と同名のフォルダーを作って置きます(AppOpsTools\AppOpsTools.psm1)。フォルダー名とファイルのベース名が一致していないと、モジュールとして認識されません。65 既定の置き場所は次のとおりで、Windows PowerShell 5.1とPowerShell 7でパスが異なる点が現場のつまずきどころです。6

スコープ PowerShell 7 Windows PowerShell 5.1
自分専用(CurrentUser) $HOME\Documents\PowerShell\Modules $HOME\Documents\WindowsPowerShell\Modules
全ユーザー(AllUsers) $env:ProgramFiles\PowerShell\Modules $env:ProgramFiles\WindowsPowerShell\Modules

正しい場所に置けば、Import-Moduleを書かなくても、モジュール内のコマンドを最初に実行したときにPowerShellが自動でインポートします(モジュールの自動読み込み)。7 つまり利用者は「コマンドが最初から入っているかのように」使えます。試行錯誤中のモジュールをフルパスでImport-Moduleして動作確認し、固まったらPSModulePath配下に配置する、という流れが実務のリズムです。

2点、環境依存の注意があります。Documentsフォルダーの実体はOneDriveのフォルダーリダイレクトで移動していることがあり、その場合ユーザースコープのモジュールもOneDrive配下に置かれます。6 また全ユーザースコープへの配置には管理者権限が必要です。サーバーに置くならAllUsersスコープにして、タスクスケジューラの実行アカウントからも見えるようにしておくと、「自分の端末では動くのにサーバーで動かない」を避けられます。

6.3. psd1マニフェストは「配る段階」で

モジュールマニフェスト(.psd1)は、モジュールのバージョンや依存関係などのメタデータを記述するハッシュテーブルのファイルで、必須ではありません。マニフェストで必須のキーはModuleVersionだけです。8 自分のチーム内で使っている段階では.psm1単体で十分で、他部署へ配る・バージョン管理を厳密にする段階になったらNew-ModuleManifestで生成します。8

New-ModuleManifest -Path .\AppOpsTools\AppOpsTools.psd1 `
    -RootModule 'AppOpsTools.psm1' `
    -ModuleVersion '1.0.0' `
    -FunctionsToExport 'Remove-OldAppLog', 'Get-AppLogSummary' `
    -PowerShellVersion '5.1'

生成されたpsd1はコメント付きのテンプレートになっているので、必要なキーだけ育てていけます。8

6.4. 社内共有とバージョン管理の勘所

  • 原本はGitに置きます。スクリプトとモジュールはテキストなのでGitと相性がよく、「いつ、誰が、なぜ変えたか」が追えることが運用スクリプトの信頼性そのものになります。ModuleVersionの更新をコミットと対応させておくと、サーバーに入っている版の特定が楽になります。
  • 配布は「共有フォルダから各マシンのPSModulePath配下へコピー」が基本形です。モジュールのフォルダーごとコピーすれば手動インストールできます。7 共有フォルダ上のパスを直接PSModulePathに足す構成は、共有が「遅い・切れる・いないことがある」前提(詳細は「ネットワークドライブとUNCパスの落とし穴」)を踏まえると、常用はお勧めしません。
  • 実行ポリシーとの関係に注意します。既定のRemoteSignedはローカル作成の無署名スクリプトを許可しますが、UNCパスとインターネットパスを区別しないシステムでは、UNCパス上のスクリプトが実行を拒否されることがあります。またダウンロード由来のマークが付いたファイルはブロックされ、Unblock-Fileでの解除か署名が必要です。9 社内配布を本格化するなら、コード署名との組み合わせを「PowerShellの実行ポリシーとスクリプト署名」で確認してください。

7. 実務の定石(判断表)

論点 選択肢 判断の目安
引数の受け取り 変数直書き / paramブロック 2回以上使う・他人が使うならparam一択。既定値は「安全側」に倒す2
[CmdletBinding()] 付けない / 付ける 人に渡すもの・運用に載せるものは常に付ける。タイプミスが実行前に止まる1
入力チェック 本体のif文 / 検証属性 単一パラメーターの形式チェックは属性へ。組み合わせ検証だけ本体で2
変更系の安全装置 独自の-TestMode引数 / SupportsShouldProcess 自前フラグは作らない。標準の-WhatIf/-Confirmに乗る4
共通処理の持ち方 コピペ / ドットソース / .psm1モジュール 2スクリプト目で共有した時点でモジュール化。公開関数はExport-ModuleMemberで明示512
モジュールの置き場所 任意フォルダー+Import-Module / PSModulePath配下 常用するものは規定の場所へ置いて自動読み込みに乗せる。サーバーはAllUsersスコープ67
psd1マニフェスト 最初から作る / 配る段階で作る チーム外へ出す・バージョン管理を厳密にする段階でNew-ModuleManifest8

8. まとめ

  • paramブロックと[CmdletBinding()]で高度な関数にすることが「人に渡せるスクリプト」の出発点です。共通パラメーターが付き、引数の間違いが実行前に止まります。
  • 型指定・[Parameter(Mandatory)]・安全側の既定値・検証属性で、エラーを入口で早く出します。ValidateSetはタブ補完という使い勝手も向上させます。
  • パイプライン入力はValueFromPipelineとprocessブロックのセットで受けます。processを忘れると最後の1件しか処理されません。
  • コメントベースヘルプでGet-Helpを効かせ、変更系はSupportsShouldProcessで-WhatIfに対応させます。リハーサルできることが運用の安全装置になります。
  • 共通関数は.psm1に切り出し、Export-ModuleMemberで公開範囲を明示して、PSModulePath配下に配置します。5.1と7でパスが違う点に注意してください。
  • psd1マニフェストは配る段階で。原本はGitで管理し、共有フォルダ配布では実行ポリシー(UNCパスとRemoteSignedの関係)を確認します。

関連記事

関連する相談領域

合同会社小村ソフトでは、属人化したPowerShellスクリプトの整理・モジュール化、運用自動化スクリプトの設計レビュー、社内配布・バージョン管理の仕組みづくりを扱っています。「動いてはいるが誰も触れない」スクリプト資産の棚卸しからでもご相談いただけます。

参考リンク

  1. Microsoft Learn, about_Functions_CmdletBindingAttribute. CmdletBinding属性が関数をコンパイル済みコマンドレットのように動作させること、共通パラメーターが自動追加されること、$PSCmdletが使えるようになること、未知のパラメーターや対応しない位置引数でバインドが失敗すること、SupportsShouldProcessがConfirm/WhatIfパラメーターを追加することについて。  2 3 4

  2. Microsoft Learn, about_Functions_Advanced_Parameters. Parameter属性とMandatory、ValueFromPipeline、switchパラメーター、ValidateSet/ValidateRange/ValidateScript/ValidateNotNullOrEmpty/ValidatePatternなどの検証属性の仕様、検証失敗時に関数が呼び出されないこと、属性を型より前に宣言するのがベストプラクティスであること、ValidateScriptのErrorMessage引数がPowerShell 6以降であることについて。  2 3 4 5 6 7 8 9 10 11 12 13 14 15

  3. Microsoft Learn, about_Comment_Based_Help. .SYNOPSIS/.DESCRIPTION/.PARAMETER/.EXAMPLEなどのキーワードでコメントベースヘルプを書くと、Get-HelpがXMLヘルプと同じ形式で表示すること、スクリプトと関数それぞれでの配置ルールについて。  2

  4. Microsoft Learn, Everything you wanted to know about ShouldProcess. SupportsShouldProcessの指定だけで-WhatIf/-Confirmが自動作成されること、$PSCmdlet.ShouldProcess()での分岐の書き方、-WhatIfの伝播を過信せず内側のコマンドに明示的に渡すことが推奨される点について。  2 3 4

  5. Microsoft Learn, How to Write a PowerShell Script Module. .psm1拡張子で保存するだけでスクリプトモジュールになること、スクリプトと同名のフォルダーに保存すること、既定では全関数が公開され変数は公開されないこと、Export-ModuleMemberで公開する関数を明示することが推奨されることについて。  2 3 4

  6. Microsoft Learn, about_PSModulePath. $env:PSModulePathがモジュール検索フォルダーの一覧であること、PowerShell 7とWindows PowerShell 5.1でCurrentUser/AllUsersスコープの既定パスが異なること、OneDriveやフォルダーリダイレクトでDocumentsの場所が変わりうることについて。  2 3 4 5

  7. Microsoft Learn, about_Modules. PSModulePath配下のモジュールはコマンド初回実行時に自動インポートされること(モジュール自動読み込み)、モジュールフォルダーごとコピーする手動インストールの方法、既定のモジュール配置場所について。  2 3 4

  8. Microsoft Learn, New-ModuleManifest. モジュールマニフェスト(.psd1)がモジュールの内容・属性・前提条件を記述するハッシュテーブルであり必須ではないこと、必須キーがModuleVersionのみであること、New-ModuleManifestがテンプレートとして使える雛形を生成することについて。  2 3 4 5

  9. Microsoft Learn, about_Execution_Policies. RemoteSignedがローカル作成の無署名スクリプトを許可しインターネット由来のスクリプトに署名を要求すること、UNCパスとインターネットパスを区別しないシステムではUNCパス上のスクリプトがRemoteSignedで実行を許可されないことがあること、Unblock-Fileによるブロック解除について。  2

  10. Microsoft Learn, about_Functions_Advanced_Methods. 高度な関数で使えるbegin/process/endの入力処理メソッド、ShouldProcessメソッドがprocessブロック内から呼び出されCmdletBinding属性での宣言が必要であることについて。  2

  11. Microsoft Learn, Approved Verbs for PowerShell Commands. コマンド名がVerb-Noun形式であるべきこと、承認済み動詞の一覧とGet-Verbでの確認方法、未承認動詞を含むモジュールのインポート時に警告が表示されることについて。 

  12. Microsoft Learn, Export-ModuleMember. Export-ModuleMemberがスクリプトモジュールからエクスポートするメンバーを指定するコマンドレットであること、未指定時は関数とエイリアスがエクスポートされ変数はされないこと、省略可能だが作者の意図を示すベストプラクティスであることについて。  2

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

PowerShellのparamブロックに[CmdletBinding()]を付けると何が変わりますか?
関数やスクリプトが「高度な関数(advanced function)」として扱われ、コンパイル済みコマンドレットと同じ振る舞いを手に入れます。具体的には-Verboseや-ErrorActionなどの共通パラメーターが自動で追加され、$PSCmdlet変数が使えるようになり、未定義のパラメーターや余分な位置引数を渡すとバインドエラーになります。タイプミスした引数が黙って無視されなくなるため、運用スクリプトでは付けるのが基本です。
スクリプトの引数チェックはValidate属性とif文のどちらで書くべきですか?
パラメーターの形式チェックはValidateSetやValidateRange、ValidateScriptなどの検証属性に寄せるのが定石です。検証は関数本体が実行される前に行われ、不正な値なら処理が1行も走らずにエラーになるため、「途中まで実行されてから壊れる」事故を防げます。ValidateSetにはタブ補完が効くという実利もあります。一方、複数パラメーターの組み合わせ検証や実行時の状態に依存するチェックは本体側のif文で行います。
PowerShellの自作モジュール(.psm1)はどこに置けばよいですか?
$env:PSModulePathに含まれるフォルダー配下に「モジュール名と同名のフォルダー」を作って置きます。自分専用ならPowerShell 7では$HOME\Documents\PowerShell\Modules、全ユーザー共通なら$env:ProgramFiles\PowerShell\Modulesが既定です。Windows PowerShell 5.1ではそれぞれWindowsPowerShell\Modulesとパスが異なる点に注意してください。この場所に置けば、Import-Moduleを書かなくてもコマンド初回実行時に自動読み込みされます。
モジュールマニフェスト(psd1)は必ず作る必要がありますか?
必須ではありません。マニフェストなしの.psm1単体でもモジュールとして動作します。マニフェストが必要になるのは「配る段階」で、バージョン番号、必要なPowerShellバージョン、依存モジュール、エクスポートするコマンドの明示などのメタデータを持たせたいときにNew-ModuleManifestで生成します。マニフェストで必須のキーはModuleVersionだけなので、まずは最小構成で始めて必要に応じて育てれば十分です。
社内の共有フォルダに置いたスクリプトが実行ポリシーでブロックされるのはなぜですか?
既定のRemoteSignedポリシーは、ローカルで作成されたスクリプトは無署名でも実行を許可しますが、インターネット由来とマークされたスクリプトには署名を要求します。UNCパスとインターネットパスを区別しない構成のシステムでは、共有フォルダ上のスクリプトがRemoteSignedで実行を拒否されることがあると公式ドキュメントにも明記されています。社内配布を本格化するなら、コード署名とAllSignedの組み合わせ、またはイントラネットゾーンの構成を検討してください。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る