如何在powershell v5模块中导出类

jas*_*son 24 powershell powershell-5.0

我有一个模块设置就像一个其他脚本的库.我无法弄清楚如何在脚本范围调用中获取类声明Import-Module.我试着Export-Module用一个-class参数安排,比如-function,但是没有-class可用的.我只需要在每个脚本中声明该类吗?

设置:

  • 在\\documents\windows\powershell\modules\holidays \中的holidays.psm1
  • 活动脚本调用 import-module holidays
  • holidays.psm1中有另一个函数正确返回一个类对象,但我不知道如何在导入后从活动脚本创建该类的新成员

这是这个类的样子:

Class data_block
{
    $array
    $rows
    $cols
    data_block($a,$r,$c)
    {
        $this.array = $a
        $this.rows = $r
        $this.cols = $c
    }
}
Run Code Online (Sandbox Code Playgroud)

alx*_*x9r 17

using 很容易陷入困境

using关键字是易发生各种缺陷如下:

  • 除非您在语句中指定模块的完整路径,否则该using语句不适用于不在PSModulePath的模块using.这是相当令人惊讶的,因为虽然一个模块可通过Get-Moduleusing声明根据模块的加载方式可能无法正常工作.
  • using语句只能在"脚本"的最开头使用.没有组合[scriptblock]::Create()New-Module似乎克服了这一点.传递给它的字符串Invoke-Expression似乎充当了一种独立的脚本; 一个using在这样的字符串类型的作品的开头声明.也就是说,Invoke-Expression "using module $path"可以成功,但模块内容可用的范围似乎是不可理解的.例如,如果Invoke-Expression "using module $path"在Pester脚本块中使用,则模块内的类不能从相同的Pester脚本块中获得.

以上陈述基于这组测试.

ScriptsToProcess 似乎可靠地工作

调用绑定到包含该类的模块的scriptblock似乎可靠地工作以导出类的实例,并且不会遇到陷阱ScriptsToProcess.考虑这个包含类并已导入的模块:

#  this is like defining c in class.ps1 and referring to it in ScriptsToProcess
class c {
    [string] priv () { return priv }
    [string] pub  () { return pub  }
}

# this is like defining priv and pub in module.psm1 and referring to it in RootModule
New-Module {
    function priv { 'private function' }
    function pub  { 'public function' }
    Export-ModuleMember 'pub'
} | Import-Module

[c]::new().pub()  # succeeds
[c]::new().priv() # fails
Run Code Online (Sandbox Code Playgroud)

ScriptsToProcess在绑定到模块的scriptblock内部调用会生成一个类型为的对象priv:

public function
priv : The term 'priv' is not recognized ...
+         [string] priv () { return priv } ...
Run Code Online (Sandbox Code Playgroud)

  • 很高兴知道,虽然`using module`需要_literal_路径(不允许变量),但它也可以是_relative_路径.此外,有意义的是不要默认使用该名称的任何模块_happens to loaded_. (3认同)

ili*_*ili 17

我找到了一种加载类的方法,而无需"使用模块".在MyModule.psd1文件中使用以下行:

ScriptsToProcess = @('Class.ps1')
Run Code Online (Sandbox Code Playgroud)

然后将您的类放在Class.ps1文件中:

class MyClass {}
Run Code Online (Sandbox Code Playgroud)

更新:虽然您不必在此方法中使用"使用模块MyModule",但您仍需要:

  • 运行"使用模块MyModule"
  • 或者运行"Import-Module MyModule"
  • 或者调用模块中的任何函数(因此它会在途中自动导入模块)

  • 这是公开存储在单个ps1或模块子文件夹中的公共类的好方法.可以用作带外卡的`ScriptsToProcess = @('publicClasses\*.ps1')` (5认同)
  • 它不起作用: `Import-Module : The member 'ScriptsToProcess' in the module manifest is not valid: 无法处理路径,因为它解析为多个文件;一次只能处理一个文件。验证是否在“C:\Stash\MyModule\MyModule.psd1”文件中为此字段指定了有效值。 (3认同)

Lar*_*ens 14

根据此处此处,您可以通过在PowerShell 5中执行以下操作来使用模块中定义的类:

using module holidays
Run Code Online (Sandbox Code Playgroud)

  • “使用”令人惊讶地令人沮丧。我发现除了最微不足道的情况之外,它基本上无法使用。但事实证明,“.NewBoundScriptBlock()”可以很好地导出类的实例。请参阅我的回答[此处](http://stackoverflow.com/a/40441684/1404637)。 (2认同)
  • 危险!危险!为此我无数次用头撞墙。显然,并非所有 5.0 在这方面都是相同的。这在 5.0.10514.6 中不起作用(使用 (Get-Host).Version 检查)。更新您的 WinRM 5.0 副本,它将起作用(5.0.10586.117 起作用)! (2认同)

Ves*_*per 5

你几乎不能。根据about_Classes帮助:

类关键字

定义一个新类。这是真正的 .NET Framework 类型。类成员是公共的,但仅在模块范围内是公共的。您不能将类型名称作为字符串引用(例如,New-Object 不起作用),并且在此版本中,您不能在脚本外部使用类型文字(例如,[MyClass])/定义类的模块文件。

这意味着,如果您想获取一个data_block实例或使用操作这些类的函数,请创建一个函数,New-DataBlock并使其返回一个新data_block实例,然后您可以使用该实例来获取类方法和属性(可能包括静态方法和属性) 。

  • “你几乎不能”:过去确实如此,但在 Powershell 5 中你现在可以了。Lars Tuijens 的回答给出了在导入模块之后添加的额外命令。“在 PowerShell 中使用 using 语句可以从 PowerShell 模块导入 PowerShell 类!” (2认同)

0xG*_*0xG 5

这当然不会按预期工作。
PowerShell 5 的想法是,您可以在扩展名为 .psm1 的单独文件中定义类。
然后您可以使用以下命令加载定义(例如):

using module C:\classes\whatever\path\to\file.psm1
Run Code Online (Sandbox Code Playgroud)

这必须是脚本中的第一行(在注释之后)。

造成如此痛苦的原因是,即使从脚本调用类定义,也会为整个会话加载模块。您可以通过运行看到这一点:

Get-Module
Run Code Online (Sandbox Code Playgroud)

您将看到您加载的文件的名称。无论您再次运行该脚本,它都不会重新加载类定义!(它甚至不会读取 psm1 文件。)这会导致很多人咬牙切齿。

有时 -有时- 您可以在运行脚本之前运行此命令,这将使用刷新的类定义重新加载模块:

Remove-Module  file
Run Code Online (Sandbox Code Playgroud)

其中 file 是不带路径或扩展名的名称。不过,为了保证您的理智,我建议您重新启动 PowerShell 会话。这显然很麻烦;微软需要以某种方式清理这个问题。

  • 我创建此问题是为了解决“using module”语句在对其进行更改后不重新加载模块的问题。请点赞并投票。https://github.com/PowerShell/PowerShell/issues/7654 (2认同)

Jak*_*bii 5

使用的语句是去它是否适合你的方式。否则这似乎也有效。

文件testclass.psm1

使用函数传递类

class abc{
    $testprop = 'It Worked!'
    [int]testMethod($num){return $num * 5}
}

function new-abc(){
    return [abc]::new()
}

Export-ModuleMember -Function new-abc
Run Code Online (Sandbox Code Playgroud)

文件someScript.ps1

class abc{
    $testprop = 'It Worked!'
    [int]testMethod($num){return $num * 5}
}

function new-abc(){
    return [abc]::new()
}

Export-ModuleMember -Function new-abc
Run Code Online (Sandbox Code Playgroud)