Call the properties/methods on the Piped Object
Asked Answered
C

6

11

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()
Czarevitch answered 19/8, 2016 at 8:19 Comment(0)
J
6

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() }
Juna answered 19/8, 2016 at 8:39 Comment(3)
That's sad. Imagine I am not sure about Reg key or the Folder exists or not. I just keep go on using tab so that I get to place where I want using auto-suggestion and to call something now, all of sudden I have to wrap it from the start can call a method. It's really painCzarevitch
The canonical way would be ForEach-Object. It can be written pretty concise using the alias %: ... | % { $_.method() }Suggest
@martin-brandl , your short answer seems to be absolutely wrong. Please look into ForEach-Object documentation.Lello
E
1

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
Ethical answered 19/8, 2016 at 8:39 Comment(1)
would be also good to have such filter for calling static method such as ` [System.Text.Encoding]::UTF8.GetString ` to make possible something like: ` Invoke-WebRequest $url | select Content | Invoke-Static System.Text.Encoding]::UTF8.GetString ` trying to construct... or asking as separate questionDiscriminator
M
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.

Mozarab answered 6/6, 2018 at 15:47 Comment(0)
L
1

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

Note that if the method takes arguments, they must be supplied as an array (,-separated), but without enclosing them in (...), because syntactically the arguments are being passed in argument mode, which also makes quoting simple string values optional - 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
PS> Get-Item Registry::HKLM\SOFTWARE\Classes\txtfile | % GetValueNames

EditFlags
FriendlyTypeName    

Method call with one argument:

# Perform the equivalent of (Get-Date).ToString('u'); i.e.,
# get a date's universally sortable string representation.
PS> 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.
PS> 'foo' | % Replace f F
Foo
Lamppost answered 19/4, 2019 at 12:33 Comment(0)
L
0

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
Lello answered 25/5, 2020 at 10:37 Comment(0)
L
0

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 value is printed and only 1 property can be passed.

Get-Service | % GetType
Get-Service | % Name
Loftin answered 23/8 at 4:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.