Import-Module 详细输出意味着模块被加载了两次
Import-Module Verbose output implies module is loaded twice
我有一个模块 (MyModule) 在非标准路径下,即不在 $env:PSModulePath -split ";"
中列出的通常位置下。但是,在我继续处理 "development" 副本时,我已将 MyModule 的 "production" 路径添加到该环境变量。
在尝试调试某些东西时,我使用以下命令加载了模块(使用 $VerbosePreference = "Continue"
),并立即看到了两条看似矛盾的 Verbose 输出行:
[D:\Dev\UserA\]> Import-Module D:\Dev\UserA\libs\PowerShell\MyModule
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\MyModule.psd1'.
VERBOSE: Loading module from path 'D:\Dev\usera\MyModule2\MyModule.psm1'.
我想了解为什么 Import-Module 似乎加载了两次模块,尤其是第二条路径不正确。
更多详情:
模块的文件夹结构是:
MyModule\MyModule.psd1
MyModule\MyModule.Test-Module.xml
MyModule\MyModule1\MyModule.psm1
MyModule\MyModule2\MyModule.psm1
注意 (1) 我在 MyModule1 子文件夹中保留了该模块的旧 "version 1" 并将更新后的 "version 2" 文件放在 MyModule2 子文件夹中,并且 (2) . xml 文件被自定义模块测试脚本用来列出测试用例。我很确定后者可以忽略。
我的模块清单 (.psd1) 文件包含以下内容,所有其他行均为空白或注释:
@{
RootModule = '.\MyModule2\MyModule.psm1'
ModuleVersion = '2.0.0.0'
GUID = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
Author = 'Old Developer (v1.x) & New Developer (v2.x)'
CompanyName = 'MyCompany'
Copyright = '(c) 2013-2015 MyCompany. All rights reserved.'
Description = 'Really useful functions'
FileList = @(
'.\MyModule.psd1'
'.\MyModule.Test-Module.xml'
'.\MyModule1\MyModule.psm1'
'.\MyModule2\MyModule.psm1'
'.\MyModule2\Examples\Archive-FilesWithCompression.ps1'
)
}
很明显,我使用了文件的相对路径,尤其是。 RootModule 键;这是必要的,因为我无法确定共享模块时会将模块复制到哪里。
回到详细输出,我可以看到这两行显示 (1) PSD1 文件的正确路径和 (2) PSM1 文件的无效路径。我确实注意到第二条路径的用户名是小写的,这就是我在测试前 Set-Location
时碰巧输入的方式。因此,看起来第一个路径是通过将 MyModule.psd1 附加到给定 Import-Module
cmdlet 的路径而采用的,第二个路径是 (Get-Location) 和 RootModule 路径的串联。
这似乎只发生在这个模块上。我在同一个 'root' 文件夹下还有其他人没有表现出这种行为。
嗯。好的。我可能已经解决了,至少部分解决了...
我不小心在 运行 Import-Module cmdlet 所在的位置下复制了 MyModule2 sub-folder。删除该文件夹后,详细的输出开始变得更有意义:
[D:\Dev\UserA\]> Import-Module D:\Dev\UserA\libs\PowerShell\MyModule
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\MyModule.psd1'.
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\.\MyModule2\MyModule.psm1'.
VERBOSE: Exporting function '<function>'.
....
我猜这意味着当 PowerShell 解析清单文件中的 RootModule 时,它首先在当前路径下查找,如果没有找到,然后在主模块文件夹下查找。我发现这个 counter-intuitive 因为我希望清单中的任何相对路径总是相对于 PSD1 文件,而不是当前位置。
如果我然后尝试再次导入模块立即我得到这个:
[D:\Dev\UserA\]> Import-Module D:\Dev\UserA\libs\PowerShell\MyModule
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\MyModule.psd1'.
VERBOSE: Importing function '<function>'.
....
即只有一行"loading module"行,而不是冗长输出的两行。然后我尝试了 -Force
开关并得到以下结果:
[D:\Dev\UserA\]> Import-Module D:\Dev\UserA\libs\PowerShell\MyModule -Force
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\MyModule.psd1'.
VERBOSE: Removing the imported "<function>" function.
....
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\.\MyModule2\MyModule.psm1'.
VERBOSE: Exporting function '<function>'.
....
VERBOSE: Importing function '<function>'.
....
因此,似乎在首次导入模块时或强行导入模块时出现两行详细输出re-imported,但如果它已经是会话的一部分,那么您只会看到第一行。
此外,我终于发现 exporting 函数和 importing 函数之间的详细输出不同。这些函数按它们在 PSM1 文件中定义的顺序 exported,但按字母顺序 imported。这表明使用一个或 two-stage 过程取决于函数定义是否来自 PSM1 文件 re-read,与我们是否看到一行或两行详细输出有关。
或者,为了更直接地回答问题,当它需要读取 .psm1 文件时,似乎有两行说 "Loading module..." ,而当 PowerShell 已经知道该模块时,只有一行说 "Loading module..." 并且它的内容。
我有一个模块 (MyModule) 在非标准路径下,即不在 $env:PSModulePath -split ";"
中列出的通常位置下。但是,在我继续处理 "development" 副本时,我已将 MyModule 的 "production" 路径添加到该环境变量。
在尝试调试某些东西时,我使用以下命令加载了模块(使用 $VerbosePreference = "Continue"
),并立即看到了两条看似矛盾的 Verbose 输出行:
[D:\Dev\UserA\]> Import-Module D:\Dev\UserA\libs\PowerShell\MyModule
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\MyModule.psd1'.
VERBOSE: Loading module from path 'D:\Dev\usera\MyModule2\MyModule.psm1'.
我想了解为什么 Import-Module 似乎加载了两次模块,尤其是第二条路径不正确。
更多详情:
模块的文件夹结构是:
MyModule\MyModule.psd1
MyModule\MyModule.Test-Module.xml
MyModule\MyModule1\MyModule.psm1
MyModule\MyModule2\MyModule.psm1
注意 (1) 我在 MyModule1 子文件夹中保留了该模块的旧 "version 1" 并将更新后的 "version 2" 文件放在 MyModule2 子文件夹中,并且 (2) . xml 文件被自定义模块测试脚本用来列出测试用例。我很确定后者可以忽略。
我的模块清单 (.psd1) 文件包含以下内容,所有其他行均为空白或注释:
@{
RootModule = '.\MyModule2\MyModule.psm1'
ModuleVersion = '2.0.0.0'
GUID = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
Author = 'Old Developer (v1.x) & New Developer (v2.x)'
CompanyName = 'MyCompany'
Copyright = '(c) 2013-2015 MyCompany. All rights reserved.'
Description = 'Really useful functions'
FileList = @(
'.\MyModule.psd1'
'.\MyModule.Test-Module.xml'
'.\MyModule1\MyModule.psm1'
'.\MyModule2\MyModule.psm1'
'.\MyModule2\Examples\Archive-FilesWithCompression.ps1'
)
}
很明显,我使用了文件的相对路径,尤其是。 RootModule 键;这是必要的,因为我无法确定共享模块时会将模块复制到哪里。
回到详细输出,我可以看到这两行显示 (1) PSD1 文件的正确路径和 (2) PSM1 文件的无效路径。我确实注意到第二条路径的用户名是小写的,这就是我在测试前 Set-Location
时碰巧输入的方式。因此,看起来第一个路径是通过将 MyModule.psd1 附加到给定 Import-Module
cmdlet 的路径而采用的,第二个路径是 (Get-Location) 和 RootModule 路径的串联。
这似乎只发生在这个模块上。我在同一个 'root' 文件夹下还有其他人没有表现出这种行为。
嗯。好的。我可能已经解决了,至少部分解决了...
我不小心在 运行 Import-Module cmdlet 所在的位置下复制了 MyModule2 sub-folder。删除该文件夹后,详细的输出开始变得更有意义:
[D:\Dev\UserA\]> Import-Module D:\Dev\UserA\libs\PowerShell\MyModule
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\MyModule.psd1'.
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\.\MyModule2\MyModule.psm1'.
VERBOSE: Exporting function '<function>'.
....
我猜这意味着当 PowerShell 解析清单文件中的 RootModule 时,它首先在当前路径下查找,如果没有找到,然后在主模块文件夹下查找。我发现这个 counter-intuitive 因为我希望清单中的任何相对路径总是相对于 PSD1 文件,而不是当前位置。
如果我然后尝试再次导入模块立即我得到这个:
[D:\Dev\UserA\]> Import-Module D:\Dev\UserA\libs\PowerShell\MyModule
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\MyModule.psd1'.
VERBOSE: Importing function '<function>'.
....
即只有一行"loading module"行,而不是冗长输出的两行。然后我尝试了 -Force
开关并得到以下结果:
[D:\Dev\UserA\]> Import-Module D:\Dev\UserA\libs\PowerShell\MyModule -Force
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\MyModule.psd1'.
VERBOSE: Removing the imported "<function>" function.
....
VERBOSE: Loading module from path 'D:\Dev\UserA\libs\PowerShell\MyModule\.\MyModule2\MyModule.psm1'.
VERBOSE: Exporting function '<function>'.
....
VERBOSE: Importing function '<function>'.
....
因此,似乎在首次导入模块时或强行导入模块时出现两行详细输出re-imported,但如果它已经是会话的一部分,那么您只会看到第一行。
此外,我终于发现 exporting 函数和 importing 函数之间的详细输出不同。这些函数按它们在 PSM1 文件中定义的顺序 exported,但按字母顺序 imported。这表明使用一个或 two-stage 过程取决于函数定义是否来自 PSM1 文件 re-read,与我们是否看到一行或两行详细输出有关。
或者,为了更直接地回答问题,当它需要读取 .psm1 文件时,似乎有两行说 "Loading module..." ,而当 PowerShell 已经知道该模块时,只有一行说 "Loading module..." 并且它的内容。