4

What works -

Lets say I have a scriptblock which I use with Select-Object cmdlet.

$jobTypeSelector = `
    {
        if ($_.Type -eq "Foo")
        {
            "Bar"
        }
        elseif ($_.Data -match "-Action ([a-zA-Z]+)")
        {
            $_.Type + " [" + $Matches[1] + "]"
        }
        else
        {
            $_.Type
        }
    }

$projectedData = $AllJobs | Select-Object -Property State, @{Name="Type"; Expression=$jobTypeSelector}

This works fine, and I get the results as expected.

What I am trying to do -

However, at a later point in code, I want to reuse the scriptblock defined as $jobTypeSelector.

For example, I expected below code to take $fooJob (note that it is a single object) passed as parameter below, and be used for $_ automatic variable in the scriptblock and return me the same result, as it returns when executed in context of Select-Object cmdlet.

$fooType = $jobTypeSelector.Invoke($fooJob)

What doesn't work -

It does not work as I expected and I get back empty value.

What I have already tried -

  1. I checked, the properties are all correctly set, and it's not due to the relevant property itself being blank or $null.

  2. I looked on the internet, and it's seemed pretty hard to find any relevant page on the subject, but I eventually found one which was close to explaining the issue in a slightly different context - calling the script blocks in PowerShell. The blog doesn't directly answer my question, and any relevant explanation only leads to a solution which would be very ugly, hard to read and maintain in my opinion.

Question -

So, what is the best way to invoke a scriptblock for a single object, which uses $_ automatic variable as parameter, (instead of param block)

Vikas Gupta
  • 4,455
  • 1
  • 20
  • 40

2 Answers2

5

After fiddling around with varoius options, I ended up sloving the problem, in a sort of Hackish way.. But I find it to be the best solution because it's small, easy to read, maintain and understand.

Even though we are talking about single object, use it in the pipeline (which is when PowerShell defines the $_ automatic variable) with ForEach-Object cmdlet

$fooType = $fooJob | ForEach-Object $jobTypeSelector
Vikas Gupta
  • 4,455
  • 1
  • 20
  • 40
2

You can certainly use foreach or ForEach-Object as you mention.

You can also pipe to the ScriptBlock directly, if you change it from a function ScriptBlock to a filter ScriptBlock by setting IsFilter to $true:

$jobTypeSelector.IsFilter = $true

$fooType = $fooJob | $jobTypeSelector

But, what would be even better is if you used a named function instead of an anonymous ScriptBlock, for example:

function Get-JobType
{
    Param ( 
        [object] $Job 
    )

    if ($Job.Type -eq "Foo")
    {
        "Bar"
    }
    elseif ($Job.Data -match "-Action ([a-zA-Z]+)")
    {
        $Job.Type + " [" + $Matches[1] + "]"
    }
    else
    {
        $Job.Type
    }
}

Then you can use it with Select-Object aka select like this:

$projectedData = $AllJobs |
    select -Property State, @{Name="Type"; Expression={Get-JobType $_}}

Or with a single job, like this:

$fooType = Get-JobType $fooJob
Sam Porch
  • 751
  • 5
  • 12
  • 5
    Thank you for your response.. I understand that this could be a function.. but about the other option you mentioned.. Setting `IsFilter` to `$true`.. I get following error - `Exception setting "IsFilter": "Operation is not valid due to the current state of the object."`. Any idea why? and how to set it..? Documentation and example seems to be very poor on this property.. and I couldn't find any way to create a scriptblock initialized with this state. – Vikas Gupta May 22 '15 at 03:03