So, I've been prepping some new materials for thisUSB flash drive training kit that I offer at conferences and classes I teach at, and I constructed a statement like this:
The practical upshot of this is to retrieve all the domain controllers from the domain, and then remap their "Name" property to be a "ComputerName" property. Why? Well, because cmdlets like Invoke-Command can bind pipeline input ByPropertyName, meaning that - I thought - if I piped in objects having a ComputerName property, they'd attach themselves to the cmdlet's -computerName parameter. So this:
Would invoke the Get-Service command on every domain controller in the domain. Or at least, it would in my perfect little world. As-is, it spit out a bunch of errors.
Well, turns out there's a trick to parameter binding that you should be aware of. True, Invoke-Command does bind pipeline input to -computerName ByPropertyName - so as far as it goes, my theory was right. But it also binds the -inputObject parameter ByValue, accepting a value of Object. The -inputObject parameter accepts stuff that you want passed into whatever command/script you're executing.
In plain English? My computer objects were being piped to Invoke-Command, but because ByValue binding happens first, my objects were being snatched up by -inputObject and being sent to that Get-Service cmdlet as its pipeline input. Get-Service didn't really know what to do with them, so it all exploded on me. Rats.
So I'm still wrapping my head around these facts:
- ByValue parameter binding always happens before ByPropertyName binding.
- -inputObject binds pipeline input ByValue, accepting anything of the Object type.
- All objects derive from the Object type, so -inputObject will bind anything.
So it seems as if -inputObject will always grab whatever you pipe to Invoke-Command. Now, here's the trick: Provided those objects can be safely used by whatever command you're invoking, those objects can also contain other miscellaneous properties that will bind, ByPropertyName, to Invoke-Command's parameters. For example, Get-Service will bind a Name property. So if I piped in an object having both a Name property and a ComputerName property, then something seems to work:
This still weirds be out a little. It seems to negate the value of having Invoke-Command's -computerName parameter bind input at all, since anything piped in will bind to -inputObject first. But surely someone thought of that, so it's obviously something I'm missing.
Needless to say, I'm tabling this particular example for right now until I can wrap my head around it. I have e-mails out to some of the other PowerShell MVPs, so we'll see what they say. I'm interested in your input, too - what am I missing? How can I successfully use pipeline binding with the -computerName parameter of Invoke-Command? Drop a comment if you know the trick - and if I discover it, I'll be sure to follow-up.