Compartilhar via


11. Módulos

Nota editorial

Importante

A Especificação da Linguagem do Windows PowerShell 3.0 foi publicada em dezembro de 2012 e baseia-se no Windows PowerShell 3.0. Essa especificação não reflete o estado atual do PowerShell. Não há nenhum plano para atualizar essa documentação para refletir o estado atual. Esta documentação é apresentada aqui para referência histórica.

O documento de especificação está disponível como um documento do Microsoft Word do Centro de Download da Microsoft em: https://www.microsoft.com/download/details.aspx?id=36389 esse documento do Word foi convertido para apresentação aqui no Microsoft Learn. Durante a conversão, algumas alterações editoriais foram feitas para acomodar a formatação para a plataforma Docs. Alguns erros de digitação e pequenos foram corrigidos.

Introdução 11.1

Conforme indicado em §3.14, um módulo é uma unidade reutilizável autocontida que permite que o código do PowerShell seja particionado, organizado e abstraído. Um módulo pode conter um ou mais membros do módulo , que são comandos (como cmdlets e funções) e itens (como variáveis e aliases). Os nomes desses membros podem ser mantidos privados para o módulo ou podem ser exportados para a sessão na qual o módulo é importado.

Há três tipos de módulo diferentes: manifesto, script e binário. Um módulo de manifesto é um arquivo que contém informações sobre um módulo e controla determinados aspectos do uso desse módulo. Um módulo de script é um arquivo de script do PowerShell com extensão de arquivo .psm1 em vez de .ps1. Um módulo binário contém tipos de classe que definem cmdlets e provedores. Ao contrário dos módulos de script, os módulos binários são escritos em idiomas compilados. Os módulos binários não são cobertos por essa especificação.

Um módulo binário é um assembly .NET (ou seja, uma DLL) que foi compilado contra as bibliotecas do PowerShell.

Os módulos podem aninhar; ou seja, um módulo pode importar outro módulo. Um módulo que tem módulos aninhados associados é um módulo raiz.

Quando uma sessão do PowerShell é criada, por padrão, nenhum módulo é importado.

Quando os módulos são importados, o caminho de pesquisa usado para localizá-los é definido pela variável de ambiente PSModulePath.

Os seguintes cmdlets lidam com módulos:

  • get-module: identifica os módulos que foram ou podem ser importados
  • import-module: adiciona um ou mais módulos à sessão atual (consulte §11.4)
  • Export-ModuleMember: identifica os membros do módulo que devem ser exportados
  • Remove-Module: remove um ou mais módulos da sessão atual (consulte §11.5)
  • new-module: cria um módulo dinâmico (consulte §11.7)

11.2 Escrever um módulo de script

Um módulo de script é um arquivo de script. Considere o seguinte módulo de script:

function Convert-CentigradeToFahrenheit ([double]$tempC) {
    return ($tempC * (9.0 / 5.0)) + 32.0
}
New-Alias c2f Convert-CentigradeToFahrenheit

function Convert-FahrenheitToCentigrade ([double]$tempF) {
    return ($tempF - 32.0) * (5.0 / 9.0)
}
New-Alias f2c Convert-FahrenheitToCentigrade

Export-ModuleMember -Function Convert-CentigradeToFahrenheit
Export-ModuleMember -Function Convert-FahrenheitToCentigrade
Export-ModuleMember -Alias c2f, f2c

Este módulo contém duas funções, cada uma com um alias. Por padrão, todos os nomes de função e apenas nomes de função são exportados. No entanto, depois que o cmdlet Export-ModuleMember tiver sido usado para exportar qualquer coisa, somente as coisas exportadas explicitamente serão exportadas. Uma série de comandos e itens podem ser exportados em uma chamada ou em várias chamadas para esse cmdlet; essas chamadas são cumulativas para a sessão atual.

11.3 Instalando um módulo de script

Um módulo de script é definido em um arquivo de script e os módulos podem ser armazenados em qualquer diretório. A variável de ambiente PSModulePath aponta para um conjunto de diretórios a serem pesquisados quando cmdlets relacionados ao módulo procuram módulos cujos nomes não incluem um caminho totalmente qualificado. Caminhos de pesquisa adicionais podem ser fornecidos; por exemplo

