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