当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 模块

作者:精品下载站 日期:2024-12-14 02:55:48 浏览:14 分类:玩电脑

模块


11.1 简介

如第 3.14 节所述,模块是一个独立的可重用单元,允许对 PowerShell 代码进行分区、组织和抽象。一个模块可以包含一个或多个模块成员,它们是命令(例如 cmdlet 和函数)和项(例如变量和别名)。这些成员的名称可以对模块保持私有,也可以导出到模块导入的会话中。

共有三种不同的模块类型:清单、脚本和二进制。 清单模块是一个包含模块信息的文件,并控制该模块使用的某些方面。 脚本模块是一个PowerShell脚本文件,其文件扩展名为.psm1而不是.ps1二进制模块包含定义 cmdlet 和提供程序的类类型。与脚本模块不同,二进制模块是用编译语言编写的。本规范不涵盖二进制模块。

二进制模块是针对 PowerShell 库编译的 .NET 程序集(即 DLL)。

模块可以嵌套;也就是说,一个模块可以导入另一个模块。具有关联嵌套模块的模块是根模块。

创建 PowerShell 会话时,默认情况下不会导入任何模块。

导入模块时,用于定位它们的搜索路径由环境变量PSModulePath定义。

以下 cmdlet 处理模块:

  • Get-Module:标识已经导入或可以导入的模块
  • 导入模块:向当前会话添加一个或多个模块(参见第 11.4 节)
  • Export-ModuleMember:标识要导出的模块成员
  • 删除模块:从当前会话中删除一个或多个模块(请参阅第 11.5 节)
  • New-Module:创建动态模块(参见§11.7)

11.2 编写脚本模块

脚本模块是一个脚本文件。考虑以下脚本模块:

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

该模块包含两个函数,每个函数都有一个别名。默认情况下,导出所有函数名称,并且仅导出函数名称。但是,一旦使用 cmdlet Export-ModuleMember 导出任何内容,则只会导出那些显式导出的内容。可以通过一次或多次调用此 cmdlet 导出一系列命令和项目;此类调用在当前会话中是累积的。

11.3 安装脚本模块

脚本模块定义在脚本文件中,模块可以存储在任意目录中。环境变量 PSModulePath 指向当模块相关 cmdlet 查找名称不包含完全限定路径的模块时要搜索的一组目录。可以提供额外的查找路径;例如,

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

添加的任何其他路径仅影响当前会话。

或者,可以在导入模块时指定完全限定路径。

11.4 导入脚本模块

在使用模块中的资源之前,必须使用 cmdlet Import-Module 将该模块导入到当前会话中。 Import-Module 可以限制它实际导入的资源。

当模块被导入时,它的脚本文件就会被执行。可以通过在脚本文件中定义一个或多个参数并通过 Import-Module 的 ArgumentList 参数传入相应的参数来配置该过程。

考虑以下脚本,该脚本使用第 11.2 节中定义的这些函数和别名:

导入模块 "E:\Scripts\Modules\PSTest_Temperature" -Verbose

"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"

当模块中的命令或项目与会话中的命令或项目具有相同名称时,导入模块会导致名称冲突。名称冲突会导致名称被隐藏或替换。 Import-Module 的 Prefix 参数可用于避免命名冲突。此外,别名Cmdlet函数变量参数可以限制要导入的命令的选择,从而减少名称冲突的机会。

即使命令是隐藏的,也可以通过用它所源自的模块的名称限定其名称来运行它。例如,& M\F 100 调用模块 M 中的函数 F,并向其传递参数 100。

当会话包含具有相同名称的同类命令(例如两个具有相同名称的 cmdlet)时,默认情况下它将运行最近添加的命令。

有关与模块相关的范围的讨论,请参见第 3.5.6 节。

11.5 删除脚本模块

可以通过 cmdlet Remove-Module 从会话中删除一个或多个模块。

删除模块不会卸载该模块。

在脚本模块中,可以指定在删除该模块之前执行的代码,如下所示:

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

11.6 模块清单

如第 11.1 节中所述,清单模块是一个包含模块信息的文件,并控制该模块使用的某些方面。

模块不需要有相应的清单,但如果有,则该清单与其描述的模块具有相同的名称,但具有 .psd1 文件扩展名。

清单包含 PowerShell 脚本的有限子集,该脚本返回包含一组键的哈希表。这些键及其值指定该模块的清单元素。也就是说,它们描述模块的内容和属性,定义任何先决条件,并确定如何处理组件。

本质上,清单是一个数据文件;但是,它可以包含对数据类型、if 语句以及算术和比较运算符的引用。 (不允许赋值、函数定义和循环。)清单还具有对环境变量的读取访问权限,并且它可以包含对 cmdlet Join-Path 的调用,因此可以构建路径。

笔记

编者注:原始文档包含模块清单文件中允许的键列表。该列表已过时且不完整。有关模块清单中键的完整列表,请参阅 New-ModuleManifest。

唯一需要的键是ModuleVersion

这是一个简单清单的示例:

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

GUID有一个字符串值。这指定了模块的全局唯一标识符(GUID)。 GUID可用于区分具有相同名称的模块。要创建新的 GUID,请调用方法[guid]::NewGuid()

11.7 动态模块

动态模块是运行时由 cmdlet New-Module 在内存中创建的模块;它不是从磁盘加载的。考虑以下示例:

$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

脚本块 $sb 定义模块的内容,在本例中是两个函数和这些函数的两个别名。与磁盘上模块一样,默认情况下仅导出函数,因此存在 Export-ModuleMember cmdlet 调用来导出函数和别名。

一旦 New-Module 运行,导出的四个名称就可以在会话中使用,如对 Convert-CentigradeToFahrenheit 和 c2f 的调用所示。

与所有模块一样,动态模块的成员在私有模块作用域中运行,该作用域是全局作用域的子级。 Get-Module 无法获取动态模块,但 Get-Command 可以获取导出的成员。

要使动态模块可供 Get-Module 使用,请将 New-Module 命令通过管道传输到 Import-Module,或通过管道传输 Import-Module 的模块对象code>New-Module 返回到 Import-Module。此操作将动态模块添加到 Get-Module 列表中,但不会将模块保存到磁盘或使其持久化。

11.8 闭包

动态模块可用于创建闭包,即带有附加数据的函数。考虑以下示例:

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

这里的目的是 Get-NextID 返回序列中可以指定起始值的下一个 ID。但是,必须支持多个序列,每个序列都有自己的 $startValue$nextID 上下文。这是通过调用方法 [scriptblock]::GetNewClosure (第 4.3.7 节)来实现的。

每次通过 GetNewClosure 创建一个新的闭包时,都会创建一个新的动态模块,并且调用者作用域中的变量(在本例中为包含增量的脚本块)被复制到这个新模块中。为了确保父函数内部(但在脚本块外部)定义的 nextId 递增,需要显式 script: 范围前缀。

当然,脚本块不必是命名函数;例如:

$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

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