$Env:PSModulePath = $Env:PSModulePath + ";<additional-path>"

Quaisquer caminhos adicionais adicionados afetam apenas a sessão atual.

Como alternativa, um caminho totalmente qualificado pode ser especificado quando um módulo é importado.

11.4 Importando um módulo de script

Antes que os recursos em um módulo possam ser usados, esse módulo deve ser importado para a sessão atual, usando o cmdlet Import-Module. Import-Module pode restringir os recursos que ele realmente importa.

Quando um módulo é importado, seu arquivo de script é executado. Esse processo pode ser configurado definindo um ou mais parâmetros no arquivo de script e passando argumentos correspondentes por meio do parâmetro ArgumentList de Import-Module.

Considere o script a seguir que usa essas funções e aliases definidos em §11.2:

Import-Module "E:\Scripts\Modules\PSTest_Temperature" - Detalhado

"0 degrees C is " + (Convert-CentigradeToFahrenheit 0) + " degrees F"
"100 degrees C is " + (c2f 100) + " degrees F"
"32 degrees F is " + (Convert-FahrenheitToCentigrade 32) + " degrees C"
"212 degrees F is " + (f2c 212) + " degrees C"

Importar um módulo causa um conflito de nomes quando comandos ou itens no módulo têm os mesmos nomes que comandos ou itens na sessão. Um conflito de nome resulta em um nome oculto ou substituído. O parâmetro prefixo de Import-Module pode ser usado para evitar conflitos de nomenclatura. Além disso, os parâmetros Alias, Cmdlet, Functione Variable podem limitar a seleção de comandos a serem importados, reduzindo assim as chances de conflito de nome.

Mesmo que um comando esteja oculto, ele pode ser executado qualificando seu nome com o nome do módulo no qual ele se originou. Por exemplo, & M\F 100 invoca a função F no módulo Me passa o argumento 100.

Quando a sessão inclui comandos do mesmo tipo com o mesmo nome, como dois cmdlets com o mesmo nome, por padrão, ele executa o comando adicionado mais recentemente.

Consulte §3.5.6 para uma discussão sobre o escopo no que diz respeito aos módulos.

11.5 Removendo um módulo de script

Um ou mais módulos podem ser removidos de uma sessão por meio do cmdlet Remove-Module.

Remover um módulo não desinstala o módulo.

Em um módulo de script, é possível especificar o código que deve ser executado antes da remoção desse módulo, da seguinte maneira:

$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { *on-removal-code* }

Manifestos do módulo 11.6

Conforme indicado em §11.1, um módulo de manifesto é um arquivo que contém informações sobre um módulo e controla determinados aspectos do uso desse módulo.

Um módulo não precisa ter um manifesto correspondente, mas, se o fizer, esse manifesto tem o mesmo nome que o módulo descrito, mas com uma extensão de arquivo .psd1.

Um manifesto contém um subconjunto limitado de script do PowerShell, que retorna um Hashtable que contém um conjunto de chaves. Essas chaves e seus valores especificam os elementos de manifesto para esse módulo. Ou seja, eles descrevem o conteúdo e os atributos do módulo, definem os pré-requisitos e determinam como os componentes são processados.

Essencialmente, um manifesto é um arquivo de dados; no entanto, ele pode conter referências a tipos de dados, à instrução if e aos operadores aritméticos e de comparação. (Atribuições, definições de função e loops não são permitidos.) Um manifesto também tem acesso de leitura a variáveis de ambiente e pode conter chamadas para o cmdlet Join-Path, para que os caminhos possam ser construídos.

Nota

Observação do editor: o documento original contém uma lista de chaves permitidas em um arquivo de manifesto do módulo. Essa lista está desatualizada e incompleta. Para obter uma lista completa de chaves em um manifesto de módulo, consulte New-ModuleManifest.

A única chave necessária é ModuleVersion.

Aqui está um exemplo de um manifesto simples:

