【问题标题】:Powershell module initializationPowershell 模块初始化
【发布时间】:2013-07-12 23:22:35
【问题描述】:

加载模块时,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 成为与第一个 sn-p 提供的对象相同的句柄。

建议表示赞赏。

【问题讨论】:

    标签: powershell module


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 您是否有指向文档的链接,以确认“导入模块时执行未嵌入函数的模块中的任何代码。”我相信这是半真半假:用 PowerShell 编写的模块以这种方式工作,用 C# 编写的模块似乎没有办法做到这一点(除非您编辑 CIL 并添加 .ModuleInit,例如使用 Fody 构建后处理程序,因为ModuleInit 不符合通用语言规范)。
    【解决方案2】:

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

    #test.psm1
    $script:myvar = "hi"
    function Show-MyVar {Write-Host $script:myvar}
    function Set-MyVar ($Value) {$script:myvar = $Value}
    #end test.psm1
    

    【讨论】:

      【解决方案3】:

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

      但我认为您真正想要做的是使用 Powershell 5 中现在可用的类(当您发布时它们不是)。我已经提供了每个示例。 Sysops 有一个 decent tutorial 的新课程,分为 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())"
      

      【讨论】:

        猜你喜欢
        • 2018-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-06
        • 2013-09-03
        • 2011-02-14
        • 2012-02-27
        • 2023-03-12
        相关资源
        最近更新 更多