加载其他文件(ps1)以在PowerShell模块中使用

时间:2018-07-12 09:23:47

标签: powershell

我已经{。{1}}(我们称其为PowerShell Module)在.psd1中的定义如下:

PSModule

将其添加到此处,以便仅包含# Script files (.ps1) that are run in the caller's environment prior to importing this module. ScriptsToProcess = @('Enums\MessageType.ps1') 的文件MessageType.ps1可以在多个文件中重复使用。

此文件如下所示:

Enums

enum MessageType { None Something } -https://github.com/EvotecIT/PSWriteWord模块就是一个例子。这应该将Enums保留在其自己的文件夹中,并在模块启动时仍加载它们。

这在大多数情况下都可以正常工作。我运行脚本没有问题。现在,我已经创建了一个奇怪的情况:script1.ps1-我称之为。

script1.ps1的内容

PSWriteWord

现在从我呼叫的PSOtherModule的Call-Me函数中

Import-Module PSModule -Force

Import-Module PSOtherModule -Force

Call-Me -Parameters <params> # part of PSOtherModule

在ISE或VSCode中运行时它将起作用...

现在,如果我从Do-Something do-Something Call-OtherFunction # function from PSModule 重新运行相同的脚本,它将不会加载Task Scheduler,这实际上在某些时候会失败。似乎它只是跳过了MessageType的处理。

现在,如果您这样做:

ScriptsToProcess

它仍然无法工作...但这会...

Do-Something
do-Something
Import-Module PSModule
Call-OtherFunction # function from PSModule

因此,现在我正在努力寻找一种方法,以将ENUMS作为单独的文件正确添加到我的模块中,并在调用PSModule之前,使用IMport-Module进行怪异的解决方法,以使其保持运行状态。

我发现了这一点:https://d-fens.ch/2014/11/26/bug-powershell-scripts-in-scriptstoprocess-attribute-appear-as-loaded-modules/可以按照它说的做得很好,但是不能解决我的问题。

有人知道解决方法吗?我试着将全路径放到ScriptsToProcess中,以为ScriptsToProcess中的枚举路径可能会以某种方式被覆盖……但是没有。

我的.psm1文件如下:

Do-Something
do-Something
Import-Module PSModule -Force
Call-OtherFunction # function from PSModule

我刚刚添加了Enums,但是它没有任何改变。Export-Module之后的事情是从模块中删除脚本(如链接中所示)。没关系,我的问题。

可以在这里看到: enter image description here

2 个答案:

答案 0 :(得分:2)

注意:

  • 如果您只是根据通过Add-Type进行C#代码的按需编译而寻求一种有效的解决方案,请参见 MadBoy's own answer

  • 如果您想理解问题,包括为什么基于Add-Type的解决方案有帮助,请继续阅读。


行为符合预期

您在Import-Module PSModule -Force范围内的script.ps1点源Enums\MessageType.ps1中的script.ps1呼叫

因此,当模块Call-Me中的PSOtherModule运行时,对您已加载到script.ps1的枚举一无所知,因为PSOtherModule有自己的范围(不继承自调用方)。

Import-Module PSModule -Force中的Call-Me有效的原因是您在PSOtherModule 重新加载模块 >,然后将其作为点源Enums\MessageType.ps1,使enum可用(而省略-Force则是无操作的操作,因为PowerShell已经加载了模块(在全局会话中进行) ),因此不会再次处理模块清单及其ScriptsToProcess条目)。

是,Add-Type与包含按需编译的C#代码的字符串一起使用即可解决问题(如the answer you've since posted所示),但是出于不相关的原因:<添加strong> Add-Type的类型始终是 session-global ,而不管调用Add-Type的范围是什么。

要使用 PowerShell enum(或class)定义来实现相同的效果-从而解决您的问题-您需要:< / p>

  • 直接在您的enum文件中包含PSModule.psm1定义。

  • 使用using module PSModule指令而不是Import-Module PSModule cmdlet调用来导入模块-只有using module使基于PowerShell的enum和{{1 }}定义可以在模块外部使用,然后也可以全局会话


可选的背景信息:

  • classenum定义是PowerShell(v5)的新增功能,它们不是模块导出机制的一部分。

    • 在模块之外,classenum的定义对于它们在/点源中定义的范围是本地的。

    • 如果将classenum定义作为模块(class)的一部分,则使用*.psm1导入该模块,这些定义的确可以使用,但它们中的全部总是可用,并且总是 session-globally (基于using module的类型也一样,尽管它们甚至在Add-Type

    • 如果您使用Import-Module而不是Import-Module,则作为模块一部分的using moduleclass定义实际上是 private 。 / li>
  • 自Windows PowerShell v5.1 / PowerShell Core v6.1.0起,对enumenum定义的许多修复和增强尚在待解决中:

    • This meta GitHub issue跟踪所有这些内容。

    • class看到模块的Import-Moduleenum的定义in this issue进行了讨论;尽管从根本上说可能,class runtime 执行而Import-Module parse time 执行的事实排除了using module的某些用例(简而言之:Import-Module个定义引用了其他class个定义)。

    • 另外,能够显式控制要导出的 classenum定义-类似于如何有选择地导出函数,别名和变量-正在讨论in this issue

答案 1 :(得分:1)

要解决此问题,我选择将Add-Type与按需编译的C#代码一起使用,而不是PowerShell自己的enum构造。有用。

<#
enum MessageType {
    Alert
    Cancel
    Disable
    Download
    Minus
    Check
    Add
    None
}

#>


Add-Type -TypeDefinition @"
   public enum MessageType
   {
    Alert,
    Cancel,
    Disable,
    Download,
    Minus,
    Check,
    Add,
    None
   }
"@