binary modules vs. script modules

Having built a number of PowerShell modules (both binary and script), there's still an inconsistency between the two models that I cannot quite get my head around. Perhaps one of you could shed some light on this matter.

  • Imagine a function that accepts a single DateTime value. In a script function, I would define this as a [DateTime] parameter; in the C# function the parameter would be of type DateTime . So far, so good.

  • Now imagine passing a DateTime to the function, to which an additional note property has been added using Add-Member . Despite being defined as a [DateTime] , the script function parameter would gladly accept this value, since it's actually a PSObject wrapping the original DateTime (and potentially containing additional members) which is unwrapped upon use - I hope I'm using the correct terminology here. As expected, passing something other than a (wrapped) DateTime would fail, thus making the function more or less type-safe.

  • The equivalent C# function defines the parameter as a DateTime , so AFAIK it has no way to access the additional parameter. After all, the only "interface" that the parameter provides comes from the DateTime type.

  • Alternatively, I could define the C# function's parameter type as a PSObject , but then I would have to do my own type checking for the PSObject 's BaseObject .

  • Is there a flaw in my logic? Or, more importantly, is there a way around this, so that I can still leave my binary module's type checking to PowerShell?

    Many thanks in advance!


    You're both right and wrong - it entirely depends on whether the target parameter is of a value type ( System.DateTime is a struct for example) - in which case everything is lost on type coercion during parameter binding.

    If, however, the parameter type is of a reference type you can "resurrect" the PSObject wrapper using PSObject.AsPSObject() .

    I came up with the following example in pure(-ish) PowerShell for ease of replicability, but I believe it adequately shows my point

    Paste the following into a C# source file (say, TestCmdlets.cs ):

    using System;
    using System.Management.Automation;
    
    namespace TestPSObject
    {
      // This will be our parameter type
      public class TestObject {}
    
      // This will be our reference type test cmdlet
      [Cmdlet(VerbsDiagnostic.Test, "PSObjectByRef")]
      public class TestPSObjectByRefCommand : Cmdlet
      {
        [Parameter(Mandatory=true)]
        public TestObject TestObject
        {
          get { return testObject; }
          set { testObject = value; }
        }
        private TestObject testObject;
    
        protected override void ProcessRecord()
        {
          // If this works, we should receive an object with
          // identical psextended properties
          WriteObject(PSObject.AsPSObject(this.TestObject));
        }
      }
    
      // This will be our value type test cmdlet
      [Cmdlet(VerbsDiagnostic.Test, "PSObjectByValue")]
      public class TestPSObjectByValueCommand : Cmdlet
      {
        [Parameter(Mandatory=true)]
        public DateTime DateTime
        {
          get { return dateTime; }
          set { dateTime = value; }
        }
        private DateTime dateTime;
    
        protected override void ProcessRecord()
        {
          // If this works, we should receive an object with
          // identical psextended properties (hint: we won't)
          WriteObject(PSObject.AsPSObject(this.DateTime));
        }
      }
    }
    

    Now, in your shell, compile and import our test module:

    Add-Type -Path .TestCmdlets.cs -OutputAssembly TestPSObject.dll -OutputType Library
    Import-Module .TestPSObject.dll
    

    Next up we create our test subjects and add a note property to them:

    $TestObject = New-Object TestPSObject.TestObject
    $TestObject |Add-Member -MemberType NoteProperty -Name TestProperty -Value "Hi there!"
    $DateTime = Get-Date
    $DateTime |Add-Member -MemberType NoteProperty -Name TestProperty -Value "Hi there!"
    

    They now both return the string value Hi there! when you dereference the TestProperty member.

    Now for the actual test:

    $TestObjectAfter = Test-PSObjectByRef -TestObject $TestObject
    $DateTimeAfter   = Test-PSObjectByValue -DateTime $DateTime
    

    This will still return Hi there! :

    $TestObjectAfter.TestProperty
    

    But this will not:

    $DateTimeAfter.TestProperty
    
    链接地址: http://www.djcxy.com/p/41218.html

    上一篇: 在日志文件中搜索

    下一篇: 二进制模块与脚本模块