Capitolo 10 - Moduli di scriptChapter 10 - Script modules

La trasformazione di one-liner e script di PowerShell in strumenti riutilizzabili diventa ancora più importante se si tratta di strumenti che verranno usati di frequente.Turning your one-liners and scripts in PowerShell into reusable tools becomes even more important if it's something that you're going to use frequently. Il packaging delle funzioni in un modulo di script li rende più professionali e ne semplifica la condivisione.Packaging your functions in a script module makes them look and feel more professional and makes them easier to share.

Funzioni dot-sourcingDot-Sourcing Functions

Un elemento che non è stato illustrato nel capitolo precedente è la funzione dot-sourcing.Something that we didn't talk about in the previous chapter is dot-sourcing functions. Quando una funzione in uno script non fa parte di un modulo, l'unico modo per caricarla in memoria consiste nell'effettuare il dot-sourcing del file .PS1 in cui è salvata.When a function in a script isn't part of a module, the only way to load it into memory is to dot-source the .PS1 file that it's saved in.

La funzione seguente è stata salvata come Get-MrPSVersion.ps1.The following function has been saved as Get-MrPSVersion.ps1.

function Get-MrPSVersion {
    $PSVersionTable
}

Quando si esegue lo script, non viene eseguita alcuna operazione.When you run the script, nothing happens.

.\Get-MrPSVersion.ps1

Se si prova a chiamare la funzione, viene generato un messaggio di errore.If you try to call the function, it generates an error message.

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

È possibile determinare se le funzioni sono caricate in memoria controllando se esistono nel PSDrive Function.You can determine if functions are loaded into memory by checking to see if they exist on the 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.GetChildItemCommand

Il problema della chiamata allo script che contiene la funzione è che le funzioni sono caricate nell'ambito Script.The problem with calling the script that contains the function is that the functions are loaded in the Script scope. Al termine dello script, l'ambito viene rimosso e con esso la funzione.When the script completes, that scope is removed and the function is removed with it.

La funzione deve essere caricata nell'ambito Global.The function needs to be loaded into the Global scope. Questa operazione può essere eseguita effettuando il dot-sourcing dello script che contiene la funzione.That can be accomplished by dot-sourcing the script that contains the function. È possibile usare il percorso relativo.The relative path can be used.

. .\Get-MrPSVersion.ps1

È anche possibile usare il percorso completo.The fully qualified path can also be used.

. C:\Demo\Get-MrPSVersion.ps1

Se una parte del percorso è archiviata in una variabile, può essere combinata con il resto del percorso.If a portion of the path is stored in a variable, it can be combined with the remainder of the path. Non esiste alcun motivo per usare la concatenazione di stringhe per combinare la variabile con il resto del percorso.There's no reason to use string concatenation to combine the variable together with the remainder of the path.

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

Se a questo punto si controlla il PSDrive Function, la funzione Get-MrPSVersion esiste.Now when I check the Function PSDrive, the Get-MrPSVersion function exists.

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

Moduli di scriptScript Modules

Un modulo di script in PowerShell è semplicemente un file che contiene una o più funzioni salvate come file .PSM1 anziché come file .PS1.A script module in PowerShell is simply a file containing one or more functions that's saved as a .PSM1 file instead of a .PS1 file.

Come si crea un modulo di script?How do you create a script module? Probabilmente si ipotizza con un comando denominato New-Module.You're probably guessing with a command named something like New-Module. L'ipotesi è sbagliata.Your assumption would be wrong. Anche se in PowerShell esiste un comando denominato New-Module, il comando crea un modulo dinamico, non un modulo di script.While there is a command in PowerShell named New-Module, that command creates a dynamic module, not a script module. Assicurarsi sempre di leggere la guida per un comando anche quando si ritiene di aver trovato il comando desiderato.Always be sure to read the help for a command even when you think you've found the command you need.

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"

Nel capitolo precedente ho specificato che le funzioni devono usare i verbi approvati, in caso contrario generano un messaggio di avviso quando viene importato il modulo.In the previous chapter, I mentioned that functions should use approved verbs otherwise they'll generate a warning message when the module is imported. Il codice seguente usa il cmdlet New-Module per creare un modulo dinamico in memoria.The following code uses the New-Module cmdlet to create a dynamic module in memory. Questo modulo illustra l'avviso del verbo non approvato.This module demonstrates the unapproved verb warning.

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.

