Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
正在加载其他文件(ps1)以在PowerShell模块中使用_Powershell - Fatal编程技术网

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

正在加载其他文件(ps1)以在PowerShell模块中使用,powershell,Powershell,我有PowerShell模块(我们称之为PSModule),其中我在.psd1中定义如下 # Script files (.ps1) that are run in the caller's environment prior to importing this module. ScriptsToProcess = @('Enums\MessageType.ps1') 这是在那里添加的,因此保存justenum的文件MessageType.ps1可以跨多个文件重用 此文件看起来像: enum

我有
PowerShell模块
(我们称之为
PSModule
),其中我在.psd1中定义如下

# Script files (.ps1) that are run in the caller's environment prior to importing this module.
ScriptsToProcess = @('Enums\MessageType.ps1')
这是在那里添加的,因此保存just
enum
的文件
MessageType.ps1
可以跨多个文件重用

此文件看起来像:

enum MessageType {
   None
   Something
}
这方面的一个例子是
PSWriteWord
-模块。这应该将枚举保存在它自己的文件夹中,并在模块启动时仍然加载它们

这在大多数情况下都很有效。我运行的脚本没有问题。现在我创建了一个奇怪的场景:script1.ps1——我调用它

script1.ps1的内容

Import-Module PSModule -Force

Import-Module PSOtherModule -Force

Call-Me -Parameters <params> # part of PSOtherModule
在ISE或VSCode中运行时,它将工作

现在,如果我从
任务调度器
重新运行相同的脚本,它将不会加载
消息类型
,这在某一点上基本上会失败。它似乎只是跳过了
ScriptsToProcess
的处理

现在如果你这样做了:

Do-Something
do-Something
Import-Module PSModule
Call-OtherFunction # function from PSModule
还是不行。。。但这将

Do-Something
do-Something
Import-Module PSModule -Force
Call-OtherFunction # function from PSModule
所以现在我正在努力找到一种方法,在调用PSModule之前,正确地将枚举作为单独的文件添加到我的模块中,并在不使用IMport Module的奇怪解决方法的情况下保持运行

我发现:它言而有信,做得很好,但不能解决我的问题

有人知道解决这个问题的方法吗?我尝试将fullpath放入ScriptStopProcess,认为ScriptStopProcess中的枚举路径可能会被某种方式覆盖。。。但是没有

我的.psm1文件如下所示:

#Get public and private function definition files.
$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue )
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue )
$Enums = @( Get-ChildItem -Path $PSScriptRoot\Enums\*.ps1 -ErrorAction SilentlyContinue )

#Dot source the files
Foreach ($import in @($Public + $Private + $Enums)) {
    Try {
        . $import.fullname
    } Catch {
        Write-Error -Message "Failed to import function $($import.fullname): $_"

    }
}
Export-ModuleMember -Function '*'
[string] $ManifestFile = '{0}.psd1' -f (Get-Item $PSCommandPath).BaseName;
$ManifestPathAndFile = Join-Path -Path $PSScriptRoot -ChildPath $ManifestFile;
if ( Test-Path -Path $ManifestPathAndFile) {
    $Manifest = (Get-Content -raw $ManifestPathAndFile) | iex;
    foreach ( $ScriptToProcess in $Manifest.ScriptsToProcess) {
        $ModuleToRemove = (Get-Item (Join-Path -Path $PSScriptRoot -ChildPath $ScriptToProcess)).BaseName;
        if (Get-Module $ModuleToRemove) {
            Remove-Module $ModuleToRemove;
        }
    }
}
我刚才添加了枚举,但它没有改变任何东西。。。导出模块之后的事情是从模块中删除脚本(如链接中所示)。这与我的问题无关

可以在这里看到:

为了解决这个问题,我选择将
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
   }
"@

添加类型-类型定义@”
公共枚举消息类型
{
警觉的
取消
使残废
下载
减
检查
添加
没有一个
}
"@

为了解决这个问题,我选择将
添加类型
与按需编译的C#代码一起使用,而不是PowerShell自己的
枚举
构造。它起作用了

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

#>


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

添加类型-类型定义@”
公共枚举消息类型
{
警觉的
取消
使残废
下载
减
检查
添加
没有一个
}
"@
注意:

  • 如果您只是想通过
    Add Type
    ,基于C代码的按需编译,寻找一个有效的解决方案,请参阅

  • 如果您想了解问题,包括为什么基于
    添加类型的解决方案有帮助,请继续阅读


行为与预期一致

您的
导入模块PSModule-Force
调用
script.ps1
点源
Enums\MessageType.ps1
仅在
script.ps1
的范围内

因此,当运行模块
PSOtherModule
中的
Call Me
时,它对加载到
script.ps1
中的枚举一无所知,因为
PSOtherModule
有自己的作用域(不会从调用方继承)

Call Me
中的
Import Module PSModule-Force
起作用的原因是,您在
PSOtherModule
的上下文中强制重新加载模块,从而点源
Enums\MessageType.ps1
,使
enum
可用(忽略
-Force
将是不可操作的,因为PowerShell已经加载了模块(在全局会话中发生),因此不会再次处理模块清单及其
ScriptsToProcess
条目)

是的,使用
添加类型
和包含按需编译的C代码的字符串可以解决问题
(如中所示),但出于一个不相关的原因:
添加类型
-添加的类型始终是会话全局的
,而不管在什么范围内调用
添加类型

使用PowerShell
enum
(或
class
)定义实现相同的效果,从而解决您的问题,您需要:

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

  • 使用
    使用模块PSModule
    指令而不是
    导入模块PSModule
    cmdlet调用来导入您的模块-仅
    使用模块
    使基于PowerShell的
    枚举
    定义在模块外部可用,然后还可以全局会话


可选背景信息:

  • enum
    class
    定义是PowerShell(v5)最近添加的,它们不是模块导出机制的一部分

    • 在模块之外,
      enum
      class
      定义是它们在/dot中定义的范围的本地定义

    • 如果将
      enum
      class
      定义作为模块(
      *.psm1
      )的一部分,并使用模块
      导入该模块,则这些定义确实变为可用,但始终是所有定义,并且始终是全局会话定义(与添加基于类型的类型一样,尽管它们即使在导入模块时也会这样做)

    • 如果使用
      导入模块
      而不是
      使用模块
      ,则属于模块一部分的
      枚举
      定义实际上是私有的
  • 自Windows PowerShell v5.1/PowerShell Core v6.1.0起,对
    enum
    class
    定义的许多修复和增强都处于挂起状态:

    • 跟踪他们所有人

    • 制作
      导入模块
      参见