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

[玩转系统] 脚本模块

作者:精品下载站 日期:2024-12-14 03:05:26 浏览:13 分类:玩电脑

脚本模块


如果您要经常使用 PowerShell 中的单行语句和脚本,那么将其转变为可重用工具就变得更加重要。将函数打包在脚本模块中可以使它们看起来更专业,并且更容易共享。

点源函数

我们在上一章中没有讨论点源函数。当脚本中的函数不是模块的一部分时,将其加载到内存中的唯一方法是对保存它的 .PS1 文件进行点源化。

以下函数已保存为 Get-MrPSVersion.ps1

function Get-MrPSVersion {
    $PSVersionTable
}

当您运行脚本时,什么也没有发生。

.\Get-MrPSVersion.ps1

如果您尝试调用该函数,它会生成一条错误消息。

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

您可以通过检查函数 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

调用包含函数的脚本的问题在于函数是在 Script 作用域中加载的。当脚本完成时,该作用域将被删除,该函数也会随之被删除。

该函数需要加载到全局范围内。这可以通过点源包含该函数的脚本来完成。可以使用相对路径。

. .\Get-MrPSVersion.ps1

也可以使用完全限定路径。

. C:\Demo\Get-MrPSVersion.ps1

如果路径的一部分存储在变量中,则可以将其与路径的其余部分组合。没有理由使用字符串连接将变量与路径的其余部分组合在一起。

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

现在,当我检查 Function PSDrive 时,Get-MrPSVersion 函数存在。

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

脚本模块

PowerShell 中的脚本模块只是一个包含一个或多个函数的文件,该文件保存为 .PSM1 文件而不是 .PS1 文件。

如何创建脚本模块?您可能正在猜测名为 New-Module 之类的命令。你的假设是错误的。虽然 PowerShell 中有一个名为 New-Module 的命令,但该命令创建的是动态模块,而不是脚本模块。即使您认为已经找到了所需的命令,也请务必阅读命令的帮助。

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"

在上一章中,我提到函数应该使用批准的动词,否则它们会在导入模块时生成警告消息。以下代码使用 New-Module cmdlet 在内存中创建动态模块。该模块演示了未批准的动词警告。

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.

重申一下,虽然前面的示例中使用了 New-Module cmdlet,但这并不是在 PowerShell 中创建脚本模块的命令。

将以下两个函数保存在名为 MyScriptModule.psm1 的文件中。

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

尝试调用其中一个函数。

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

生成一条错误消息,指出找不到该函数。您也可以像以前一样检查Function PSDrive,您会发现它也不存在。

您可以使用 Import-Module cmdlet 手动导入该文件。

Import-Module C:\MyScriptModule.psm1

PowerShell 版本 3 中引入了模块自动加载功能。要利用模块自动加载功能,需要将脚本模块保存在与 .PSM1 文件具有相同基本名称的文件夹中并保存在指定位置在 $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 Server0\Tools\PowerShell\Modules\

结果很难读。由于路径由分号分隔,因此您可以拆分结果以在单独的行上返回每个路径。这使得它们更容易阅读。

$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 Server0\Tools\PowerShell\Modules\

列表中的前三个路径是默认路径。安装 SQL Server Management Studio 时,它添加了最后一个路径。为了使模块自动加载工作,MyScriptModule.psm1 文件需要直接位于这些路径之一内名为 MyScriptModule 的文件夹中。

没那么快。对我来说,我当前的用户路径不是列表中的第一个。我几乎从不使用该路径,因为我使用与运行 PowerShell 不同的用户登录 Windows。这意味着它不位于我的普通文档文件夹中。

第二条路径是AllUsers 路径。这是我存储所有模块的位置。

第三个路径位于C:\Windows\System32 下。只有 Microsoft 才应将模块存储在该位置,因为它驻留在操作系统文件夹中。

一旦 .PSM1 文件位于正确的路径中,该模块将在调用其命令之一时自动加载。

模块清单

所有模块都应该有一个模块清单。模块清单包含有关模块的元数据。模块清单文件的文件扩展名是.PSD1。并非所有具有 .PSD1 扩展名的文件都是模块清单。它们还可用于存储 DSC 配置的环境部分等。 New-ModuleManifest 用于创建模块清单。 路径是唯一需要的值。但是,如果未指定 RootModule,该模块将无法工作。如果您决定使用 PowerShellGet 将模块上传到 NuGet 存储库,最好指定作者描述,因为在这种情况下需要这些值。

没有清单的模块的版本是 0.0.0。这是一个明显的泄露,表明该模块没有清单。

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

可以使用所有推荐信息创建模块清单。

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

如果在模块清单的初始创建过程中丢失了任何此类信息,可以稍后使用 Update-ModuleManifest 添加或更新。创建清单后,请勿使用 New-ModuleManifest 重新创建清单,因为 GUID 会发生变化。

定义公共和私人职能

您可能希望将辅助函数设为私有,并且只能由模块内的其他函数访问。它们不适合您的模块的用户访问。有几种不同的方法可以实现这一点。

如果您没有遵循最佳实践并且只有 .PSM1 文件,那么您唯一的选择就是使用 Export-ModuleMember cmdlet。

function Get-MrPSVersion {
    $PSVersionTable
}

function Get-MrComputerName {
    $env:COMPUTERNAME
}

Export-ModuleMember -Function Get-MrPSVersion

在前面的示例中,只有 Get-MrPSVersion 函数可供模块的用户使用,但 Get-MrComputerName 函数可供模块本身内的其他函数使用。

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

如果您已将模块清单添加到模块中(并且应该这样做),那么我建议您在模块清单的 FunctionsToExport 部分中指定要导出的各个函数。

FunctionsToExport = 'Get-MrPSVersion'

无需同时使用 .PSM1 文件中的 Export-ModuleMember 和模块清单的 FunctionsToExport 部分。选其一就足够了。

概括

在本章中,您学习了如何将函数转换为 PowerShell 中的脚本模块。您还了解了创建脚本模块的一些最佳实践,例如为脚本模块创建模块清单。

审查

  1. 如何在 PowerShell 中创建脚本模块?
  2. 为什么使用经过批准的动词对您的函数很重要?
  3. 如何在 PowerShell 中创建模块清单?
  4. 从模块中仅导出某些函数的两个选项是什么?
  5. 当调用命令时自动加载模块需要什么?

推荐阅读

  • 如何创建 PowerShell 脚本模块和模块清单
  • about_模块
  • New-ModuleManifest
  • Export-ModuleMember

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

取消回复欢迎 发表评论:

关灯