PowerShell with a Purpose Blog

Pipeline Parameter Binding: ByPropertyName

In a previous article, I discussed pipeline binding ByValue; this time, I want to look at pipeline binding ByPropertyName. Let's start with the Get-Service cmdlet. If you look at the full help ("Help Get-Service -full"), you'll notice that several parameters accept pipeline input ByPropertyName, including -Name and -ComputerName. Let's play with those two.

The idea here is that the PowerShell pipeline supports the ability to pass objects that are more complex than simple string or numeric values. A simple value is just - well, it's one value, like a name. An object, on the other hand, can have multiple properties that each support a distinct value. The way ByPropertyName works is that you pipe in an object, and any properties of that object attach themselves to parameters that have the same name, and that support ByPropertyName. So, if you pass in an object that has a ComputerName property, that will attach to the -ComputerName parameter.

Start experimenting by making a simple text file named Computers.csv:

win-por9tp458l7,don client
localhost,local machine
win2008r2,domain controller

I've created three lines, and each line has two columns: ComputerName and Description. If we import this with Import-CSV, it'll turn it into three objects, which have ComputerName and Description properties:

Import-CSV Computers.csv

Since these objects have a ComputerName property, we can pipe them to the Get-Service cmdlet, right?

Import-CSV Computers.csv | Get-Service

Oops - that caused an error. The problem here is that the objects created by Import-CSV look a bit like strings, so PowerShell tries to attach them ByValue to the -Name parameter, which gets confused. The trick is to manually specify the -Name parameter, which takes it off the table for pipeline binding, and lets the objects find the -ComputerName parameter:

Import-CSV Computers.csv | Get-Service -Name *

Now let's look at a far more useful example: The ActiveDirectory module that comes with Windows Server 2008 R2. Run this:

Import-Module ActiveDirectory
Help New-ADUser -full

Notice all the parameters that support ByPropertyName? That means you could construct a text CSV file (perhaps using Excel, or exported from Access or another database) that includes columns named Name, SamAccountName, City, Department, and so on. With all of those columns in place, you could create new users as easily as this:

Import-CSV users.csv | New-ADUser

Neat, isn't it? But what if your CSV file is coming from someone else - like HR - and you can't get them to include the SamAccountName column? Let's say they keep naming that column Sam. Pipeline binding won't work that way, because the column name has to exactly match the parameter name. What you need to do is create a new SamAccountName column that contains the same value as the Sam column you were given. You could just edit the CSV file, but that's cheating - let PowerShell do it:

Import-CSV users.csv | Select *,@{"Label"="SamAccountName";Expression={$_.Sam}} | New-ADUser

I've stuck Select-Object in the middle, there, and told it to keep all existing properties from the CSV (that's the * part), and to create a new property with the label SamAccountName. That new property will contain whatever is in the existing Sam column - the $_ part gives me access to the current object, and the .Sam part lets me access just the Sam property of the current object. The Sam property is still there, but since it doesn't match any of the New-ADUser parameter names, it will be safely ignored.
Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.