Search code examples
powershellpipescriptblock

Piping into a ScriptBlock


I'm trying to find some way of flexibly altering/substituting pipeline elements in PowerShell:

Function Where-DirectlyReportsTo {
    Param (
        [Parameter(
            ValueFromPipeline = $true,
            HelpMessage = "The ADUser object to be tested"
        )]
        [Microsoft.ActiveDirectory.Management.ADUser] $ADUser,
        [Parameter( 
            Mandatory = $true,
            ValueFromPipeline = $false,
            Position = 0
        )]
        [String] $mgrDN
    )
    Process {
        If ($ADUser) {
            If ($ADUser.Manager -eq $mgrDN) { Return $ADUser }
        }
    }
}

$Properties = @("Manager")
$users = Get-ADUser -Filter * -SearchBase $OU -Properties $Properties
[ScriptBlock] $sb = {Where-DirectlyReportsTo "CN=Colonel Foobar,$OU"}
$DNs = $users | $sb | %{$_.DistinguishedName}

Which I want to return the DNs of all the users that report to Colonel Foobar, but it gives me the error Expressions are only allowed as the first element of a pipeline.

This is a trivial example, but I'd ultimately like to be able to put the pipeline step inside a loop and pass it different ScriptBlocks to get different sets of users, or use more complicated ScriptBlocks (e.g.: {Where-IsEmployee | Where-IsInDepartment "Finance" | Where-LikesIceCream}).

I realize that I may be going about this all wrong, and I would very much appreciate being pointed in the right direction.

EDIT: To clarify, here's a rough outline of what I'd like to accomplish:

[ScriptBlock[]] $arrBlocks = @( # lots of different cases
)
ForEach ($sb In $arrBlocks) {
    $DNs = $users | $sb | %{$_.DistinguishedName}
    # Then do something with the DNs
}

Realistically, this will probably involve a hash table instead of an array, so that I know what to do with each set of results.


Solution

  • There needs to be something at the head of the pipeline in your scriptblock and you have to define your scriptblock as taking pipeline input.g.:

    [scriptBlock]$sb = {[CmdletBinding()]param([Parameter(ValueFromPipeline=$true)]$obj) `
                       process {
                           foreach ($o in $obj) {
                               $o | Where-DirectlyReportsTo "CN=Colonel Foobar,$OU"}}}
    

    You also can't throw $sb into the pipeline quite like that, try this:

    $users | &$sb | %{$_.DistinguishedName}