我刚刚在Powershell中遇到错误:
because the module nesting limit has been exceeded. Modules can only be nested to 10 levels.
我找到了这个,并找到了一个名为"模块清单"的东西。我已经有一个模块 .psm1 文件 - 为什么我还需要这个?
注意:我没有 10 个级别的模块,我有 10 个模块,全部由一个 import.psm1 文件加载。
超出模块嵌套级别通常是由于在模块导入过程中意外进入无限递归的结果(无论您是通过Import-Module
还是 PSv5+using module
语句导入(。
无论您的模块是否有清单,都会发生这种情况;链接问题的答案显示了清单是如何发生的;下面是一个没有清单的示例:以下foo.psm1
模块会导致无限递归,从而导致您看到的错误消息
# Create sample module (without manifest).
@'
# Accidentally try to import the module itself.
using module .foo.psm1
function bar { 'hi from module foo' }
'@ > foo.psm1
# This fails, because an infinite import loop is entered,
# eventually causing the nesting limit to be exceeded.
Import-Module .foo.psm1
为什么使用清单创建(脚本(模块是个好主意:
虽然模块清单是可选的- 独立*.psm1
文件可以单独用作模块 - 但有充分的理由使用它们:
模块清单是*.psm1
文件附带的*.psd1
文件,以哈希表文本的形式指定重要的元数据,特别是版本号;为了获得最佳用户体验,两个文件应放在同名的目录中(例如,Foo.psm1
,其清单Foo.psd1
应放在名为Foo
的目录中(。
通过使用清单模块,您可以启用几个重要的用例:
您需要一个清单来正确支持模块的软件开发过程,尤其是版本管理。
- 这也是支持并行安装多个版本的模块的先决条件。
需要一个清单来自动加载关联的资源(如其他模块或辅助 .NET 程序集(,并定义帮助资源。
您需要一个清单才能与PowerShell的模块自动加载机制集成: 如果将正确列出的模块放入
$env:PSModulePath
中列出的目录之一,PowerShell 将:- 甚至在导入模块之前就发现模块及其命令。
- 将按需导入它,第一次尝试从会话调用命令。
您需要一个清单才能将模块发布到 PowerShell 模块的官方在线存储库,即 PowerShell 库
要快速概述使用清单创建模块的步骤,请执行以下操作:
- 创建一个以
.psm1
文件的基本名称命名的目录;例如,Foo
- 将脚本代码作为文件
Foo.psm1
文件放在该目录中。 在同一目录中,使用
New-ModuleManifest
cmdlet 创建具有相同基本名称的清单.psd1
文件(例如,Foo.psd1
(至少,更新新
.psd1
文件中的RootModule
条目以指向您的.psm1
文件(例如,RootModule = 'Foo.psm1'
(要与自动加载功能集成,请将模块目录放在
$env:PSModulePath
中列出的位置之一;对于当前用户,该位置为:- Windows PowerShell:
$HOMEDocumentsWindowsPowerShellModules
- PowerShell [Core] v6+:
- 窗户:
$HOMEDocumentsPowerShellModules
- Linux, macOS:
$HOME/.local/share/powershell/Modules
- 窗户:
- Windows PowerShell:
为了有效地支持模块发现和自动加载,并显式控制和指示模块导出的内容,最好在
FunctionsToExport
中显式列出各个导出的模块成员,CmdletsToExport
、VariablesToExport
和AliasesToExport
清单的条目。
为了使模块创建更容易,社区提供了帮助程序模块:
Plaster
是一个"用PowerShell编写的基于模板的文件和项目生成器",也可用于搭建模块的基架:内置的"新建 PowerShell 清单模块"模板将模块目录设置为基架,其中包含所有必要的文件,并支持
Pester
测试。有关演练,请参阅此博客文章。
Stucco
建立在Plaster的基础上,提供了一个"用于构建高质量PowerShell模块的固执己见的Plaster模板"。- Stucco 是一种高级工具,它超越了单纯的模块创建,通过搭建整个项目结构的基架,包括
psake
任务、用于 CI/CD 集成的基架、许可和帮助创作。
- Stucco 是一种高级工具,它超越了单纯的模块创建,通过搭建整个项目结构的基架,包括
一个快速的例子Plaster
:
# Install Plaster for the current user, if necessary.
Install-Module Plaster -Scope CurrentUser
# Get the template for creating a new script module.
$template = Get-PlasterTemplate | Where TemplatePath -match ScriptModule
# Scaffold a module in subdirectory 'Foo'
# * This will present a series of prompts, most of them with default values.
# * IMPORTANT: Be sure to also choose 'Foo' as the module *name* when prompted,
# so that the module auto-loading feature can discover your module
# (if placed in a dir. in $env:PSModulePath) and also so that you
# you can load it by its *directory* path; e.g., Import-Module ./Foo
Invoke-Plaster -TemplatePath $template.TemplatePath -Destination Foo
# Add a test function to the `.psm1` file.
# Note:
# * This is just for illustrative purposes. In real life, you would
# obviously use an editor to add functions to your module.
# * The function must be placed *before* the `Export-ModuleMember` call in order
# to be exported.
# * As stated, it is additionally recommended to list the exported members
# *explicitly*, one by one, in the *ToExport keys of the *.psd1 file.
(Get-Content -Raw ./Foo/Foo.psm1) -replace 'r?nr?n', "`n`nfunction Get-Foo { 'Hi from module Foo.' }`n" | Set-Content -Encoding utf8 ./Foo/Foo.psm1
# Import the newly created module by its *directory* path.
# IMPORTANT:
# As stated, this assumes that you specified 'Foo' as the module name, i.e.
# that your manifest's file name is 'Foo.psd1', and your script module's
# 'Foo.psm1'.
Import-Module ./Foo -Verbose -Force
'---'
# Call the test function
Get-Foo
'---'
# Invoke the module's tests.
# Note: The scaffolding creates a single test to ensure that the
# module manifest (*.psd1) is valid.
Invoke-Pester ./Foo
应会看到如下所示的输出:
VERBOSE: Loading module from path 'C:UsersjdoeFooFoo.psd1'.
VERBOSE: Loading module from path 'C:UsersjdoeFooFoo.psm1'.
VERBOSE: Importing function 'Get-Foo'.
---
Hi from module Foo.
---
____ __
/ __ ___ _____/ /____ _____
/ /_/ / _ / ___/ __/ _ / ___/
/ ____/ __(__ ) /_/ __/ /
/_/ ___/____/__/___/_/
Pester v4.9.0
Executing all tests in './Foo'
Executing script C:UsersjdoeFootestFoo.Tests.ps1
Describing Module Manifest Tests
[+] Passes Test-ModuleManifest 128ms
Tests completed in 375ms
Tests Passed: 1, Failed: 0, Skipped: 0, Pending: 0, Inconclusive: 0