3

In PowerShell, you can pipe into Cmdlets and into scripted functions. But is it possible to pipe into objects, properties, or member functions?

For example, if I have a database connection object $dbCon, I want to be able to so something like this:

$dbCon.GetSomeRecords() | <code-to-manipulate-those-records | $dbCon.WriteBackRecords()

I know the same functionality can be achieved with Foreach-Object or with a Cmdlet that gets the object as an argument - the reason I want to pipe directly to the object or to it's members is to achieve elegance and to keep the OOP style(using an object's method instead of sending the object as an argument)

Is it possible?


EDIT:

It looks like people don't understand my question, so I need to clarify it:

PowerShell can pipe to normal functions. I can Write:

function ScriptedFunction
{
    $input|foreach{"Got "+$_}
}
1,2,3|ScriptedFunction

And get
Got 1
Got 2
Got 3

As the result. But when I try to use that technique with a scripted method:

$object=New-Object System.Object
$object|Add-Member -MemberType ScriptMethod -Name ScriptedMethod -Value {$input|foreach{"Got "+$_}}
1,2,3|$object.ScriptedMethod

I get an error message: Expressions are only allowed as the first element of a pipeline.(adding () does not help BTW). What I'm looking for is a way to make that command work the same way it works with global functions.

Idan Arye
  • 12,402
  • 5
  • 49
  • 68

2 Answers2

3

This is not exactly what you are asking for but this has almost the same syntax: use a NoteProperty instead of a ScriptedMethod and call it using operators . or &:

$object = New-Object System.Object
$object | Add-Member -MemberType NoteProperty -Name Script -Value {$input|foreach{"Got "+$_}}
1,2,3 | & $object.Script

Output

Got 1
Got 2
Got 3

BUT: There is a caveat, perhaps a show stopper: this is not a script method at all, there will be no $this defined by the core for it (you can define $this = $object before invocation yourself but this is rather ugly, to send $object as a parameter would be better).

Roman Kuzmin
  • 40,627
  • 11
  • 95
  • 117
  • That's a pretty big "but" - the main reason I want to pipe into object is so I could use their state in their piping. Maybe if I used the `NoteProperty` as a wrapper I could do a little hack: store the object in some global dictionary, make the NoteProperty's command fetch the object using it's key(which, being just text, can be stored in the NoteProperty) and pass it to the real function together with the input. Then I could hide everything behind some automation or something. Still, I would prefer a less hacky approach... – Idan Arye Oct 03 '11 at 16:21
  • 1
    Yes, it is a big "but". But it looks like you have to choose between "buts"... so that the more "buts" you have to choose from the better :) – Roman Kuzmin Oct 03 '11 at 16:28
0

If I'm following, you can attach new script methods to exiting objects with the Add-Member cmdlet (take a look at Example code #4 in help). You can also add them in a Type file (xml) and load the file with the Update-TypeData cmdlet so they become available automatically when you have certain type of objects in hand.

UPDATE

You cannot pipe to methods. Methods you add are avaiable on the objects:

function ScriptedFunction
{
    process
    {
        $object = $_
        $object = $object | Add-Member -MemberType ScriptMethod -Name Increment -Value {$this+1} -PassThru -Force
        $object
    }
}

$newObjects = 1,2,3 | ScriptedFunction 
# increment the first object, its value is one, when the 
# Incereent method is invoked you get 2
$newObjects[0].Increment() 

2
Shay Levy
  • 121,444
  • 32
  • 184
  • 206