Parameter alias not working in pipeline

Hello,

I´m fairly new to scripting/programming in general (including Powershell), trying to move away from being a GUI-based technician. While doing my best to get my first cmdlets to work I came across an unexpected behavior, I hope someone can give me an explanation for this. I made two nearly identical functions to illustrate my problem:

 function Test-Name
{    
    Param
    (
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true)]
        [Alias("Name")] 
        $ComputerName
    )

    $ComputerName
}

function Test-Name2
{    
    Param
    (
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true)]
        [Alias("ComputerName")] 
        $Name
    )

    $Name
}  

And then I tested a few things:

PS U:> Get-ADComputer Test | Test-Name
Test-Name : Cannot bind argument to parameter ‘ComputerName’ because it is null.
At line:1 char:23

  • Get-ADComputer Test | Test-Name
  •                   ~~~~~~~~~
    
    • CategoryInfo : InvalidData: (CN=Test,CN=Computers,DC=test,DC=ing:PSObject) [Test-Name], ParameterBindingValidationException
    • FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Test-Name

PS U:> Get-ADComputer Test | Select-Object Name | Test-Name
Test

PS U:> Get-ADComputer Test | Test-Name2
Test

PS U:> (Get-ADComputer Test).gettype()

IsPublic IsSerial Name BaseType


True False ADComputer Microsoft.ActiveDirectory.Management.ADAccount

PS U:> (Get-ADComputer Test | Select-Object *).gettype()

IsPublic IsSerial Name BaseType


True False PSCustomObject System.Object

I red in a post, that I unfortunately can´t find right now, that objects from ActiveDirectory module cmdlets acts weird in the pipeline and that using Select-Object was a way around it. I can see that the object types are different, but why does it work when the parameter name match the property name from the pipeline?

Meet the ActiveDirectory module, one of the most annoying things ever produced for PowerShell. :slight_smile: The objects that come out of those commands behave very oddly. As you mentioned, piping the AD commands to “Select-Object *” first is a viable workaround, because it changes the type of the objects that you’re piping into other functions.

The reason for this is that the AD objects, when you try to read any property, will automatically create a property on themselves of that name with no value. (They’re essentially both an object and a hashtable, in terms of their interface). When you pipe in an object to your function with an aliased parameter, this is what would normally happen:

  • PowerShell checks the object for a property matching the actual parameter name “ComputerName”
  • That’s not found, so instead it starts checking the aliases. It finds a property “Name”, and binds that.

But when you’re using these goofy AD objects, instead it goes like this:

  • PowerShell checks the object for a property of type ComputerName. It didn’t exist before this happened, but now suddenly the object has a “ComputerName” property with no value. PowerShell binds this to your parameter, and never bothers checking the aliases.

Thank you for your time and thorough explanation, my mind is at ease once again :slight_smile: