Delen via


Hoofdstuk 10 - Scriptmodules

Als u dezelfde PowerShell one-liners of scripts vaak gebruikt, is het nog belangrijker om ze om te zetten in herbruikbare hulpprogramma's. Het verpakken van uw functies in een scriptmodule geeft ze een professioneler gevoel en maakt ze gemakkelijker te ondersteunen en met anderen te delen.

Functies voor dot-sourcing

Een ding dat we in het vorige hoofdstuk niet hebben besproken, is dot-sourcingfuncties. Wanneer u een functie definieert in een script dat geen deel uitmaakt van een module, is de enige manier om deze in het geheugen te laden door het bestand te dot-sourcen .ps1.

Sla bijvoorbeeld de volgende functie op in een bestand met de naam Get-MrPSVersion.ps1.

function Get-MrPSVersion {
    $PSVersionTable
}

Wanneer u het script uitvoert, lijkt het erop dat er niets gebeurt.

.\Get-MrPSVersion.ps1

Als u de functie probeert aan te roepen, treedt er een fout op omdat deze niet in het geheugen is geladen.

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

U kunt controleren of functies in het geheugen worden geladen door het bestaan ervan te controleren op de functie: 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

Het probleem met het uitvoeren van het script waarmee de functie wordt gedefinieerd, is dat deze in het scriptbereik wordt geladen. Zodra het script is uitgevoerd, wordt dat bereik samen met de functie verwijderd in PowerShell.

Als u de functie beschikbaar wilt houden nadat het script is uitgevoerd, moet deze in het globale bereik worden geladen. U kunt dit doen door dot-sourcing van het scriptbestand. U kunt hiervoor een relatief pad gebruiken.

. .\Get-MrPSVersion.ps1

U kunt ook het volledige pad naar het script gebruiken bij het bronprogramma.

. C:\Demo\Get-MrPSVersion.ps1

Als een deel van het pad is opgeslagen in een variabele, kunt u het combineren met de rest van het pad. U hoeft hiervoor geen tekenreekssamenvoeging te gebruiken.

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

Als u nu de functie PSDrive controleert, ziet u dat de Get-MrPSVersion functie beschikbaar is.

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

Scriptmodules

In PowerShell is een scriptmodule gewoon een .psm1 bestand dat een of meer functies bevat, net als een gewoon script, maar met een andere bestandsextensie.

Hoe maakt u een scriptmodule? U kunt ervan uitgaan dat u een opdracht hebt met de naam iets als New-Module. Deze aanname is een redelijke schatting, maar die opdracht maakt daadwerkelijk een dynamische module, niet een scriptmodule.

Dit scenario is een goede herinnering om altijd de Help-documentatie te lezen, zelfs wanneer een opdrachtnaam er precies zo uitziet als wat u nodig hebt.

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"

In het vorige hoofdstuk werd vermeld dat functies goedgekeurde werkwoorden moeten gebruiken. Anders genereert PowerShell een waarschuwing wanneer de module wordt geïmporteerd.

In het volgende voorbeeld wordt de New-Module cmdlet gebruikt om een dynamische module in het geheugen te maken, met name om te laten zien wat er gebeurt wanneer u geen goedgekeurd werkwoord gebruikt.

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.

Hoewel u de New-Module cmdlet in het vorige voorbeeld hebt gebruikt, zoals eerder vermeld, is dit niet de opdracht voor het maken van scriptmodules in PowerShell.

Als u een scriptmodule wilt maken, slaat u uw functies op in een .psm1 bestand. Sla bijvoorbeeld de volgende twee functies op in een bestand met de naam MyScriptModule.psm1.

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Probeer een van de functies uit te voeren.

Get-MrComputerName

Wanneer u de functie aanroept, krijgt u een foutmelding dat PowerShell deze niet kan vinden. Zoals eerder bevestigt het controleren van de functie: PSDrive dat deze niet in het geheugen is geladen.

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

Als u de functie beschikbaar wilt maken, kunt u het MyScriptModule.psm1 bestand handmatig importeren met behulp van de Import-Module cmdlet.

Import-Module C:\MyScriptModule.psm1

PowerShell heeft module automatisch laden geïntroduceerd in versie 3. Als u van deze functie wilt profiteren, moet de scriptmodule worden opgeslagen in een map met dezelfde basisnaam als het .psm1 bestand. Deze map moet zich in een van de mappen bevinden die zijn opgegeven in de $env:PSModulePath omgevingsvariabele.

$env:PSModulePath

De uitvoer van $env:PSModulePath is moeilijk te lezen.

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\

Als u de resultaten beter leesbaar wilt maken, splitst u de paden op het scheidingsteken voor puntkomma's, zodat elk pad op een eigen regel wordt weergegeven.

$env:PSModulePath -split ';'

De eerste drie paden in de lijst zijn de standaardmodulelocaties. SQL Server Management Studio heeft het laatste pad toegevoegd toen u het hebt geïnstalleerd.

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\

