创建模块

257 阅读13分钟

概述

Windows PowerShell模块使您能够将Windows PowerShell代码划分、组织和抽象为自包含的、可重用的单元。有了这些可重用单元,您可以轻松地直接与其他人共享您的模块。如果您是脚本开发人员,您还可以重新打包第三方模块来创建基于脚本的自定义应用程序。

理解模块

官方文档

通过将一组相关的脚本文件程序集相关资源定义为一个模块,可以比使用其他方法更容易地引用、加载、持久化和共享代码。

创建模块的最基本方法是简单地将Windows PowerShell脚本保存为.psm1文件。这样做可以让你控制脚本中包含的函数和变量。将脚本保存为.psm1文件还允许您控制某些变量的范围。

模块组件和类型

一个模块由四个基本组件组成

  • 某种代码文件。通常是PowerShell脚本或托管cmdlet程序集
  • 上述代码文件可能需要的任何其他内容,例如附加程序集、帮助文件或脚本
  • 描述上述文件以及存储元数据的清单文件
  • 包含上述所有内容的目录,并且位于PowerShell可以合理地找到它的位置

这些组件本身并不是必须的。模块在技术上只能是存储在.psm1文件中的脚本。您还可以拥有一个只是一个清单文件的模块,它主要用于组织目的。您还可以编写一个脚本来动态创建一个模块,因此实际上不需要一个目录来存储任何东西。

脚本模块

脚本模块是包含任何有效的Windows PowerShell代码的文件(.psm1)。

二进制模块

二进制模块是一个程序集(.dll),它包含编译后的代码,比如c#。与脚本模块相比,二进制模块允许您创建更快的cmdlet,或者使用在Windows PowerShell脚本中不容易编码的特性(如多线程)。

清单模块

清单模块是使用清单文件描述其所有组件的模块,但没有任何类型的核心程序集或脚本。

动态模块

动态模块不是从文件中加载或保存到文件中的模块。相反,它们是通过使用New-Modulecmdlet的脚本动态创建的。这种类型的模块允许脚本按需创建不需要加载或保存到持久存储的模块。动态模块的本质是短命的,因此不能被Get-Modulecmdlet访问。类似地,它们通常不需要模块清单,也不可能需要永久文件夹来存储它们相关的程序集。

存储和安装模块

可以通过使用存储在$ENV:PSModulePath变量中的路径来确定应该在哪里安装模块。

模块cmdlet和变量

New-Module

创建了一个新的动态模块,它只存在于内存中。该模块是从一个脚本块创建的,其导出的成员(如函数和变量)在会话中立即可用,并且在会话关闭之前一直可用。

New-ModuleManifest

创建一个新的模块清单(.psd1)文件,填充其值,并将清单文件保存到指定的路径。

Import-Module

将一个或多个模块添加到当前会话。

Get-Module

检索关于已经导入或可以导入到当前会话中的模块的信息。

Export-ModuleMember

指定从脚本模块(.psm1)文件或使用New-Modulecmdlet创建的动态模块中导出的模块成员(如cmdlet、函数、变量和别名)。

Remove-Module

从当前会话中删除模块。

Test-ModuleManifest

通过验证模块清单文件(.psd1)中列出的文件实际上存在于指定的路径中,来验证模块清单是否准确地描述了模块的组件。

$PSScriptRoot

该变量包含脚本模块在其中执行的目录。它允许脚本使用模块路径来访问其他资源。

$env:PSModulePath

这个环境变量包含了Windows PowerShell模块存储目录的列表。Windows PowerShell在自动导入模块和更新模块的帮助主题时使用此变量的值。

脚本模块

官方文档

要创建脚本模块,请将有效的PowerShell脚本保存到.psm1文件中。脚本和存储它的目录必须使用相同的名称。例如,一个名为MyPsScript的脚本。psm1存储在名为MyPsScript的目录下。模块的目录需要在$env:PSModulePath中指定的路径中。模块的目录可以包含运行脚本所需的任何资源,以及一个向PowerShell描述模块如何工作的模块清单文件。

创建一个基本的PowerShell模块

