Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of property names in PowerShell pipeline $_ variable

Tags:

powershell

As a C# developer, I'm still learning the basics of PowerShell and often getting confused. Why does the $_. give me the intellisense list of vaild property names in the first example, but not the second?

Get-Service | Where {$_.name -Match "host" } 

Get-Service | Write-Host $_.name

What is the basic difference in these two examples?

When I run the second one, it gives this error on each iteration of Get-Service:

Write-Host : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters 
that take pipeline input.
At line:3 char:15
+ Get-Service | Write-Host $_.name
+               ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (wuauserv:PSObject) [Write-Host], ParameterBindingException
    + FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Commands.WriteHostCommand

My coworker and I were first using a foreach loop to iterate a Get-commandlet, and we were stuck getting the property names to appear. We tried to simplify till we go to the core basics above.

Just figured out sometimes it's a typo in the commandlet, below first one fails because the commandlet should be Get-Service instead of Get-Services.

foreach ($item in Get-Services) 
 {
    Write-Host $item.xxx  #why no intellisense here? 
 }


foreach ($item in Get-Service) 
 {
    Write-Host $item.Name 
 }
like image 206
NealWalters Avatar asked Mar 19 '23 18:03

NealWalters


1 Answers

First part: you can't use $_ like that, it represents current pipeline object only within script blocks. These script blocks are usually used with any *-Object cmdlet (but there are other use cases too). Not all parameters/ cmdlet support it. Write-Host is one of those that don't.

Second: It looks like you are using own function (GetServices). PowerShell v3 intellisense is depending on command metadata (OutputType). If any cmdlet/ function produces object but is silent about OutputType, intellisense won't work. It's pretty simple to get it, and you can lie and still get proper intellisense for any existing type:

function Get-ServiceEx {
[OutputType('System.ServiceProcess.ServiceController')]
param ()
    'This is not really a service!'
}

(Get-ServiceEx).<list of properties of ServiceController object>

You can read more about it on my blog.

like image 141
BartekB Avatar answered Apr 02 '23 09:04

BartekB