Als u automatisch laden van modules wilt laten werken, moet u het MyScriptModule.psm1 bestand in een map met de naam MyScriptModuleplaatsen en die map moet zich rechtstreeks in een van de paden bevinden die worden vermeld in
$env:PSModulePath.

Niet al deze paden zijn even nuttig. Het huidige gebruikerspad op mijn systeem is bijvoorbeeld niet het eerste pad in de lijst. Dat komt omdat ik me met een ander account bij Windows aanmeld dan het account dat ik gebruik om PowerShell uit te voeren. Het verwijst dus niet naar de map documenten van mijn gebruiker.

Het tweede pad is het pad AllUsers , waar ik al mijn modules opslaat.

Het derde pad verwijst naar C:\Windows\System32, een beveiligde systeemlocatie. Alleen Microsoft moet daar modules plaatsen, omdat deze onder de mapstructuur van het besturingssysteem valt.

Zodra u het .psm1 bestand in een geschikte map binnen een van deze paden hebt geplaatst, wordt de module automatisch geladen wanneer u een van de opdrachten aanroept.

Modulemanifesten

Elke module moet een modulemanifest bevatten. Dit is een .psd1 bestand met metagegevens over de module. Hoewel de .psd1 extensie wordt gebruikt voor manifesten, zijn niet alle .psd1 bestanden modulemanifesten. U kunt ze ook gebruiken voor andere doeleinden, zoals het definiëren van omgevingsgegevens in een DSC
configuratie.

U kunt een modulemanifest maken met behulp van de New-ModuleManifest cmdlet. De enige vereiste parameter is Path, maar om de module correct te laten werken, moet u ook de parameter RootModule opgeven.

Het is een best practice om waarden zoals Auteur en Beschrijving op te nemen, met name als u van plan bent om uw module te publiceren naar een NuGet-opslagplaats met behulp van PowerShellGet. Deze velden zijn vereist in dat scenario.

Een snelle manier om te zien of een module geen manifest heeft, is door de versie ervan te controleren.

Get-Module -Name MyScriptModule

Een versienummer van 0.0 is een duidelijk teken dat de module geen manifest heeft.

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

U moet alle aanbevolen details opnemen bij het maken van een modulemanifest om ervoor te zorgen dat uw module goed is gedocumenteerd en gereed is voor delen of publiceren.

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

New-ModuleManifest @moduleManifestParams

Als u waarden weglaat bij het maken van het modulemanifest, kunt u deze later toevoegen of bijwerken met behulp van de Update-ModuleManifest cmdlet. Vermijd het opnieuw maken van het manifest nadat u het hebt gemaakt, omdat hiermee een nieuwe GUID wordt gegenereerd.

Het definiëren van openbare en privéfuncties

Soms bevat uw module helperfuncties die u niet beschikbaar wilt maken voor gebruikers. Deze privéfuncties worden intern gebruikt door andere functies in de module, maar worden niet blootgesteld aan gebruikers. Er zijn een aantal manieren om dit scenario af te handelen.

Als u geen aanbevolen procedures volgt en alleen een .psm1 bestand zonder modulemanifest hebt, kunt u alleen de zichtbaarheid beheren met behulp van de Export-ModuleMember cmdlet. Met deze optie kunt u expliciet definiëren welke functies rechtstreeks vanuit het .psm1 scriptmodulebestand moeten worden weergegeven, zodat alle andere functies standaard privé moeten blijven.

In het volgende voorbeeld is alleen de Get-MrPSVersion functie zichtbaar voor gebruikers van uw module, terwijl de Get-MrComputerName functie intern toegankelijk blijft voor andere functies in de module.

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Export-ModuleMember -Function Get-MrPSVersion

Bepaal welke opdrachten openbaar beschikbaar zijn in de module MyScriptModule .

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

Als u een modulemanifest aan uw module toevoegt, is het raadzaam om expliciet de functies weer te geven die u wilt exporteren in de sectie FunctionsToExport . Met deze optie kunt u bepalen wat u beschikbaar maakt voor gebruikers vanuit het manifestbestand van de .psd1 module.

FunctionsToExport = 'Get-MrPSVersion'

U hoeft niet zowel Export-ModuleMember in het .psm1 bestand als in de FunctionsToExport sectie in het modulemanifest te gebruiken. Beide benaderingen zijn zelfstandig genoeg.

Samenvatting

In dit hoofdstuk hebt u geleerd hoe u uw functies kunt omzetten in een scriptmodule in PowerShell. U hebt ook aanbevolen procedures verkend voor het maken van scriptmodules, waaronder het toevoegen van een modulemanifest om metagegevens te definiëren en geëxporteerde opdrachten te beheren.

Recensie

  1. Hoe maakt u een scriptmodule in PowerShell?
  2. Waarom is het belangrijk om goedgekeurde werkwoorden te gebruiken voor uw functienamen?
  3. Hoe maakt u een modulemanifest in PowerShell?
  4. Wat zijn de twee manieren om alleen specifieke functies uit een module te exporteren?
  5. Aan welke voorwaarden moet worden voldaan om een module automatisch te laden wanneer u een van de opdrachten uitvoert?

Verwijzingen