次の方法で共有


第 10 章 - スクリプト モジュール

同じ PowerShell ワンライナーまたはスクリプトを頻繁に使用している場合は、それらを再利用可能なツールに変換することがさらに重要です。 スクリプト モジュールに関数をパッケージ化すると、よりプロフェッショナルな操作性が得られ、他のユーザーとのサポートや共有が容易になります。

ドット ソーシング関数

前の章で取り上げなかった点の 1 つは、ドット ソーシング関数です。 スクリプトで関数を定義し、モジュールの一部ではない場合、メモリに読み込む唯一の方法は、 .ps1 ファイルをドット ソーシングすることです。

たとえば、次の関数を Get-MrPSVersion.ps1 という名前のファイルに保存します。

function Get-MrPSVersion {
    $PSVersionTable
}

スクリプトを実行すると、何も起こっていないように見えます。

.\Get-MrPSVersion.ps1

関数を呼び出そうとすると、メモリに読み込まれていないため、エラーが発生します。

Get-MrPSVersion
Get-MrPSVersion : The term 'Get-MrPSVersion' is not recognized as the name
of a cmdlet, function, script file, or operable program. Check the spelling
of the name, or if a path was included, verify that the path is correct and
try again.
At line:1 char:1
+ Get-MrPSVersion
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Get-MrPSVersion:String) [],
   CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

関数がメモリに読み込まれているかどうかを確認するには、 Function: PSDrive に関数が存在することを確認します。

Get-ChildItem -Path Function:\Get-MrPSVersion
Get-ChildItem : Cannot find path 'Get-MrPSVersion' because it does not
exist.
At line:1 char:1
+ Get-ChildItem -Path Function:\Get-MrPSVersion
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Get-MrPSVersion:String) [Get
   -ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.Ge
   tChildItemCommand

関数を定義するスクリプトを実行する場合の問題は、 スクリプト スコープに読み込まれることです。 スクリプトの実行が完了すると、PowerShell はそのスコープを関数と共に破棄します。

スクリプトの実行後に関数を使用できるようにするには、 グローバル スコープに読み込む必要があります。 これを実現するには、スクリプト ファイルをドット ソーシングします。 この目的には相対パスを使用できます。

. .\Get-MrPSVersion.ps1

また、ドット ソーシング時にスクリプトへの完全パスを使用することもできます。

. C:\Demo\Get-MrPSVersion.ps1

パスの一部が変数に格納されている場合は、それをパスの残りの部分と組み合わせることができます。 これを行うために文字列連結を使用する必要はありません。

$Path = 'C:\'
. $Path\Get-MrPSVersion.ps1

関数 PSDrive を確認すると、 Get-MrPSVersion 関数が使用できることがわかります。

Get-ChildItem -Path Function:\Get-MrPSVersion
CommandType     Name                                               Version
-----------     ----                                               -------
Function        Get-MrPSVersion

スクリプト モジュール

PowerShell では、スクリプト モジュールは、通常のスクリプトと同様に、ファイル拡張子が異なる 1 つ以上の関数を含む単なる .psm1 ファイルです。

スクリプト モジュールを作成する方法 New-Moduleのような名前のコマンドがあると仮定するかもしれません。 この前提は妥当な推測ですが、そのコマンドは実際にはスクリプト モジュールではなく動的モジュールを作成します。

このシナリオは、コマンド名が必要とまったく同じように見える場合でも、常にヘルプ ドキュメントを読むのに適しています。

help New-Module
NAME
    New-Module

SYNOPSIS
    Creates a new dynamic module that exists only in memory.


SYNTAX
    New-Module [-Name] <System.String> [-ScriptBlock]
    <System.Management.Automation.ScriptBlock> [-ArgumentList
    <System.Object[]>] [-AsCustomObject] [-Cmdlet <System.String[]>]
    [-Function <System.String[]>] [-ReturnResult] [<CommonParameters>]


DESCRIPTION
    The `New-Module` cmdlet creates a dynamic module from a script block.
    The members of the dynamic module, such as functions and variables, are
    immediately available in the session and remain available until you
    close the session.

    Like static modules, by default, the cmdlets and functions in a dynamic
    module are exported and the variables and aliases are not. However, you
    can use the Export-ModuleMember cmdlet and the parameters of
    `New-Module` to override the defaults.

    You can also use the **AsCustomObject** parameter of `New-Module` to return
    the dynamic module as a custom object. The members of the modules, such
    as functions, are implemented as script methods of the custom object
    instead of being imported into the session.

    Dynamic modules exist only in memory, not on disk. Like all modules,
    the members of dynamic modules run in a private module scope that is a
    child of the global scope. Get-Module cannot get a dynamic module, but
    Get-Command can get the exported members.

    To make a dynamic module available to `Get-Module`, pipe a `New-Module`
    command to Import-Module, or pipe the module object that `New-Module`
    returns to `Import-Module`. This action adds the dynamic module to the
    `Get-Module` list, but it does not save the module to disk or make it
    persistent.


RELATED LINKS
    Online Version: https://learn.microsoft.com/powershell/module/microsoft.
    powershell.core/new-module?view=powershell-5.1&WT.mc_id=ps-gethelp
    Export-ModuleMember
    Get-Module
    Import-Module
    Remove-Module
    about_Modules

REMARKS
    To see the examples, type: "Get-Help New-Module -Examples".
    For more information, type: "Get-Help New-Module -Detailed".
    For technical information, type: "Get-Help New-Module -Full".
    For online help, type: "Get-Help New-Module -Online"

前の章では、関数は承認済みの動詞を使用する必要があることを説明しました。 それ以外の場合、モジュールがインポートされると、PowerShell によって警告が生成されます。

次の例では、 New-Module コマンドレットを使用してメモリ内に動的モジュールを作成します。具体的には、承認された動詞を使用しない場合の動作を示します。

New-Module -Name MyModule -ScriptBlock {

    function Return-MrOsVersion {
        Get-CimInstance -ClassName Win32_OperatingSystem |
        Select-Object -Property @{Label='OperatingSystem';Expression={$_.Caption}}
    }

    Export-ModuleMember -Function Return-MrOsVersion

} | Import-Module
WARNING: The names of some imported commands from the module 'MyModule' include
unapproved verbs that might make them less discoverable. To find the commands with
unapproved verbs, run the Import-Module command again with the Verbose parameter. For a
list of approved verbs, type Get-Verb.

前の例で New-Module コマンドレットを使用しましたが、PowerShell でスクリプト モジュールを作成するためのコマンドではありません。

スクリプト モジュールを作成するには、関数を .psm1 ファイルに保存します。 たとえば、次の 2 つの関数を MyScriptModule.psm1 という名前のファイルに保存します。

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

関数の 1 つを実行してみてください。

Get-MrComputerName

関数を呼び出すと、PowerShell で見つからないというエラーが表示されます。 前と同様に、 関数を 確認すると、PSDrive はメモリに読み込まれていないことを確認します。

Get-MrComputerName : The term 'Get-MrComputerName' is not recognized as the
name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is
correct and try again.
At line:1 char:1
+ Get-MrComputerName
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Get-MrComputerName:String) [
   ], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

関数を使用できるようにするには、MyScriptModule.psm1 コマンドレットを使用してImport-Module ファイルを手動でインポートします。

Import-Module C:\MyScriptModule.psm1

PowerShell では、バージョン 3 でモジュールの自動読み込みを導入しました。 この機能を利用するには、スクリプト モジュールを、 .psm1 ファイルと同じベース名のフォルダーに保存する必要があります。 そのフォルダーは、 $env:PSModulePath 環境変数で指定されたディレクトリのいずれかに配置する必要があります。

$env:PSModulePath

$env:PSModulePathの出力は読みにくいです。

C:\Users\mike-ladm\Documents\WindowsPowerShell\Modules;C:\Program Files\Wind
owsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\
Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\

結果を読みやすくするには、セミコロンパス区切り記号のパスを分割して、それぞれのパスが独自の行に表示されるようにします。

$env:PSModulePath -split ';'

一覧の最初の 3 つのパスは、既定のモジュールの場所です。 SQL Server Management Studio では、インストール時に最後のパスが追加されました。

C:\Users\mike-ladm\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules
C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\

モジュールの自動読み込みを機能させるには、 MyScriptModule.psm1 ファイルを MyScriptModule という名前のフォルダーに配置する必要があります。そのフォルダーは、次に示すパスの 1 つ内に直接存在する必要があります。
$env:PSModulePath

これらのパスがすべて同じように役に立つわけではありません。 たとえば、システム上の現在のユーザー パスは、一覧の最初のユーザー パスではありません。 これは、PowerShell の実行に使用するアカウントとは異なるアカウントで Windows にサインインするためです。 そのため、そのフォルダーは私のユーザーのドキュメントフォルダーを指していません。

2 番目のパスは AllUsers パスです。このパスには、すべてのモジュールが格納されます。

3 番目のパスは、保護されたシステムの場所である C:\Windows\System32を指します。 オペレーティング システムのディレクトリ構造に該当するモジュールは、Microsoft のみがそこに配置する必要があります。

これらのパスの 1 つ内の適切なフォルダーに .psm1 ファイルを配置すると、そのコマンドのいずれかを初めて呼び出すと、PowerShell によってモジュールが自動的に読み込まれます。

モジュール マニフェスト

すべてのモジュールには、モジュール に関するメタデータを含む .psd1 ファイルであるモジュール マニフェストを含める必要があります。 .psd1拡張機能はマニフェストに使用されますが、すべての.psd1 ファイルがモジュール マニフェストであるわけではありません。 DSC での環境データの定義など、他の目的にも使用できます。
構成。

New-ModuleManifest コマンドレットを使用してモジュール マニフェストを作成できます。 必要なパラメーターは Path だけですが、モジュールが正しく機能するためには、 RootModule パラメーターも指定する必要があります。

特に PowerShellGet を使用してモジュールを NuGet リポジトリに発行する場合は、AuthorDescription などの値を含めるのがベスト プラクティスです。 このシナリオでは、これらのフィールドが必要です。

モジュールにマニフェストがないかどうかを簡単に確認する方法の 1 つは、そのバージョンを確認することです。

Get-Module -Name MyScriptModule

0.0のバージョン番号は、モジュールにマニフェストがないことを明確に示しています。

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.0        MyScriptModule                      {Get-MrComputer...

モジュール マニフェストを作成するときに推奨されるすべての詳細を含めて、モジュールが適切に文書化され、共有または発行の準備ができていることを確認する必要があります。

$moduleManifestParams = @{
    Path = "$env:ProgramFiles\WindowsPowerShell\Modules\MyScriptModule\MyScriptModule.psd1"
    RootModule = 'MyScriptModule'
    Author = 'Mike F. Robbins'
    Description = 'MyScriptModule'
    CompanyName = 'mikefrobbins.com'
}

New-ModuleManifest @moduleManifestParams

モジュール マニフェストを最初に作成するときに値を省略した場合は、後で Update-ModuleManifest コマンドレットを使用して追加または更新できます。 作成すると新しい GUID が生成されるため、 New-ModuleManifest を使用してマニフェストを再作成することは避けてください。

パブリック関数とプライベート関数の定義

モジュールに、ユーザーに公開したくないヘルパー関数が含まれている場合があります。 これらのプライベート関数は、モジュール内の他の関数によって内部的に使用されますが、ユーザーには公開されません。 このシナリオを処理するには、いくつかの方法があります。

ベスト プラクティスに従っていなくても、適切なモジュール構造を持たない .psm1 ファイルしかない場合は、 Export-ModuleMember コマンドレットを使用して可視性を制御するしかありません。 このオプションを使用すると、 .psm1 スクリプト モジュール ファイル内から直接公開する必要がある関数を明示的に定義し、それ以外のすべてを既定でプライベートに保ちます。

次の例では、 Get-MrPSVersion 関数のみがモジュールのユーザーに公開されますが、 Get-MrComputerName 関数はモジュール内の他の関数から内部的にアクセスできます。

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Export-ModuleMember -Function Get-MrPSVersion

MyScriptModule モジュールでパブリックに使用できるコマンドを決定します。

Get-Command -Module MyScriptModule
CommandType     Name                                               Version
-----------     ----                                               -------
Function        Get-MrPSVersion                                    1.0

モジュール マニフェストをモジュールに追加する場合は、 FunctionsToExport セクションでエクスポートする関数を明示的に一覧表示することをお勧めします。 このオプションを使用すると、 .psd1 モジュール マニフェスト ファイルからユーザーに公開する内容を制御できます。

FunctionsToExport = 'Get-MrPSVersion'

Export-ModuleMember ファイルの.psm1とモジュール マニフェストの FunctionsToExport セクションの両方を使用する必要はありません。 どちらの方法でも、単独で十分です。

概要

この章では、PowerShell で関数をスクリプト モジュールに変換する方法について説明しました。 また、メタデータを定義し、エクスポートされたコマンドを管理するためにモジュール マニフェストを追加することの重要性など、スクリプト モジュールを作成するためのベスト プラクティスについても説明しました。

レビュー

  1. PowerShell でスクリプト モジュールを作成する方法
  2. 関数名に承認済みの動詞を使用することが重要なのはなぜですか?
  3. PowerShell でモジュール マニフェストを作成する方法
  4. モジュールから特定の関数のみをエクスポートする 2 つの方法は何ですか?
  5. いずれかのコマンドを実行するときにモジュールを自動読み込みするには、どのような条件を満たす必要がありますか?

リファレンス