functions/SelectFunctions.ps1

function Select-First {
    [CmdletBinding()]
    [Alias('First')]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [PSObject]$InputObject,

        [Parameter(Position = 0, Mandatory, HelpMessage = 'How many items do you want to select?')]
        [ValidateRange(0, 2147483647)]
        [int]$First,

        [Parameter(Position = 1, HelpMessage = 'Select a property to sort on before selecting the first number of objects.')]
        [ValidateNotNullOrEmpty()]
        [string]$Property,

        [Parameter()]
        [ValidateRange(0, 2147483647)]
        [int]$Skip = 0,

        [Parameter()]
        [switch]$Descending
    )

    begin {
        #tags are used for categorizing the command
        #cmdTags = select
        Write-Verbose "[BEGIN ] Starting $($MyInvocation.MyCommand)"
        Write-Verbose "[BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"

        if ($PSBoundParameters.ContainsKey('Property')) {
            $sortParams = @{Property = $Property }
            Write-Verbose "[BEGIN ] Sorting on $Property"
        }
        if ($PSBoundParameters.ContainsKey('Descending')) {
            if ($sortParams) {
                $sortParams.Add('Descending', $True)
            }
            else {
                #it is possible to sort without a property say on a string or number
                $sortParams = @{'Descending' = $True }
            }
        }

        $data = [System.Collections.Generic.List[object]]::new()

        Write-Verbose "[BEGIN ] Selecting first $First, skipping $skip."

    } #begin

    process {

        #save input objects so they can be sorted
        if ($data.count -eq 0) {
            Write-Verbose '[PROCESS] Processing input'
        }
        #verify property
        if ($property -and $InputObject.PSObject.properties.name -notcontains $property) {
            $exception = [System.ArgumentException]::new("Cannot find property $property on the InputObject.")
            throw $exception
        }
        else {
            $data.add($InputObject)
        }

    } #process

    end {
        if ($sortParams) {
            Write-Verbose '[END ] Sort parameters'
            Write-Verbose ($sortParams | Out-String)
            $data = $data | Sort-Object @sortParams
        }
        $data | Microsoft.PowerShell.Utility\Select-Object -First $first -Skip $skip

        Write-Verbose "[END ] Ending $($MyInvocation.MyCommand)"

    } #end

} #end function Select-First

function Select-Last {
    [CmdletBinding()]
    [Alias('Last')]
    param(
        [Parameter(Mandatory, ValueFromPipeline )]
        [PSObject]$InputObject,

        [Parameter(Position = 0, Mandatory, HelpMessage = 'How many items do you want to select?')]
        [ValidateRange(0, 2147483647)]
        [int]$Last,

        [Parameter(Position = 1, HelpMessage = 'Sort on this property and then select the last number of items')]
        [ValidateNotNullOrEmpty()]
        [string]$Property,

        [Parameter()]
        [ValidateRange(0, 2147483647)]
        [int]$Skip = 0,

        [Parameter()]
        [switch]$Descending
    )

    begin {
        #tags are used for categorizing the command
        #cmdTags = select
        Write-Verbose "[BEGIN ] Starting $($MyInvocation.MyCommand)"
        Write-Verbose "[BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"

        if ($PSBoundParameters.ContainsKey('Property')) {
            $sortParams = @{Property = $Property }
            Write-Verbose "[BEGIN ] Sorting on $Property"
        }
        if ($PSBoundParameters.ContainsKey('Descending')) {
            if ($sortParams) {
                $sortParams.Add('Descending', $True)
            }
            else {
                #it is possible to sort without a property say on a string or number
                $sortParams = @{'Descending' = $True }
            }
        }

        $data = [System.Collections.Generic.List[object]]::new()

        Write-Verbose "[BEGIN ] Selecting Last $Last, skipping $skip."

    } #begin

    process {
        #save input objects so they can be sorted
        if ($data.count -eq 0) {
            Write-Verbose '[PROCESS] Processing input'
        }
        #verify property
        if ($property -and $InputObject.PSObject.properties.name -notcontains $property) {
            $exception = [System.ArgumentException]::new("Cannot find property $property on the InputObject.")
            throw $exception
        }
        else {
            $data.add($InputObject)
        }
    } #process

    end {
        if ($sortParams) {
            Write-Verbose '[END ] Sorting parameters'
            Write-Verbose ($sortParams | Out-String)
            $data = $data | Sort-Object @sortParams
        }
        $data | Select-Object -Last $Last -Skip $skip

        Write-Verbose "[END ] Ending $($MyInvocation.MyCommand)"

    } #end

} #end function Select-Last

