Parameter type validation in functions - binary modules vs. script modules Parameter type validation in functions - binary modules vs. script modules powershell powershell

Parameter type validation in functions - binary modules vs. script modules


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 LibraryImport-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