Come già indicato, anche se il cmdlet New-Module è stato usato nell'esempio precedente, non è il comando per la creazione di moduli di script in PowerShell.Just to reiterate, although the New-Module cmdlet was used in the previous example, that's not the command for creating script modules in PowerShell.

Salvare le due funzioni seguenti in un file denominato MyScriptModule.psm1.Save the following two functions in a file named MyScriptModule.psm1.

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Provare a chiamare una delle funzioni.Try to call one of the functions.

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

Viene generato un messaggio di errore che informa che la funzione non è stata trovata.An error message is generated saying the function can't be found. È anche possibile controllare il PSDrive Function esattamente come prima e si noterà la funzione non è presente neanche in quella posizione.You could also check the Function PSDrive just like before and you'll find that it doesn't exist there either.

È possibile importare manualmente il file con il cmdlet Import-Module.You could manually import the file with the Import-Module cmdlet.

Import-Module C:\MyScriptModule.psm1

La funzionalità di caricamento automatico dei moduli è stata introdotta in PowerShell versione 3.The module autoloading feature was introduced in PowerShell version 3. Per sfruttare i vantaggi del caricamento automatico dei moduli, è necessario salvare un modulo di script in una cartella con lo stesso nome di base del file .PSM1 e in un percorso specificato in $env:PSModulePath.To take advantage of module autoloading, a script module needs to be saved in a folder with the same base name as the .PSM1 file and in a location specified in $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\

I risultati sono difficili da leggere.The results are difficult to read. I percorsi sono separati da un punto e virgola, quindi è possibile suddividere i risultati per restituire ogni percorso in una riga separata.Since the paths are separated by a semicolon, you can split the results to return each path on a separate line. In questo modo, la lettura è più semplice.This makes them easier to read.

$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\

I primi tre percorsi nell'elenco sono i valori predefiniti.The first three paths in the list are the default. Quando SQL Server Management Studio è stato installato, è stato aggiunto l'ultimo percorso.When SQL Server Management Studio was installed, it added the last path. Per il corretto funzionamento del caricamento automatico del modulo, il file MyScriptModule.psm1 deve trovarsi in una cartella denominata MyScriptModule direttamente all'interno di uno di questi percorsi.For module autoloading to work, the MyScriptModule.psm1 file needs to be located in a folder named MyScriptModule directly inside one of those paths.

Rallentiamo.Not so fast. Per me, il percorso utente corrente non è il primo nell'elenco.For me, my current user path isn't the first one in the list. Non uso quasi mai quel percorso perché accedo a Windows con un utente diverso da quello che uso per eseguire PowerShell.I almost never use that path since I log into Windows with a different user than the one I use to run PowerShell. Ciò significa che non si trova nella normale cartella Documenti.That means it's not located in my normal Documents folder.

Il secondo percorso è il percorso AllUsers.The second path is the AllUsers path. Questo è il percorso in cui archivio tutti i moduli.This is the location where I store all of my modules.

Il terzo percorso si trova sotto C:\Windows\System32.The third path is underneath C:\Windows\System32. Solo Microsoft dovrebbe archiviare i moduli in quella posizione perché risiede all'interno della cartella del sistema operativo.Only Microsoft should be storing modules in that location since it resides within the operating systems folder.

Quando il file .PSM1 si trova nel percorso corretto, il modulo viene caricato automaticamente quando viene chiamato uno dei relativi comandi.Once the .PSM1 file is located in the correct path, the module will load automatically when one of its commands is called.

Manifesti dei moduliModule Manifests

Tutti i moduli devono avere un manifesto.All modules should have a module manifest. Un manifesto del modulo contiene i metadati relativi al modulo.A module manifest contains metadata about your module. L'estensione di un file manifesto del modulo è .PSD1.The file extension for a module manifest file is .PSD1. Non tutti i file con estensione .PSD1 sono manifesti del modulo.Not all files with a .PSD1 extension are module manifests. Possono anche essere usati per operazioni come l'archiviazione della parte ambientale di una configurazione DSC.They can also be used for things such as storing the environmental portion of a DSC configuration. New-ModuleManifest viene usato per creare un manifesto del modulo.New-ModuleManifest is used to create a module manifest. Path è l'unico valore obbligatorio.Path is the only value that's required. Tuttavia, il modulo non funzionerà se non viene specificato RootModule.However, the module won't work if RootModule isn't specified. È consigliabile specificare Author e Description nel caso in cui si decida di caricare il modulo in un repository NuGet con PowerShellGet perché questi valori sono necessari in quello scenario.It's a good idea to specify Author and Description in case you decide to upload your module to a NuGet repository with PowerShellGet since those values are required in that scenario.

