【问题标题】:Why would I need a module manifest - because the module nesting limit has been exceeded为什么我需要模块清单 - 因为已超出模块嵌套限制
【发布时间】:2020-01-27 13:16:57
【问题描述】:

我刚刚在 Powershell 中遇到错误:

 because the module nesting limit has been exceeded. Modules can only be nested to 10 levels.

我找到了this 并找到了一个叫做“模块清单”的东西。我已经有一个模块 .psm1 文件 - 为什么我还需要这个?

注意:我没有 10 级模块,我有 10 个模块,全部由一个 import.psm1 文件加载。

【问题讨论】:

    标签: powershell module manifest powershell-module


    【解决方案1】:

    模块嵌套级别超出通常是由于在模块导入期间意外进入无限递归(无论您是通过 Import-Module 还是 PSv5+ 导入using module 声明)。

    无论您的模块是否有清单,这都可能发生linked question 的答案显示了它是如何通过清单 发生的;这是一个示例没有:以下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 文件可以自己充当modules - 有使用它们的充分理由

    模块清单是一个 *.psd1 文件,它伴随着您的 *.psm1 文件并以 元数据,尤其是版本号>散列表文字;为获得最佳用户体验,两个文件都应放在 同名目录中(例如,Foo.psm1 及其清单,@ 987654340@,应放在名为Foo的目录中。

    通过使用清单模块,您可以启用几个重要的用例

    • 您需要一个清单来正确支持模块的软件开发流程,尤其是版本管理。

      • 它也是支持多个版本的模块并排安装的先决条件。
    • 您需要一个清单来自动加载相关资源,例如其他模块或辅助 .NET 程序集,并定义帮助资源。

    • 您需要一个清单才能与 PowerShell 的 module auto-loading mechanism 集成:如果您将正确显示的模块放入 $env:PSModulePath 中列出的目录之一,PowerShell 将:

      • 在导入模块之前就发现模块及其命令。
      • 将在您第一次尝试从会话中调用命令时按需导入
    • 您需要清单才能将模块发布到 PowerShell 模块的官方在线存储库 PowerShell Gallery


    快速概述使用清单创建模块的步骤

    • 创建一个以.psm1 文件的基本名称命名的目录;例如,Foo
    • 将脚本代码作为文件Foo.psm1文件放在该目录中。
    • 在同一目录中,使用New-ModuleManifest cmdlet,创建具有相同基本名称(例如Foo.psd1)的清单.psd1 文件

    • 至少,更新新的.psd1 文件中的RootModule 条目以指向您的.psm1 文件(例如,RootModule = 'Foo.psm1'

    • 要与自动加载功能集成,请将您的模块目录放在$env:PSModulePath 中列出的位置之一;对于当前用户,该位置是:

      • Windows PowerShell:
        • $HOME\Documents\WindowsPowerShell\Modules
      • PowerShell [核心] v6+:
        • 窗口:$HOME\Documents\PowerShell\Modules
        • Linux、macOS:$HOME/.local/share/powershell/Modules
    • 为了支持模块发现和自动加载高效显式控制和指示模块导出的内容,最好显式列出 FunctionsToExport 中的单个导出模块成员, CmdletsToExportVariablesToExportAliasesToExport 清单的条目。


    为了使模块创建更容易,社区提供了帮助模块

    • Plaster 是“用 PowerShell 编写的基于模板的文件和项目生成器”,也可用于构建模块:

      • 内置的“New PowerShell Manifest Module”模板构建了一个包含所有必要文件并支持Pester 测试的模块目录。

      • 请参阅 this blog post 了解详细信息。

    • Stucco 在 Plaster 的基础上构建,以提供“用于构建高质量 PowerShell 模块的自以为是的 Plaster 模板”。

      • Stucco 是一种高级工具,它超越了单纯的模块创建,它构建了整个项目结构,其中包括 psake 任务、用于 CI/CD 集成、许可和帮助创作的脚手架。

    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?\n\r?\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:\Users\jdoe\Foo\Foo.psd1'.
    VERBOSE: Loading module from path 'C:\Users\jdoe\Foo\Foo.psm1'.
    VERBOSE: Importing function 'Get-Foo'.
    ---
    Hi from module Foo.
    ---
        ____            __
       / __ \___  _____/ /____  _____
      / /_/ / _ \/ ___/ __/ _ \/ ___/
     / ____/  __(__  ) /_/  __/ /
    /_/    \___/____/\__/\___/_/
    Pester v4.9.0
    Executing all tests in './Foo'
    
    Executing script C:\Users\jdoe\Foo\test\Foo.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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-07
      • 1970-01-01
      • 2013-08-04
      • 1970-01-01
      • 2020-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多