6

加载模块时,PowerShell 会调用任何初始化代码吗?

我正在寻找类似 Perl BEGIN 块或构造函数的东西。

NEW-MODULE 和 IMPORT-MODULE 都将返回一个 PSCustomObject。我正在尝试将自定义对象封装在模块中,以避免脚本中出现冗长的代码。在开放代码中测试良好的一种方法是:

$m = new-module -scriptblock {
New-Object PSCustomObject | 
    Add-Member NoteProperty -name person -value Frodo -passthru | 
    Add-Member ScriptMethod Who { $this.person }  -passthru |
    Add-Member ScriptMethod Mod { 
        param($x)
        $this.person = $x
        } -passthru
} -ascustomobject -returnresult

理想情况下,我想将此代码放入模块中并使用以下内容:

$MyObj = Import-Module -Name ".\MyPackage" -AsCustomObject

并让 MyObj 成为与第一个片段提供的对象相同的句柄。

建议表示赞赏。

4

3 回答 3

5

目前尚不清楚您是要在加载模块时运行初始化代码(如 Perl 的 BEGIN 块)还是要创建自定义类(这是“构造函数”所建议的)。

模块中的初始化代码很容易。导入模块时,将执行模块中未嵌入函数的任何代码。

PS 本机不支持创建自定义类。但请参阅: http: //psclass.codeplex.com/。也可以编写C#、VBScript等并使用Add-Type。

Import-module 无法模拟类,因为您只能拥有一个具有给定名称的模块实例 - 充其量您将拥有一个单例类。(顺便说一句,import-module 确实有一个 -passthru 参数,它或多或少会让你的最后一行代码工作 - 作为一个单例。你还必须添加export-module -variable * -function *到你的模块代码中)你可以使用 New-Module 来模拟不过一堂课。例如,您可以将其包装在一个名为的函数new-myClass中。

顺便说一句,如果您使用 -ASCustomObject 参数,您最终会得到一个不支持“this”的哈希表(换句话说,作为脚本块的哈希表值没有内置方式来引用哈希表本身) . 如果您使用没有 -AsCustomObject 的 new-module(并且可能使用工厂函数,例如 new-myclass),那么您可以使用& $myModule $varInMyModule. 但是,如果您使用 Add-Member 创建 PSCustomObject,则脚本方法可以访问 $this,并且它通常更像具有属性和方法的典型对象。

于 2013-07-14T01:50:27.550 回答
2

模块确实应该输出 cmdlet,而不是对象。一个模块应该提供一组相关的 cmdlet。有一种方法可以使用Import-Modules's-ArgumentList参数将数据发送到模块中,如下所示。例如,您可以使用该技术为要连接的 cmdlet 提供服务器名称。PowerCLI 模块使用 cmdlet 以不同方式处理该问题,该 cmdlet 创建脚本范围连接对象 ( $script:connection),其他 cmdlet 检查并在其存在时重新使用,类似于以下内容:

#test.psm1
$script:myvar = "hi"
function Show-MyVar {Write-Host $script:myvar}
function Set-MyVar ($Value) {$script:myvar = $Value}
#end test.psm1
于 2013-07-13T02:14:19.460 回答
0

使用模块,您可以导出固有属性和函数,并且不需要通过 add-member 运行它们或做很多杂技。但是请注意,如果您不想导出所有属性和方法,则会出现一些问题,并且虽然您可以将属性初始化为初始值,但您不能在初始化过程中调用内部函数,而无需进行一些笨拙的杂技。

但我认为你真正想做的是使用 Powershell 5 中现在可用的类(当你发布时它们不是)。我已经提供了每个示例。Sysops 有一个关于新课程的不错的教程,分为 4 个部分

这是powershell 5.0之前的旧方式

# powershell 3.0 and above (I think)
$m = new-module -ascustomobject -scriptblock `
    {
    $person = "Frodo"
    function Who
        ()
        {return $this.person}
    function Rename
        ($name)
        {$this.person = $name}
    Export-ModuleMember -Function * -Variable *
    }

write-host "direct property access: $($m.person)"
write-host "method call: $($m.who())"
$m.Rename("Shelob")
write-host "change test: $($m.who())"

您还可以从这样的模板复制多个对象:

# powershell 3.0 and above (I think)
$template = `
    {
    $person = "Frodo"
    function Who
        ()
        {return $this.person}
    function Rename
        ($name)
        {$this.person = $name}
    Export-ModuleMember -Function * -Variable *
    }

$me = new-module -ascustomobject -scriptblock $template; $me.Rename("Shelob")
$you = new-module -ascustomobject -scriptblock $template

"Me: $($me.Who())"
"You: $($you.Who())"

在 powershell 5 中你有实际的类(大部分)

#requires -version 5
Class Person
    {
    hidden [String] $name #not actually private

    [string] Who ()
        {return $this.name}

    [void] Rename ([string] $name)
        {$this.name = $name}

    # constructors are weird though, you don't specify return type OR explicitly return value.
    Person ([String]$name)
        {$this.name = $name}
    <#
    # The above constructor code is secretly converted to this
    [Person] New ([string]$name) #note the added return type and renamed to New
        {
        $this.name = $name
        return $this #note that we are returning ourself, you can exploit this to create chained constructors like [person]::New("gandalf").withWizardLevel("White") but I haven't done so here
        }
    #>

    }
$me = [Person]::new("Shelob")
$you = [Person]::new("Frodo")

# $me|gm        # Note that Name doesn't show here
# $me.name      # But we can still access it...
# $me|gm -Force # Note that Name DOES show here

"`n"
"Me: $($me.who())"
"You: $($you.who())"
$you.Rename("Dinner")
"You after we meet: $($you.who())"
于 2019-05-29T17:02:29.880 回答