La versione di un modulo senza manifesto è 0.0,The version of a module without a manifest is 0.0. a dimostrazione che il modulo non ha un manifesto.This is a dead giveaway that the module doesn't have a manifest.

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

Il manifesto del modulo può essere creato con tutte le informazioni consigliate.The module manifest can be created with all of the recommended information.

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

Se una di queste informazioni non viene specificata durante la creazione iniziale del manifesto del modulo, è possibile aggiungerla o aggiornarla in un secondo momento usando Update-ModuleManifest.If any of this information is missed during the initial creation of the module manifest, it can be added or updated later using Update-ModuleManifest. Non ricreare il manifesto usando New-ModuleManifest dopo che è già stato creato perché il GUID cambia.Don't recreate the manifest using New-ModuleManifest once it's already created because the GUID will change.

Definizione di funzioni pubbliche e privateDefining Public and Private Functions

Ci possono essere funzioni helper che si vogliono rendere private e accessibili solo da altre funzioni all'interno del modulo.You may have helper functions that you may want to be private and only accessible by other functions within the module. Non sono destinate a essere accessibili agli utenti del modulo.They are not intended to be accessible to users of your module. Esistono alcuni modi per eseguire questa operazione.There are a couple of different ways to accomplish this.

Se non si seguono le procedure consigliate ed è disponibile solo un file .PSM1, l'unica opzione consiste nell'usare il cmdlet Export-ModuleMember.If you're not following the best practices and only have a .PSM1 file, then your only option is to use the Export-ModuleMember cmdlet.

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Export-ModuleMember -Function Get-MrPSVersion

Nell'esempio precedente, solo la funzione Get-MrPSVersion è disponibile per gli utenti del modulo, ma la funzione Get-MrComputerName è disponibile per altre funzioni all'interno del modulo stesso.In the previous example, only the Get-MrPSVersion function is available to the users of your module, but the Get-MrComputerName function is available to other functions within the module itself.

Get-Command -Module MyScriptModule

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

Se è stato aggiunto un manifesto al modulo (ed è in effetti opportuno aggiungerlo), è consigliabile specificare le singole funzioni che si vogliono esportare nella sezione FunctionsToExport del manifesto del modulo.If you've added a module manifest to your module (and you should), then I recommend specifying the individual functions you want to export in the FunctionsToExport section of the module manifest.

FunctionsToExport = 'Get-MrPSVersion'

Non è necessario usare sia Export-ModuleMember nel file .PSM1 che la sezione FunctionsToExport del manifesto del modulo.It's not necessary to use both Export-ModuleMember in the .PSM1 file and the FunctionsToExport section of the module manifest. È sufficiente uno o l'altro.One or the other is sufficient.

SummarySummary

In questo capitolo si è appreso come trasformare le funzioni in un modulo di script in PowerShell.In this chapter you've learned how to turn your functions into a script module in PowerShell. Sono state inoltre apprese alcune delle procedure consigliate per la creazione di moduli di script, ad esempio la creazione di un manifesto del modulo per il modulo di script.You've also leaned some of the best practices for creating script modules such as creating a module manifest for your script module.

VerificaReview

  1. Come si crea un modulo di script in PowerShell?How do you create a script module in PowerShell?
  2. Perché è importante per le funzioni usare un verbo approvato?Why is it important for your functions to use an approved verb?
  3. Come si crea un manifesto del modulo in PowerShell?How do you create a module manifest in PowerShell?
  4. Quali sono le due opzioni per esportare solo determinate funzioni dal modulo?What are the two options for exporting only certain functions from your module?
  5. Cosa è necessario per il caricamento automatico dei moduli quando viene chiamato un comando?What is required for your modules to load automatically when a command is called?