Rozdział 10 — moduły skryptów

Przekształcenie elementów jednowierszowych i skryptów w programie PowerShell w narzędzia wielokrotnego użytku staje się jeszcze ważniejsze, jeśli jest to coś, czego będziesz używać często. Pakowanie funkcji w module skryptu sprawia, że wyglądają i czują się bardziej profesjonalnie i ułatwiają ich udostępnianie.

Dot-Sourcing Functions

Coś, o czym nie rozmawialiśmy w poprzednim rozdziale, to funkcje dot-sourcing. Jeśli funkcja w skrypcie nie jest częścią modułu, jedynym sposobem załadowania go do pamięci jest dot-source .PS1 pliku, w ramach którego został zapisany.

Następująca funkcja została zapisana jako Get-MrPSVersion.ps1.

function Get-MrPSVersion {
    $PSVersionTable
}

Po uruchomieniu skryptu nic się nie dzieje.

.\Get-MrPSVersion.ps1

Jeśli spróbujesz wywołać funkcję, zostanie wygenerowany komunikat o błędzie.

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) [], CommandNotFou
   ndException
    + FullyQualifiedErrorId : CommandNotFoundException

Możesz określić, czy funkcje są ładowane do pamięci, sprawdzając, czy istnieją w usłudze PSDrive funkcji .

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.GetChildItemCommand

Problem z wywoływaniem skryptu zawierającego funkcję polega na tym, że funkcje są ładowane w zakresie skryptu . Po zakończeniu działania skryptu ten zakres zostanie usunięty i funkcja zostanie usunięta z nim.

Funkcja musi zostać załadowana do zakresu globalnego . Można to osiągnąć za pomocą kropki określania źródła skryptu, który zawiera funkcję. Można użyć ścieżki względnej.

. .\Get-MrPSVersion.ps1

Można również użyć w pełni kwalifikowanej ścieżki.

. C:\Demo\Get-MrPSVersion.ps1

Jeśli część ścieżki jest przechowywana w zmiennej, można ją połączyć z pozostałą częścią ścieżki. Nie ma powodu, aby użyć łączenia ciągów w celu połączenia zmiennej wraz z pozostałą częścią ścieżki.

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

Teraz, gdy sprawdzam funkcję PSDrive, Get-MrPSVersion funkcja istnieje.

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

Moduły skryptów

Moduł skryptu w programie PowerShell to po prostu plik zawierający co najmniej jedną funkcję, która jest zapisywana jako .PSM1 plik zamiast .PS1 pliku.

Jak utworzyć moduł skryptu? Prawdopodobnie odgadniesz polecenie o nazwie podobnej do New-Module. Twoje założenie byłoby błędne. Chociaż w programie PowerShell istnieje polecenie o nazwie New-Module, to polecenie tworzy moduł dynamiczny, a nie moduł skryptu. Zawsze pamiętaj, aby przeczytać pomoc dotyczącą polecenia, nawet jeśli uważasz, że znaleziono potrzebne polecenie.

help New-Module
NAME
    New-Module

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

SYNTAX
    New-Module [-Name] <String> [-ScriptBlock] <ScriptBlock> [-ArgumentList <Object[]>]
    [-AsCustomObject] [-Cmdlet <String[]>] [-Function <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: http://go.microsoft.com/fwlink/?LinkId=821495
    Export-ModuleMember
    Get-Module
    Import-Module
    Remove-Module

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"

W poprzednim rozdziale wspomniałem, że funkcje powinny używać zatwierdzonych czasowników. W przeciwnym razie wygenerują komunikat ostrzegawczy podczas importowania modułu. Poniższy kod używa polecenia cmdlet do utworzenia modułu New-Module dynamicznego w pamięci. W tym module przedstawiono niezatwierdzone ostrzeżenie o czasowniku.

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.

Aby powtórzyć, chociaż New-Module polecenie cmdlet zostało użyte w poprzednim przykładzie, nie jest to polecenie do tworzenia modułów skryptów w programie PowerShell.

Zapisz następujące dwie funkcje w pliku o nazwie MyScriptModule.psm1.

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Spróbuj wywołać jedną z funkcji.

Get-MrComputerName
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) [], CommandNot
   FoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Zostanie wygenerowany komunikat o błędzie z informacją, że nie można odnaleźć funkcji. Możesz również sprawdzić funkcję PSDrive tak jak wcześniej i dowiedzieć się, że też nie istnieje.

Możesz ręcznie zaimportować plik za Import-Module pomocą polecenia cmdlet .

Import-Module C:\MyScriptModule.psm1

Funkcja automatycznego ładowania modułu została wprowadzona w programie PowerShell w wersji 3. Aby skorzystać z automatycznego ładowania modułu, moduł skryptu musi zostać zapisany w folderze o tej samej nazwie podstawowej co .PSM1 plik i w lokalizacji określonej w $env:PSModulePath.

$env:PSModulePath
C:\Users\mike-ladm\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerShell\
Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files (x86)\Microsof
t SQL Server\130\Tools\PowerShell\Modules\

Wyniki są trudne do odczytania. Ponieważ ścieżki są oddzielone średnikami, można podzielić wyniki, aby zwrócić każdą ścieżkę w osobnym wierszu. Ułatwia to ich odczytywanie.