function Select-After {
    [CmdletBinding()]
    [alias('after')]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [PSObject]$InputObject,

        [Parameter(Position = 0, Mandatory, HelpMessage = 'Enter the cutoff date')]
        [DateTime]$After,

        [Parameter(HelpMessage = 'Enter the property name to select on. It needs to be a datetime object.')]
        [ValidateNotNullOrEmpty()]
        [string]$Property = 'LastWriteTime'
    )

    begin {
        #tags are used for categorizing the command
        #cmdTags = select
        Write-Verbose "[BEGIN ] Starting $($MyInvocation.MyCommand)"
        Write-Verbose "[BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"
        Write-Verbose "[BEGIN ] Selecting objects after $after based on the $Property property"
    } #begin

    process {
        #verify property
        if ($InputObject.PSObject.properties.name -notcontains $property) {
            $exception = [System.ArgumentException]::new("Cannot find property $property on the InputObject.")
            throw $exception
        }
        else {
            $InputObject | Where-Object { $_.$property -ge $After }
        }
    } #process

    end {
        Write-Verbose "[END ] Ending $($MyInvocation.MyCommand)"
    } #end

} #end function

function Select-Before {
    [CmdletBinding()]
    [alias('before')]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [PSObject]$InputObject,

        [Parameter(Position = 0, Mandatory, HelpMessage = 'Enter the cutoff date')]
        [DateTime]$Before,

        [Parameter(HelpMessage = 'Enter the property name to select on. It must be a datetime object.')]
        [ValidateNotNullOrEmpty()]
        [string]$Property = 'LastWriteTime'
    )

    begin {
        #tags are used for categorizing the command
        #cmdTags = select
        Write-Verbose "[BEGIN ] Starting $($MyInvocation.MyCommand)"
        Write-Verbose "[BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"
        Write-Verbose "[BEGIN ] Selecting objects before $before based on the $Property property"
    } #begin

    process {
        #verify property
        if ($InputObject.PSObject.properties.name -notcontains $property) {
            $exception = [System.ArgumentException]::new("Cannot find property $property on the InputObject.")
            throw $exception
        }
        else {
            $InputObject | Where-Object { $_.$property -le $Before }
        }
    } #process

    end {
        Write-Verbose "[END ] Ending $($MyInvocation.MyCommand)"
    } #end

} #end function

function Select-Newest {
    [CmdletBinding()]
    [alias('newest')]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [PSObject]$InputObject,

        [Parameter(Position = 0, Mandatory, HelpMessage = 'Enter the number of newest items to get')]
        [ValidateRange(0, 2147483647)]
        [Int]$Newest,

        [Parameter(HelpMessage = 'Enter the property name to select on. It must be a datetime object.')]
        [ValidateNotNullOrEmpty()]
        [string]$Property = 'LastWriteTime'
    )

    begin {
        #tags are used for categorizing the command
        #cmdTags = select
        Write-Verbose "[BEGIN ] Starting $($MyInvocation.MyCommand)"
        Write-Verbose "[BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"
        $data = [System.Collections.Generic.List[object]]::new()
    } #begin

    process {
        if ($data.count -eq 0) {
            Write-Verbose '[PROCESS] Processing input'
        }
        #verify property
        if ($InputObject.PSObject.properties.name -notcontains $property) {
            $exception = [System.ArgumentException]::new("Cannot find property $property on the InputObject.")
            throw $exception
        }
        else {
            $data.add($InputObject)
        }
    } #process

    end {
        Write-Verbose "[END ] Selecting newest $newest object(s) based on $property"
        $data | Sort-Object -Property $property -Descending | Select-Object -First $Newest
        Write-Verbose "[END ] Ending $($MyInvocation.MyCommand)"
    } #end

}

function Select-Oldest {
    [CmdletBinding()]
    [alias('oldest')]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [PSObject]$InputObject,

        [Parameter(Position = 0, Mandatory, HelpMessage = 'Enter the number of Oldest items to get')]
        [ValidateRange(0, 2147483647)]
        [Int]$Oldest,

        [Parameter(HelpMessage = 'Enter the property name to select on. It must be a datetime object.')]
        [ValidateNotNullOrEmpty()]
        [string]$Property = 'LastWriteTime'
    )

    begin {
        #tags are used for categorizing the command
        #cmdTags = select
        Write-Verbose "[BEGIN ] Starting $($MyInvocation.MyCommand)"
        Write-Verbose "[BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"
        $data = [System.Collections.Generic.List[object]]::new()
    } #begin

    process {
        if ($data.count -eq 0) {
            Write-Verbose '[PROCESS] Processing input'
        }
        #verify property
        if ($InputObject.PSObject.properties.name -notcontains $property) {
            $exception = [System.ArgumentException]::new("Cannot find property $property on the InputObject.")
            throw $exception
        }
        else {
            $data.add($InputObject)
        }
    } #process

    end {
        Write-Verbose "[END ] Selecting oldest $oldest object(s) based on $property"
        $data | Sort-Object -Property $property | Select-Object -First $Oldest
        Write-Verbose "[END ] Ending $($MyInvocation.MyCommand)"
    } #end
}


#EOF