简体   繁体   中英

Powershell filter for only unique entries in array from pipeline within custom module

This is a tangent/continuation from my other question where I need to sanitize the input to one of my custom modules. Here's the code:

function Get-MyTest {

    param(
        [string[]]$MyInput
    )


    [array]$Output = @()
    $i=0

    foreach($Item in $MyInput){

        $i++

        $Output += [pscustomobject]@{
            Name = $Item
            Id = $i
        }

    }

    return $Output

}

function Get-IncorrectResults {

    param(
        [parameter(ValueFromPipeline)][array]$MyIncorrectInput
    )

    process {
    
        foreach ($Item in $MyIncorrectInput) {
        
            Write-Host "Current object: $Item `n "

        }

    }

}

Problem
Adding begin{} , process{} , and end{} allows me to individually process each entry in the pipeline, but I can no longer filter the input. A user could end up with several identical objects in the $MyIncorrectInput , for example by doing:

[array]$TestVariable = @()
$TestVariable += Get-MyTest "Test1","Test2"
$TestVariable += Get-MyTest "Test3","Test2"

This would end up with two identical entries for Test2. If I then run either of the following:

Get-IncorrectResults -MyIncorrectInput $TestVariable
$TestVariable | Get-IncorrectResults

Then the Test2 object will be processed twice. Since the goal here is to use this in GET/POST/PUT/DELETE requests for a RESTAPI then I can't have the code process the same entry (or ID) twice for DELETE since the resource has already been deleted. I therefore need to filter out to only process unique values.

Attempted solution
I tried to change the foreach loop to use $item in $UniqueInput instead, and add the following code:

$UniqueInput = $MyIncorrectInput | Get-Unique -AsString

If I add it in the process{} block it doesn't do anything, it still processes every entry including duplicates. If I add it in the begin{} block well then the value doesn't seem to carry over to the process{} block and the Write-Host section is empty because $UniqueInput seems to be empty.

Even changing to the following has no effect:

$UniqueInput = $MyIncorrectInput | Select-Object * -Unique

What is the correct way to filter an array input for only unique values in a custom module that needs to take the array from the pipeline? I don't need to have the full PSCustomObject be unique, it would be enough to have the .Id unique if that makes any difference.

You can do this with a HashSet<T> , this class is designed to contain only unique elements:

function Get-IncorrectResults {
    param(
        [parameter(Mandatory, ValueFromPipeline)]
        [array] $MyIncorrectInput,

        [parameter(Mandatory)]
        [string] $On,

        [parameter()]
        [switch] $CaseSensitive
    )

    begin {
        if($CaseSensitive.IsPresent) {
            return $hash = [Collections.Generic.HashSet[string]]::new()
        }
        $hash = [Collections.Generic.HashSet[string]]::new([StringComparer]::InvariantCultureIgnoreCase)
    }
    process {
        foreach ($Item in $MyIncorrectInput) {
            if($hash.Add($Item.$On)) {
                $Item
            }
        }
    }
}

$TestVariable = @(
    Get-MyTest "Test1", "Test2"
    Get-MyTest "Test3", "Test2"
)

Get-IncorrectResults $TestVariable -On Id
$TestVariable | Get-IncorrectResults -On Id

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM