Kapitola 10 – Skriptovací moduly

Pokud zjistíte, že používáte stejné one-linery nebo skripty PowerShellu často, je jejich přeměna na opakovaně použitelné nástroje ještě důležitější. Zabalení funkcí do modulu skriptu jim dává profesionální pocit a usnadňuje jejich podporu a sdílení s ostatními.

Funkce dot-sourcingu

Jedna věc, kterou jsme nepokryli v předchozí kapitole, je funkce dot-sourcing. Když definujete funkci ve skriptu, která není součástí modulu, jediný způsob, jak ji načíst do paměti, je použitím dot-sourcing jejího .ps1 souboru.

Například uložte následující funkci do souboru s názvem Get-MrPSVersion.ps1.

function Get-MrPSVersion {
    $PSVersionTable
}

Když skript spustíte, zdá se, že se nic nestane.

.\Get-MrPSVersion.ps1

Při pokusu o volání funkce dojde k chybě, protože není načtena do paměti.

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

Ověřením jejich existence ve funkci : PSDrive můžete ověřit, jestli jsou funkce načtené do paměti.

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

Problém se spuštěním skriptu, který definuje funkci, je, že ji načte do oboru Script . Jakmile se skript dokončí, PowerShell tento obor společně s funkcí zahodí.

Aby byla funkce po spuštění skriptu dostupná, musí být načtena do Globálního oboru. Toho dosáhnete tak, že zdrojový soubor skriptu načtete pomocí bodového zahrnutí. Pro tento účel můžete použít relativní cestu.

. .\Get-MrPSVersion.ps1

Když provádíte dot-sourcing skriptu, můžete také použít jeho úplnou cestu.

. C:\Demo\Get-MrPSVersion.ps1

Pokud je část cesty uložená v proměnné, můžete ji zkombinovat se zbytkem cesty. K tomu není potřeba používat zřetězení řetězců.

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

Pokud teď zkontrolujete funkci PSDrive, uvidíte, že Get-MrPSVersion je tato funkce dostupná.

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

Moduly skriptů

V PowerShellu je modul skriptu jednoduše .psm1 soubor, který obsahuje jednu nebo více funkcí, stejně jako běžný skript, ale s jinou příponou souboru.

Jak vytvoříte modul skriptu? Můžete předpokládat, že příkaz má název podobně jako New-Module. Tento předpoklad je rozumný odhad, ale tento příkaz ve skutečnosti vytvoří dynamický modul, nikoli skriptovací modul.

Tento scénář je dobrým připomenutím, abyste si vždy přečetli dokumentaci nápovědy, i když název příkazu vypadá přesně tak, jak potřebujete.

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"

Předchozí kapitola zmínila, že funkce by měly používat schválené příkazy. V opačném případě PowerShell při importu modulu vygeneruje upozornění.

Následující příklad používá rutinu New-Module k vytvoření dynamického modulu v paměti, konkrétně k předvedení toho, co se stane, když nepoužíváte schválené příkazy.

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.

Přestože jste rutinu New-Module použili v předchozím příkladu, jak už jsme zmínili dříve, nejedná se o příkaz pro vytváření modulů skriptů v PowerShellu.

Pokud chcete vytvořit modul skriptu, uložte funkce do .psm1 souboru. Například uložte následující dvě funkce do souboru s názvem MyScriptModule.psm1.

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Zkuste spustit jednu z těchto funkcí.

Get-MrComputerName

Při volání funkce se zobrazí chyba s informací, že PowerShell ji nemůže najít. Stejně jako předtím zkontrolujte funkci: PSDrive potvrdí, že není načtena do paměti.

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

Pokud chcete funkci zpřístupnit, můžete soubor MyScriptModule.psm1 ručně importovat pomocí rutiny Import-Module.

Import-Module C:\MyScriptModule.psm1

PowerShell zavedl automatické načítání modulu ve verzi 3. Pokud chcete tuto funkci využít, musí se modul skriptu uložit do složky se stejným základním názvem jako soubor .psm1 . Tato složka musí být umístěná v jednom z adresářů zadaných v $env:PSModulePath proměnné prostředí.

$env:PSModulePath

Výstup $env:PSModulePath je obtížně čitelný.

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\

Aby byly výsledky čitelnější, rozdělte cesty podle oddělovače středníkem, aby se každá zobrazila na vlastním řádku.

$env:PSModulePath -split ';'

První tři cesty v seznamu jsou výchozí umístění modulů. SQL Server Management Studio přidal poslední cestu, když jste ji nainstalovali.

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\

Aby automatické načítání modulu fungovalo, musíte soubor umístit MyScriptModule.psm1 do složky s názvem MyScriptModulea tato složka se musí nacházet přímo v jedné z cest uvedených v
$env:PSModulePath.

Ne všechny tyto cesty jsou stejně užitečné. Například aktuální cesta uživatele v mém systému není první v seznamu. Je to proto, že se přihlásím k Windows pomocí jiného účtu, než který používám ke spuštění PowerShellu. Proto neodkazuje na složku dokumentů mého uživatele.

Druhou cestou je cesta AllUsers , kde ukládám všechny moduly.

Třetí cesta odkazuje na C:\Windows\System32, chráněné umístění systému. Moduly by tam měl umístit pouze Microsoft, protože spadá do adresářové struktury operačního systému.

Jakmile soubor umístíte .psm1 do příslušné složky v některé z těchto cest, PowerShell automaticky načte modul při prvním volání jednoho z jeho příkazů.

Manifesty modulů

Každý modul by měl obsahovat manifest modulu, což je .psd1 soubor obsahující metadata o modulu. I když se .psd1 rozšíření používá pro manifesty, ne všechny .psd1 soubory jsou manifesty modulů. Můžete je také použít pro jiné účely, například pro definování dat prostředí v DSC.
konfigurace.

Manifest modulu můžete vytvořit pomocí rutiny New-ModuleManifest . Jediný povinný parametr je Path, ale aby modul fungoval správně, musíte také zadat parametr RootModule .

Osvědčeným postupem je zahrnout hodnoty jako Autor a Popis, zejména pokud plánujete publikovat modul do úložiště NuGet pomocí modulu PowerShellGet. Tato pole jsou v tomto scénáři povinná.

Jedním z rychlých způsobů, jak zjistit, jestli modul nemá manifest, je zkontrolovat jeho verzi.

Get-Module -Name MyScriptModule

Číslo 0.0 verze je jasné znamení, že modul nemá manifest.

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

Při vytváření manifestu modulu byste měli zahrnout všechny doporučené podrobnosti, abyste měli jistotu, že je modul dobře zdokumentovaný a připravený ke sdílení nebo publikování.

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

New-ModuleManifest @moduleManifestParams

Pokud při počátečním vytvoření manifestu modulu vynecháte nějaké hodnoty, můžete je později přidat nebo aktualizovat pomocí rutiny Update-ModuleManifest . Vyhněte se opětovnému vytvoření manifestu pomocí New-ModuleManifest poté, co jej vytvoříte, protože tím se vygeneruje nový identifikátor GUID.

Definování veřejných a privátních funkcí

Někdy může váš modul obsahovat pomocné funkce, které nechcete zpřístupnit uživatelům. Tyto privátní funkce se používají interně jinými funkcemi v modulu, ale nejsou přístupné uživatelům. Existuje několik způsobů, jak tento scénář zpracovat.

Pokud nepoužíváte osvědčené postupy a máte .psm1 jenom soubor bez manifestu modulu, jedinou možností je řídit viditelnost pomocí rutiny Export-ModuleMember . Tato možnost umožňuje explicitně definovat, které funkce by měly být vystaveny přímo ze .psm1 souboru modulu skriptu, a ponechat vše ostatní ve výchozím nastavení soukromé.

V následujícím příkladu je uživatelům vašeho modulu vystavena pouze funkce Get-MrPSVersion, zatímco funkce Get-MrComputerName zůstává přístupná interně pro jiné funkce v rámci modulu.

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Export-ModuleMember -Function Get-MrPSVersion

Určete, které příkazy jsou veřejně dostupné v modulu MyScriptModule .

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

Pokud do modulu přidáte manifest modulu, je osvědčeným postupem explicitně vypsat funkce, které chcete exportovat v části FunctionsToExport . Tato možnost vám dává kontrolu nad tím, co zpřístupňujete uživatelům ze souboru manifestu .psd1 modulu.

FunctionsToExport = 'Get-MrPSVersion'

Nepotřebujete používat Export-ModuleMember jak v souboru .psm1, tak v části FunctionsToExport manifestu modulu. Oba přístupy jsou samy o sobě dostatečné.

Shrnutí

V této kapitole jste se naučili, jak v PowerShellu převést funkce na modul skriptu. Prozkoumali jste také osvědčené postupy pro vytváření modulů skriptů, včetně důležitosti přidání manifestu modulu pro definování metadat a správy exportovaných příkazů.

Přezkoumání

  1. Jak v PowerShellu vytvoříte modul skriptu?
  2. Proč je důležité používat schválené příkazy pro názvy funkcí?
  3. Jak v PowerShellu vytvoříte manifest modulu?
  4. Jaké jsou dva způsoby exportu pouze konkrétních funkcí z modulu?
  5. Jaké podmínky musí být splněny, aby se modul při spuštění jednoho z jeho příkazů automaticky načítá?

Odpovědi na otázky ke kontrole najdete v dodatku této knihy.

Odkazy