@{
ModuleVersion = '1.0'
Author = 'John Doe'
RequiredModules = @()
FunctionsToExport = 'Set*','Get*','Process*'
}

A chave GUID tem um valor string. Isso especifica um GUID (IDentifier Globally Unique) para o módulo. O GUID pode ser usado para distinguir entre os módulos que têm o mesmo nome. Para criar um novo GUID, chame o método [guid]::NewGuid().

11.7 Módulos dinâmicos

Um módulo dinâmico é um módulo criado na memória em runtime pelo cmdlet New-Module; ele não é carregado do disco. Considere o seguinte exemplo:

$sb = {
    function Convert-CentigradeToFahrenheit ([double]$tempC) {
        return ($tempC * (9.0 / 5.0)) + 32.0
    }

    New-Alias c2f Convert-CentigradeToFahrenheit

    function Convert-FahrenheitToCentigrade ([double]$tempF) {
        return ($tempF - 32.0) * (5.0 / 9.0)
    }

    New-Alias f2c Convert-FahrenheitToCentigrade

    Export-ModuleMember -Function Convert-CentigradeToFahrenheit
    Export-ModuleMember -Function Convert-FahrenheitToCentigrade
    Export-ModuleMember -Alias c2f, f2c
}

New-Module -Name MyDynMod -ScriptBlock $sb
Convert-CentigradeToFahrenheit 100
c2f 100

O bloco de script $sb define o conteúdo do módulo, nesse caso, duas funções e dois aliases para essas funções. Assim como acontece com um módulo em disco, somente as funções são exportadas por padrão, portanto, Export-ModuleMember chamadas de cmdlets existem para exportar as funções e os aliases.

Depois que New-Module for executado, os quatro nomes exportados estarão disponíveis para uso na sessão, conforme mostrado pelas chamadas para o Convert-CentigradeToFahrenheit e c2f.

Assim como todos os módulos, os membros de módulos dinâmicos são executados em um escopo de módulo privado que é um filho do escopo global. Get-Module não pode obter um módulo dinâmico, mas Get-Command pode obter os membros exportados.

Para disponibilizar um módulo dinâmico para Get-Module, redirecione um comando New-Module para Import-Moduleou redirecione o objeto de módulo que New-Module retorna, para Import-Module. Essa ação adiciona o módulo dinâmico à lista de Get-Module, mas não salva o módulo em disco ou o torna persistente.

Fechamentos 11.8

Um módulo dinâmico pode ser usado para criar um fechamento , uma função com dados anexados. Considere o seguinte exemplo:

function Get-NextID ([int]$StartValue = 1) {
    $nextID = $StartValue
    {
        ($Script:nextID++)
    }.GetNewClosure()
}

$v1 = Get-NextID      # get a scriptblock with $StartValue of 0
& $v1                 # invoke Get-NextID getting back 1
& $v1                 # invoke Get-NextID getting back 2

$v2 = Get-NextID 100  # get a scriptblock with $StartValue of 100
& $v2                 # invoke Get-NextID getting back 100
& $v2                 # invoke Get-NextID getting back 101

O objetivo aqui é que Get-NextID retorne o próximo identificador em uma sequência cujo valor inicial pode ser especificado. No entanto, várias sequências devem ser suportadas, cada uma com seu próprio contexto de $StartValue e $nextID. Isso é obtido pela chamada para o método [scriptblock]::GetNewClosure (§4.3.7).

Sempre que um novo fechamento é criado por GetNewClosure, um novo módulo dinâmico é criado e as variáveis no escopo do chamador (nesse caso, o bloco de script que contém o incremento) são copiadas para este novo módulo. Para garantir que a nextId definida dentro da função pai (mas fora do bloco de script) seja incrementada, o script explícito: prefixo de escopo é necessário.

É claro que o bloco de script não precisa ser uma função nomeada; por exemplo:

$v3 = & {      # get a scriptblock with $StartValue of 200
    param ([int]$StartValue = 1)
    $nextID = $StartValue
    {
        ($Script:nextID++)
    }.GetNewClosure()
} 200

& $v3          # invoke script getting back 200
& $v3          # invoke script getting back 201