下面的步骤描述了如何创建PowerShell模块。

  1. 保存一个扩展名为.psm1的PowerShell脚本。使用相同的脚本名称和存放目录。默认情况下,当用户导入.psm1文件时,脚本中的所有函数都可以访问,但是变量不能
  2. 控制用户对某些函数或变量的访问,请在脚本的末尾调用Export-ModuleMember。代码只有一个函数,默认情况下将公开该函数。但是,建议显式地调用希望公开的函数
  3. 如果您的模块需要加载其他模块模块,可以在模块的顶部使用Import-Module
  4. 要向PowerShell帮助系统描述您的模块,您可以在文件中使用标准帮助注释,或者创建一个额外的帮助文件
  5. 如果您有其他模块、XML文件或其他想要打包到模块中的内容,您可以使用模块清单
  6. 要安装和运行模块,请将模块保存到适当的PowerShell路径之一,并使用Import-Module。从PowerShell 3.0开始,如果您已经将模块置于PowerShell模块路径之一中,则不需要显式地导入它,当用户调用您的函数时,您的模块将自动加载
  7. 要从当前PowerShell会话中的活动服务中删除模块,请使用remove-module

二进制模块

官方文档

二进制模块可以是任何包含cmdlet类的程序集(.dll)。默认情况下,在导入二进制模块时将导入程序集中的所有cmdlet。但是,您可以通过创建其根模块为程序集的模块清单来限制导入的cmdlet。(例如,清单的CmdletsToExport键可以用于仅导出那些需要的cmdlet)—。此外,二进制模块可以包含单个cmdlet无法包含的其他文件、目录结构和其他有用的管理信息。

创建和安装一个PowerShell二进制模块

  1. 创建一个具有所需功能的二进制PowerShell解决方案(例如用c#编写的cmdlet),并确保它正确运行。二进制模块的核心就是一个cmdlet程序集。事实上,就加载和卸载而言,PowerShell将单个cmdlet程序集视为模块,开发人员不需要做任何额外的工作
  2. 如果有必要,创建解决方案的其余部分:(额外的cmdlet、XML文件等)并使用模块清单描述它们。模块清单还可以描述您希望如何导出和导入模块、将公开哪些cmdlet以及将哪些附加文件放入模块中。但是,如前所述,PowerShell可以将二进制cmdlet视为模块,而不需要额外的努力。因此,模块清单主要用于将多个文件组合到单个包中,或显式地控制给定程序集的发布
  3. 打包您的解决方案,并将该包保存到PowerShell模块路径的某个位置
  4. 通过调用Import-module将模块导入到PowerShell中。如果你使用的是PowerShell 3.0或更高版本,只需在代码中调用模块名也可以导入它

模块清单

官方文档

编写完PowerShell模块之后,可以添加一个可选的模块清单,其中包含关于该模块的信息。例如,您可以描述作者、指定模块中的文件(如嵌套模块)、运行脚本来定制用户的环境、加载类型和格式化文件、定义系统需求,以及限制模块导出的成员

创建模块清单

模块清单是一个PowerShell数据文件(.psd1),它描述模块的内容并确定如何处理模块。清单文件是一个包含键和值的散列表的文本文件。通过将清单文件命名为与模块相同的清单,并将清单文件存储在模块的根目录中,可以将清单文件链接到模块。

对于只包含一个.psm1或二进制程序集的简单模块模块清单是可选的。但是,建议尽可能使用模块清单,因为它们对帮助您组织代码和维护版本信息非常有用。并且,导出安装在全局程序集缓存中的程序集需要模块清单。

创建和使用模块清单

  1. 创建模块清单的最佳实践是使用New-ModuleManifestcmdlet。您可以使用参数来指定清单的一个或多个默认键和值。唯一的要求是命名文件
  2. 在清单文件中添加您想要的任何其他元素。
  3. 要解决基本模块清单元素可能没有涵盖的任何场景,您可以选择向模块清单添加额外的代码。PowerShell只运行模块清单文件中可用操作的一小部分。通常,您可以使用if语句、算术和比较运算符以及基本的PowerShell数据类型
  4. 创建模块清单之后,可以对其进行测试,以确认清单中描述的任何路径都是正确的。要测试模块清单,请使用test-modulemanifest。如:Test-ModuleManifest myModuleName.psd1
  5. 确保您的模块清单位于包含您的模块的目录的顶层
  6. 还可以选择,您可以通过调用Import-Module来直接测试您的模块清单,方法是对清单本身进行“点号溯源”。如:Import-Module .\myModuleName.psd1

模块清单元素

元素数据类型默认值描述示例
RootModuleString<empty string>与此清单关联的脚本模块或二进制模块文件
根模块的可能类型可以为空,这将创建一个Manifest模块、一个脚本模块的名称(.psm1)或一个二进制模块的名称(.exe或.dll)
在此元素中放置模块清单(.psd1)或脚本文件(.ps1)的名称会导致错误
RootModule = 'ScriptModule.psm1'
ModuleVersionVersion'0.0.1'此模块的版本号
如果没有指定值,New-ModuleManifest将使用默认值。字符串必须能够转换为版本类型,例如#.#.#.#
Import-Module加载它在$PSModulePath中找到的第一个与名称匹配的模块,并且ModuleVersion的值至少和MinimumVersion参数一样高
要导入特定的版本,请使用import-modulecmdlet的RequiredVersion参数
ModuleVersion = '1.0'
GUIDGUID'<GUID>'用于唯一标识此模块的ID
如果没有指定值,New-ModuleManifest会自动生成该值
当前不能通过GUID导入模块
GUID = 'cfc45206-1e49-459d-a8ad-5b571ef94857'
AuthorString'<Current user>'这个模块的作者
如果没有指定值,New-ModuleManifest将使用当前用户
Author = 'AuthorNameHere'
CompanyNameString'Unknown'此模块的公司或供应商
如果没有指定值,New-ModuleManifest将使用默认值
CompanyName = 'Fabrikam'
CopyrightString'(c) <Author>. All rights reserved.'此模块的版权声明
如果没有指定值,New-ModuleManifest将使用默认值,当前用户为
若要指定作者,请使用author参数
Copyright = '2019 AuthorName. All rights reserved.'
DescriptionString<empty string>此模块提供的功能的描述Description = 'This is the module's description.'
PowerShellVersionVersion<empty string>此模块所需的PowerShell引擎的最小版本
有效值为1.0、2.0、3.0、4.0、5.0、5.1、6.0、6.1、6.2、7.0和7.1
PowerShellVersion = '5.0'
PowerShellHostNameString<empty string>此模块所需的PowerShell主机名
这个名称由PowerShell提供
要查找主机程序的名称,在程序中输入$host.name
PowerShellHostName = 'ConsoleHost'
PowerShellHostVersionVersion<empty string>此模块所需的PowerShell主机的最小版本PowerShellHostVersion = '2.0'
DotNetFrameworkVersionVersion<empty string>此模块所需的Microsoft .net框架的最小版本
这个前提条件仅对PowerShell桌面版有效,例如PowerShell 5.1
DotNetFrameworkVersion = '3.5'
CLRVersionVersion<empty string>此模块所需的公共语言运行库(CLR)的最小版本
这个前提条件仅对PowerShell桌面版有效,例如PowerShell 5.1
CLRVersion = '3.5'
ProcessorArchitectureProcessorArchitecture<empty string>该模块所需的处理器架构
有效值为x86、AMD64、Arm、IA64、MSIL和None(未知或未指定)
ProcessorArchitecture = 'x86'
RequiredModulesObject[]@()在导入此模块之前必须导入到全局环境中的模块
这将加载列出的任何模块,除非它们已经被加载。例如,一些模块可能已经被不同的模块加载
可以使用RequiredVersion而不是ModuleVersion指定要加载的特定版本
当使用ModuleVersion时,它将加载具有指定版本最小值的最新版本
您可以在参数值中组合字符串和散列表
RequiredModules = @("MyModule", @{ModuleName="MyDependentModule"; ModuleVersion="2.0"; GUID="cfc45206-1e49-459d-a8ad-5b571ef94857"})
RequiredModules = @("MyModule", @{ModuleName="MyDependentModule"; RequiredVersion="1.5"; GUID="cfc45206-1e49-459d-a8ad-5b571ef94857"})
RequiredAssembliesString[]@()在导入此模块之前必须加载的程序集
指定模块所需的程序集(.dll)文件名
PowerShell在更新类型或格式、导入嵌套模块或导入在RootModule键值中指定的模块文件之前加载指定的程序集
使用此参数列出模块所需的所有程序集
RequiredAssemblies = @("assembly1.dll", "assembly2.dll", "assembly3.dll")
ScriptsToProcessString[]@()当模块被导入时,在调用者的会话状态下运行的脚本(.ps1)文件
这可以是全局会话状态,或者对于嵌套模块,是另一个模块的会话状态。可以使用这些脚本准备环境,就像使用登录脚本一样
这些脚本在加载清单中列出的任何模块之前运行
criptsToProcess = @("script1.ps1", "script2.ps1", "script3.ps1")
TypesToProcessString[]@()输入在导入这个模块时要加载的文件(.ps1xml)TypesToProcess = @("type1.ps1xml", "type2.ps1xml", "type3.ps1xml")
FormatsToProcessString[]@()在导入此模块时格式化要加载的文件(.ps1xml)FormatsToProcess = @("format1.ps1xml", "format2.ps1xml", "format3.ps1xml")
NestedModulesObject[]@()作为RootModule(别名:ModuleToProcess)中指定的模块的嵌套模块导入的模块
向此元素添加模块名称类似于从脚本或汇编代码中调用Import-Module
使用清单文件的主要区别在于,它更容易看到正在加载的内容。而且,如果一个模块加载失败,您还没有加载实际的模块
除了其他模块之外,您还可以在这里加载脚本(.ps1)文件。这些文件将在根模块的上下文中执行。这相当于在根模块中点源代码脚本
NestedModules = @("script.ps1", @{ModuleName="MyModule"; ModuleVersion="1.0.0.0"; GUID="50cdb55f-5ab7-489f-9e94-4ec21ff51e59"})
FunctionsToExportString[]@()指定要从此模块导出的函数,为了获得最佳性能,不要使用通配符,也不要删除条目,如果没有要导出的函数,请使用空数组。缺省情况下,不导出函数。您可以使用此键列出模块导出的函数
模块将函数导出到调用者的会话状态。调用者的会话状态可以是全局会话状态,或者对于嵌套模块,是另一个模块的会话状态。当链接嵌套模块时,由嵌套模块导出的所有函数将被导出到全局会话状态,除非链中的模块使用FunctionsToExport键限制该函数
如果清单导出了函数的别名,则该键可以删除别名列在AliasesToExport键中的函数,但该键不能将函数别名添加到列表中
FunctionsToExport = @("function1", "function2", "function3")
CmdletsToExportString[]@()指定要从此模块导出的cmdlet,为了获得最佳性能,不要使用通配符,也不要删除条目,如果没有要导出的cmdlet,则使用空数组。默认情况下,不导出cmdlet。您可以使用此键列出模块导出的cmdlet
调用者的会话状态可以是全局会话状态,或者对于嵌套模块,是另一个模块的会话状态。当您链接嵌套模块时,由嵌套模块导出的所有cmdlet将被导出到全局会话状态,除非链中有一个模块使用CmdletsToExport键限制了cmdlet
如果清单导出cmdlet的别名,则此键可以删除别名列在AliasesToExport键中的cmdlet,但此键不能将cmdlet别名添加到列表中
CmdletsToExport = @("Get-MyCmdlet", "Set-MyCmdlet", "Test-MyCmdlet")
VariablesToExportString[]'*'指定模块导出到调用者会话状态的变量。允许使用通配符。默认情况下,导出所有变量('*')。您可以使用此键来限制模块导出的变量
调用者的会话状态可以是全局会话状态,或者对于嵌套模块,是另一个模块的会话状态。当您将嵌套模块链接起来时,所有由嵌套模块导出的变量都将被导出到全局会话状态,除非链中的模块使用VariablesToExport键来限制变量
如果清单也导出了变量的别名,那么这个键可以删除别名列在AliasesToExport键中的变量,但是这个键不能将变量别名添加到列表中
VariablesToExport = @('MyVariable1,MyVariable1', 'MyVariable2', '$MyVariable3')
AliasesToExportString[]@()指定要从此模块导出的别名,为了获得最佳性能,不要使用通配符,也不要删除条目,如果没有要导出的别名,则使用空数组。默认情况下,不导出别名。您可以使用此键列出模块导出的别名
模块将别名导出到调用者的会话状态。调用者的会话状态可以是全局会话状态,或者对于嵌套模块,是另一个模块的会话状态。当您链接嵌套模块时,嵌套模块导出的所有别名最终将被导出到全局会话状态,除非链中的模块使用AliasesToExport键限制别名
AliasesToExport = @("MyAlias1", "MyAlias2", "MyAlias3")
DscResourcesToExportString[]@()指定与此模块打包的所有模块
这些模块可以通过名称输入,使用逗号分隔的字符串,或者作为一个带有ModuleName和GUID键的散列表
散列表也可以有一个可选的ModuleVersion键。ModuleList键被设计成一个模块清单
这些模块不会被自动处理
ModuleList = @("SampleModule", "MyModule", @{ModuleName="MyModule"; ModuleVersion="1.0.0.0"; GUID="50cdb55f-5ab7-489f-9e94-4ec21ff51e59"})
FileListString[]@()这个模块打包的所有文件的列表
与ModuleList一样,FileList是一个库存列表,否则不会被处理
FileList = @("File1", "File2", "File3")
PrivateDataObject@{...}指定需要传递给RootModule(别名:ModuleToProcess)密钥指定的根模块的任何私有数据
PrivateData是一个散列表,它包含几个元素:Tags,icenseUri, ProjectURI,IconUri,ReleaseNotes,prerrelease,RequireLicenseAcceptance和ExternalModuleDependencies
/
TagsString[]@()标记有助于在在线图库中发现模块Tags = "PackageManagement", "PowerShell", "Manifest"
LicenseUriUri<empty string>这个模块的许可证的URLLicenseUri = 'www.contoso.com/license'
ProjectUriUri<empty string>这个项目的主要网站的URLProjectUri = 'www.contoso.com/project'
IconUriUri<empty string>表示此模块的图标的URLIconUri = 'www.contoso.com/icons/icon.…'
ReleaseNotesString<empty string>指定模块的发布说明ReleaseNotes = 'The release notes provide information about the module'
PreReleaseString<empty string>预发布字符串,将模块标识为在线图库中的预发布版本PreRelease = 'This module is a prerelease version'
RequireLicenseAcceptanceBoolean$true标志,指示模块是否需要用户明确接受安装、更新或保存RequireLicenseAcceptance = $false
ExternalModuleDependenciesString[]@()此模块所依赖的外部模块列表ExternalModuleDependencies = @("ExtModule1", "ExtModule2", "ExtModule3")
HelpInfoURIString<empty string>这个模块的帮助信息URIHelpInfoURI = 'www.contoso.com//help'
DefaultCommandPrefixString<empty string>从此模块导出的命令的默认前缀
使用Import-Module -Prefix覆盖默认前缀
DefaultCommandPrefix = 'My'

示例模块清单

#
# Module manifest for module 'SampleModuleManifest'
#
# Generated by: User01
#
# Generated on: 10/15/2019
#

@{

	# Script module or binary module file associated with this manifest.
	# RootModule = ''

	# Version number of this module.
	ModuleVersion = '0.0.1'

	# Supported PSEditions
	# CompatiblePSEditions = @()

	# ID used to uniquely identify this module
	GUID = 'b632e90c-df3d-4340-9f6c-3b832646bf87'

	# Author of this module
	Author = 'User01'

	# Company or vendor of this module
	CompanyName = 'Unknown'

	# Copyright statement for this module
	Copyright = '(c) User01. All rights reserved.'

	# Description of the functionality provided by this module
	# Description = ''

	# Minimum version of the PowerShell engine required by this module
	# PowerShellVersion = ''

	# Name of the PowerShell host required by this module
	# PowerShellHostName = ''

	# Minimum version of the PowerShell host required by this module
	# PowerShellHostVersion = ''

	# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
	# DotNetFrameworkVersion = ''

	# Minimum version of the common language runtime (CLR) required by this module. This 	prerequisite is valid for the PowerShell Desktop edition only.
	# CLRVersion = ''

	# Processor architecture (None, X86, Amd64) required by this module
	# ProcessorArchitecture = ''

	# Modules that must be imported into the global environment prior to importing this module
	# RequiredModules = @()

	# Assemblies that must be loaded prior to importing this module
	# RequiredAssemblies = @()

	# Script files (.ps1) that are run in the caller's environment prior to importing this module.
	# ScriptsToProcess = @()

	# Type files (.ps1xml) to be loaded when importing this module
	# TypesToProcess = @()

	# Format files (.ps1xml) to be loaded when importing this module
	# FormatsToProcess = @()

	# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
	# NestedModules = @()

	# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
	FunctionsToExport = @()

	# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
	CmdletsToExport = @()

	# Variables to export from this module
	VariablesToExport = '*'

	# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
	AliasesToExport = @()

	# DSC resources to export from this module
	# DscResourcesToExport = @()

	# List of all modules packaged with this module
	# ModuleList = @()

	# List of all files packaged with this module
	# FileList = @()

	# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
	PrivateData = @{

		PSData = @{

			# Tags applied to this module. These help with module discovery in online galleries.
			# Tags = @()

			# A URL to the license for this module.
			# LicenseUri = ''

			# A URL to the main website for this project.
			# ProjectUri = ''

			# A URL to an icon representing this module.
			# IconUri = ''

			# ReleaseNotes of this module
			# ReleaseNotes = ''

			# Prerelease string of this module
			# Prerelease = ''

			# Flag to indicate whether the module requires explicit user acceptance for install/update/save
			RequireLicenseAcceptance = $true

			# External dependent modules of this module
			# ExternalModuleDependencies = @()

		} # End of PSData hashtable

	} # End of PrivateData hashtable

	# HelpInfo URI of this module
	# HelpInfoURI = ''

	# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
	# DefaultCommandPrefix = ''

}