Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell function ValueFromPipelineByPropertyName not using alias parameter name

Trying to create a function that takes objects on the pipeline using the alias property. I'm not sure where this is going wrong.

Example of the process:

function Get-Name
{
  Param
  (
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [alias("givenname")]
    [System.String] $FirstName,

    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [alias("sn")]
    [System.String] $LastName
  )
  write-host "firstName = $FirstName / $($FirstName.GetType().FullName)"
  Write-host "LastName  = $LastName  / $($LastName.GetType().FullName)"
}

If I run this command:

Get-Aduser -filter {sn -eq 'smith'} -properties sn,givenname | Get-Name

the output looks like this:

firstName =  / string
LastName  =   / string

The Function never seems to grab the sn and givenname attributes from the passed in object. What am I missing?

like image 853
GLaisne Avatar asked Feb 11 '23 07:02

GLaisne


2 Answers

The AD Cmdlets are to blame here

The problem here is that the AD Cmdlets return objects in really non-standard ways. For instance, with any other cmdlet if you take the output of the command and select a non-existing property, you'll get back nothing, like this:

get-date | select Hamster

Hamster                                                                                                                                                                                                                        
-------     

>

See, nothing. Sure, it says Hamster, but there is no actual Object there. This is standard PowerShell behavior.

Now, look at what Get-ADUser does instead:

get-aduser -Filter {sn -eq 'adkison'} | select Hamster

Hamster                                                                                                                                                                                                                        
-------                                                                                                                                                                                                                        
{}                    

It creates a $null! So what will happen with your function is that PowerShell will look for a property of -LastName or -FirstName, get a $null and then stop right there. It sucks!

The best way around this is to swap the parameter names like this, and it will still work:

function Get-Name
{
  Param
  (
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [alias('FirstName')]
    [System.String] $givenname,

    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [alias("sn","lastname")]
    [System.String] $Surname
  )
  write-host "firstName = $givenname / $($givenname.GetType().FullName)"
  Write-host "LastName  = $SurName  / $($SurName.GetType().FullName)"
}


get-aduser -Filter {sn -eq 'adkison'} | Get-Name

firstName = James / System.String
LastName  = Adkison  / System.String

Want to know more?

Check out this awesome answer from /u/JBSmith on the topic.

like image 55
FoxDeploy Avatar answered Feb 12 '23 22:02

FoxDeploy


From what I've been able to determine, it isn't technically the AD cmdlets that are to blame, but the types in the Microsoft.ActiveDirectory.Management namespace--in this case, ADUser. The properties on ADUser are ultimately all just stored in a private SortedDictionary and fetched through get accessors, which might explain why it doesn't work quite as expected.

As alluded to by Colyn1337 in a previous comment, ADUser doesn't contain a property (or key) named either sn or LastName by default, so you'd need to either include an alias of Surname on your LastName parameter or select sn in your Get-ADUser call:

Get-ADUser -Filter {sn -eq 'Adkison'} -Properties sn | Get-Name

That still won't work, but from there you can just pipe to Select-Object before piping to your function:

Get-ADUser -Filter {sn -eq 'Adkison'} -Properties sn | Select * | Get-Name

Of course, you could also just select the specific properties you need instead of * in Select-Object. I assume this works because it resolves the ADUser dictionary into a PSCustomObject with concrete properties. Once resolved, they will match aliases as well as the actual parameter names.

like image 23
fizzled Avatar answered Feb 12 '23 22:02

fizzled