$env:PSModulePath -split ';'
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\

Pierwsze trzy ścieżki na liście są domyślne. Po zainstalowaniu SQL Server Management Studio została dodana ostatnia ścieżka. Aby automatyczne ładowanie modułu działało, MyScriptModule.psm1 plik musi znajdować się w folderze o nazwie MyScriptModule bezpośrednio w jednej z tych ścieżek.

Nie tak szybko. Dla mnie moja bieżąca ścieżka użytkownika nie jest pierwszą na liście. Prawie nigdy nie używam tej ścieżki, ponieważ loguję się do systemu Windows z innym użytkownikiem niż ten, którego używam do uruchamiania programu PowerShell. Oznacza to, że nie znajduje się on w normalnym folderze Dokumenty.

Druga ścieżka to ścieżka AllUsers . Jest to lokalizacja, w której przechowujem wszystkie moje moduły.

Trzecia ścieżka znajduje się poniżej C:\Windows\System32. Tylko firma Microsoft powinna przechowywać moduły w tej lokalizacji, ponieważ znajduje się w folderze systemów operacyjnych.

Po zlokalizowaniu .PSM1 pliku w prawidłowej ścieżce moduł zostanie załadowany automatycznie po wywołaniu jednego z jego poleceń.

Manifesty modułów

Wszystkie moduły powinny mieć manifest modułu. Manifest modułu zawiera metadane dotyczące modułu. Rozszerzenie pliku manifestu modułu to .PSD1. Nie wszystkie pliki z .PSD1 rozszerzeniem są manifestami modułów. Mogą być również używane w przypadku takich elementów, jak przechowywanie części środowiska konfiguracji DSC. New-ModuleManifest służy do tworzenia manifestu modułu. Ścieżka jest jedyną wymaganą wartością. Jednak moduł nie będzie działać, jeśli nie określono elementu RootModule . Dobrym pomysłem jest określenie autora i opisu w przypadku, gdy zdecydujesz się przekazać moduł do repozytorium NuGet przy użyciu modułu PowerShellGet, ponieważ te wartości są wymagane w tym scenariuszu.

Wersja modułu bez manifestu to 0.0. Jest to dead giveaway, że moduł nie ma manifestu.

Get-Module -Name MyScriptModule
ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.0        myscriptmodule                      {Get-MrComputerName, Get-MrP...

Manifest modułu można utworzyć ze wszystkimi zalecanymi informacjami.

New-ModuleManifest -Path $env:ProgramFiles\WindowsPowerShell\Modules\MyScriptModule\MyScriptModule.psd1 -RootModule MyScriptModule -Author 'Mike F Robbins' -Description 'MyScriptModule' -CompanyName 'mikefrobbins.com'

Jeśli którakolwiek z tych informacji zostanie pominięta podczas początkowego tworzenia manifestu modułu, można go dodać lub zaktualizować później przy użyciu polecenia Update-ModuleManifest. Nie twórz ponownie manifestu po New-ModuleManifest jego utworzeniu, ponieważ identyfikator GUID ulegnie zmianie.

Definiowanie funkcji publicznych i prywatnych

Mogą istnieć funkcje pomocnicze, które mogą być prywatne i dostępne tylko dla innych funkcji w module. Nie są one przeznaczone dla użytkowników modułu. Istnieje kilka różnych sposobów, aby to osiągnąć.

Jeśli nie stosujesz najlepszych rozwiązań i masz tylko plik, jedyną opcją .PSM1 jest użycie Export-ModuleMember polecenia cmdlet .

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Export-ModuleMember -Function Get-MrPSVersion

W poprzednim przykładzie tylko Get-MrPSVersion funkcja jest dostępna dla użytkowników modułu, ale Get-MrComputerName funkcja jest dostępna dla innych funkcji w samym module.

Get-Command -Module MyScriptModule

CommandType     Name                        Version    Source
-----------     ----                        -------    ------
Function        Get-MrPSVersion             1.0        MyScript...

Jeśli do modułu dodano manifest modułu (i należy), zalecamy określenie poszczególnych funkcji, które chcesz wyeksportować w sekcji FunctionsToExport manifestu modułu.

FunctionsToExport = 'Get-MrPSVersion'

Nie jest konieczne użycie zarówno Export-ModuleMember w pliku, jak .PSM1 i w sekcji FunctionsToExport manifestu modułu. Jeden lub drugi jest wystarczający.

Podsumowanie

W tym rozdziale przedstawiono sposób przekształcania funkcji w moduł skryptu w programie PowerShell. Znasz również niektóre z najlepszych rozwiązań dotyczących tworzenia modułów skryptów, takich jak tworzenie manifestu modułu dla modułu skryptu.

Przegląd

  1. Jak utworzyć moduł skryptu w programie PowerShell?
  2. Dlaczego ważne jest, aby funkcje używały zatwierdzonego zlecenia?
  3. Jak utworzyć manifest modułu w programie PowerShell?
  4. Jakie są dwie opcje eksportowania tylko niektórych funkcji z modułu?
  5. Co jest wymagane, aby moduły ładowały się automatycznie po wywołaniu polecenia?