4

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 
 }
4
  • Just FYI: Get-Service | Select -Expand Name makes that a lot simpler. If you just want the value of one property from a series of things, Select -Expand is great for expanding the property's value and returning that for each object. Commented Apr 28, 2014 at 20:22
  • To make BatekB's explanation a lot simpler, it is because you didn't pipe to a for-each loop: get-service | % { Write-host $_.Name } will work Commented Apr 28, 2014 at 20:34
  • @Cole9350 - your comments sounds like the best answer to me - why not put it in an answer below, and I'll select it. Commented Apr 29, 2014 at 13:16
  • @Neal I believe bartek covered all the bases and explained it best technically Commented Apr 29, 2014 at 14:51

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow, I never know that you can accept $_ even without Foreach-Object or Where-Object. Sweet.
Sure, my favorite example is with rename-item: ls *.txt | ren -new { $_.Name -replace '\.txt', '.old' } -WhatIf
3

Intellisense will work if you put $_ inside a scriptblock. The following will trigger intellisense:

Get-Service | Foreach-Object {$_.Name} # Intellisense works
Get-Service | Where-Object {$_.Name}   # Intellisense works
Get-Service | Write-Host {$_.Name}     # Intellisense works

Note that your command need not be a valid command: the third example will not work but intellisense will display auto-complete for $_ anyway because it is inside a scriptblock.

I suspect it is because $_ is only usable inside a scriptblock (e.g. switch, %, ?) but I have no hard-evidence for it.

Comments

0

$_ is the current object in the pipeline. It's the same as $item in a foreach ($item in $array).

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

Get-Service | Write-Host $_.name

The difference between these two lines is a fundamental part of the PowerShell design. Pipelines are supposed to be easy. You should be able to ex. search for and delete files as simply as:

Get-ChildItem *.txt | Remove-Item

This is clean, simple, and everyone can use it. The cmdlets are built to identify the type of the incoming object, adapt to support the specific type, and process the object.

However, sometimes you need more advanced object manipulation in the pipeline, and that's where Where-Object and Foreach-Object comes in. Both cmdlets lets you write your own processing logic without having to create an function or cmdlet first. To be able to access the object in your code(processing logic), you need an identifier for it, and that is $_. $_ is also supported in some other special cmdlets, but it's not used in most cmdlets(including Write-Host).

Also, Intellisense in foreach ($item in Get-Service) works. You had a typo.

2 Comments

The first line of this post just doesn't make sense. Also "The cmdlets are built to identify the type of the incoming object, adapt to support the specific type, and process the object." Is not true. Remove-Item accepts pipeline input on the default path parameter which accepts a string, so its just calling the tostring() function of the object. It does not care or know what type it originally was, demonstrated by how fast that line breaks when adding the -recurse parameter
Sorry if I used a bad example, but the idea is still valid. Pipelines(without foreach-/where-object) are supposed to be easy and dynamic. Maybe Remove-Item isn't written to behave differentley depending on the object-type, but the point is that a cmdlet could and should, at least for the objects types that are most likely to be pipelined into it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.