How can I use a PSCustomObject ScriptMethod on the pipeline

PSVersion: 5.1


Desired

What I wished would work
$obj = [PSCustomObject]@{
   PSTypeName = 'MyObject'
   con        = 'local'
}
add-member -MemberType ScriptMethod -InputObject $obj -Name MyMethod -Value {
   param([parameter(ValueFromPipeline=$true)]$x)
   begin  {write-host 'begin'}
   process{write-host "$($this.con): $x"}
   end    {write-host 'end'}
}
1..5 | $obj.MyMethod

To give

begin
local: 1
local: 2
local: 3
local: 4
local: 5
end

but gives error

At line:1 char:8
+ 1..5 | $obj.MyMethod
+        ~~~~~~~~~~~~~
Expressions are only allowed as the first element of a pipeline.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ExpressionsMustBeFirstInPipeline

Tried

what doesn't work because: idk, tl;dr reasons?
1..5 | %{$obj.MyMethod($_)}

what doesn't work because: begin/end

$obj = [PSCustomObject]@{
   PSTypeName = 'MyObject'
   con        = 'local'
}
add-member -MemberType ScriptMethod -InputObject $obj -Name MyMethod -Value {
   param($x)
   write-host "$($this.con): $x"
}
1..5 | %{$obj.MyMethod($_)}

what doesn't work because: $this is no longer attached

$obj = [PSCustomObject]@{
   PSTypeName = 'MyObject'
   con        = 'local'
   MyMethodSB  = {
      param()
      begin  {write-host 'begin'}
      process{write-host "$($obj.con): $_"}
      end    {write-host 'end'}
   }
}
1..5 | &$obj.MyMethodSB

what doesn't work because: idk, maybe the scope of Stepper dies prematurely

$obj = [PSCustomObject]@{
   PSTypeName = 'MyObject'
   con        = 'local'
   Stepper    = $null
}
add-member -MemberType ScriptMethod -InputObject $obj -Name MyMethod -Value {
   param($x)
   if($null -eq $this.Stepper){
      $t = $this
      $sb = {
         param($o)
         begin  {write-host 'begin'}
         process{write-host "$($o.con): $_"}
         end    {write-host 'end'}
      }
      $this.Stepper = {&$sb $t}.GetSteppablePipeline()
      $this.Stepper.Begin($true)
   }
   $this.Stepper.Process($x)
}
1..5 | %{$obj.MyMethod($_)} 
$obj.Stepper.End()
$obj.Stepper = $null

Almost There

What is kinda working
$Data = @{
   ItemNo1 = @(
      @{loc = 'WH';  qty = 20}
      @{loc = 'DK';  qty = 0}
      @{loc = 'ST1'; qty = 3}
      @{loc = 'ST2'; qty = 2}
   )
   ItemNo2 = @(
      @{loc = 'WH'; qty = 6}
      @{loc = 'DK'; qty = 0}
   )
   ItemNo3 = @(
      @{loc = 'WH'; qty = 100}
      @{loc = 'ST1'; qty = 5}
      @{loc = 'DK'; qty = 0}
   )
   ItemNo4 = @(
      @{loc = 'WH'; qty = 0}
      @{loc = 'DK'; qty = 0}
      @{loc = 'ST2'; qty = 15}
   )
   ItemNo5 = @(
      @{loc = 'WH'; qty = 0}
      @{loc = 'DK'; qty = 15}
   )
}
$QueryParameter = [PSCustomObject]@{Value = $null}
function MockDataQuery{
   $Item = $QueryParameter.Value
   foreach($iDat in $Data.$Item){
      "   $Item;$($iDat.loc);$($iDat.qty)"
   }
}
$InvObj = [PSCustomObject]@{
   PSTypeName = 'Data.Connection'
   con        = 'item.inventory'
}
add-member -MemberType ScriptMethod -InputObject $InvObj -Name FetchItemData -Value {
   $p = $this
   $qPipe = [PSCustomObject]@{
      PSTypeName = 'Data.Connection.QueryPipe'
      parent  = $p
      qHeader = 'Item;Location;Quantity'
      query   = 'select * from inventory where item = ?'
      param   = $null
   }
   add-member -MemberType ScriptMethod -InputObject $qPipe -Name begin   -Value {
      param([bool]$Header=$true)
      write-host "connect to: $($this.parent.con)"
      write-host "compile command: $($this.query)"
      $this.param = $QueryParameter
      write-host 'begin transaction'
      if($Header){
         write-host "   $($this.qHeader)"
      }
   }
   add-member -MemberType ScriptMethod -InputObject $qPipe -Name process -Value {
      param($itm)
      $this.param.Value = $itm
      MockDataQuery | write-host
   }
   add-member -MemberType ScriptMethod -InputObject $qPipe -Name end     -Value {
      write-host 'end transaction'
      write-host 'dispose command'
      write-host 'close connection'
   }
   return $qPipe
}
1..5 | %{"ItemNo$_"} | &{
   begin  {$stp = $InvObj.FetchItemData();$stp.begin()}
   process{$stp.process($_)}
   end    {$stp.end()}
}

While this seems to be a functional model, it would be better if there was a solution that didn't require the user of the connection object to have to code the begin/process/end script on their end every time they use the object's method.



Read more here: https://stackoverflow.com/questions/66162105/how-can-i-use-a-pscustomobject-scriptmethod-on-the-pipeline

Content Attribution

This content was originally published by Gregor y at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: