RaceBase
RaceBase

Reputation: 18848

Call the properties/methods on the Piped Object

I am trying to understand how to pipe | an object and call the properties or methods on that.

Ex:
$a = Get-Item Registry::HKLM\SOFTWARE\WOW6432Node\Microsoft\Test\abc\
$a.GetSomething()  //calls the method
(Get-Item Registry::HKLM\SOFTWARE\WOW6432Node\Microsoft\Test\abc\).GetSomething() //calls the method

Can I pipe the output of the Get-Item and invoke properties/methods on it?

Get-Item Registry::HKLM\SOFTWARE\WOW6432Node\Microsoft\Test\abc\ | call GetSomething()

Upvotes: 12

Views: 7655

Answers (7)

mklement0
mklement0

Reputation: 439477

Ansgar Wiechers has provided the crucial pointer in a comment on Martin Brandl's answer:

The canonical way would be ForEach-Object. It can be written pretty concisely using the alias %:
... | % { $_.GetSomething() }

In PowerShell version 3 or higher, you an make the call even more concise with simplified syntax, which obviates the need for enclosing the call in { ... }, having to explicitly refer to $_, and needing to use parentheses ((...)):

... | % GetSomething  # short for: ... | ForEach-Object GetSomething

If the method (overload) being called has more than one parameter, pass arguments to them individually[1] - see examples below.

Examples:

Method call without arguments:

# Perform the equivalent of:
# (Get-Item Registry::HKLM\SOFTWARE\Classes\txtfile).GetValueNames()     
# That is, get the names of the values defined on registry key 
# HKEY_LOCAL_MACHINE\SOFTWARE\Classes\txtfile
Get-Item Registry::HKLM\SOFTWARE\Classes\.txt | % GetValueNames
# -> @('Content Type', 'PerceivedType')    

Method call with one argument:

# Perform the equivalent of (Get-Date).ToString('u'); i.e.,
# get a date's universally sortable string representation.
Get-Date | % ToString u  # "u" may be quoted, but doesn't need to be.
# -> '2019-04-19 08:22:22Z'

Method call with multiple arguments:

# Perform the equivalent of 'foo'.Replace('f', 'F'); i.e.,
# replace all lowercase Fs with uppercase ones.

# Note how the arguments are passed *individually*.
'foo' | % Replace f F
# -> 'Foo'

[1] You can alternatively use an array, (,-separated arguments), but in Windows PowerShell that requires explicit use of the -ArgumentList parameter name, which is awkward (no longer needed in PowerShell (Core) 7).

Upvotes: 3

js2010
js2010

Reputation: 27516

Foreach-object example with an argument, getting the type of a value under the key (REG_EXPAND_SZ) with the GetValueKind() method:

Get-Item HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion | 
  % GetValueKind DevicePath

ExpandString

Upvotes: -1

hanzo765
hanzo765

Reputation: 104

Use % followed by the method name.

Get-Item Registry::HKLM\SOFTWARE\WOW6432Node\Microsoft\Test\abc\ | % GetSomething

You can use it on properties as well. It behaves like select -expand. Only the value will be printed and only 1 property can be passed.

Get-Service | % GetType
Get-Service | % Name

Upvotes: -1

Martin Brandl
Martin Brandl

Reputation: 58991

The short answer is no. You can't call a method like this using Pipeline. But you can surround your Get-Item invoke in parentheses and invoke it:

(Get-Item Registry::HKLM\SOFTWARE\WOW6432Node\Microsoft\Test\abc\).GetSomething()

If you don't want that, you could abuse the Select-Object cmdlet:

Get-Item Registry::HKLM\SOFTWARE\WOW6432Node\Microsoft\Test\abc\  | select { $_.GetSomething() }

Upvotes: 5

Distagon
Distagon

Reputation: 1075

This requirement in most cases says that the task can be accomplished in a simpler way.

However, if it is really needed, you can use the MemberName parameter of the ForEach-Object cmdlet:

# declare something
$o = @{
    One   = 1
    Two   = 2
    Three = 6
}

# do something
$o |
    ForEach-Object -MemberName "GetEnumerator" |
    ForEach-Object { "$($_.Key): $($_.Value)" } |
    Write-Host

Upvotes: 0

Andrew
Andrew

Reputation: 1

A nicer method in my opinion would be to use e.g.:

Get-Item Registry::HKLM | % { $_ }:

where % is ForEach-Object (which is fine to use, even if you only have 1) and $_ is each object.

Upvotes: 2

Chris Dent
Chris Dent

Reputation: 4250

It's not possible without writing something to make it so. That something would be pretty confusing.

Like this.

filter Invoke-Method {
    param(
        [String]$Method,

        [Object[]]$ArgumentList
    )

    $_.GetType().InvokeMember(
        $Method.Trim(),
        ([System.Reflection.BindingFlags]'InvokeMethod'),
        $null,
        $_,
        $ArgumentList
   )
}
"qwerty" | Invoke-Method Replace 'q', 'z'

Properties are easier in that there's already a command to do that:

(...).GetSomething() | Select-Object Property1, Property2

Upvotes: 1

Related Questions