none
How do I skip a record in pipeline input RRS feed

  • Question

  • I have a fairly simple script that is taking input from "Import-Csv .\file.csv | .\script.ps1". My function has the Param, Begin, Process, End, etc.  I am creating users based off the pipeline CSV data and allow password to be provided in the file.  If the password however does not meet length requirements, I would like to show the user a "Write-Warning", skip creation of the user 'breaking out' of the remaining code for the individual user, and continue with the next row of data being input via pipeline. 

    When I use "Exit" or "Break" it stops the entire script and does not continue with the next user.  Is there a way to just skip the remaining code in the "Process" block and move to the next record?


    Find this post helpful? Does this post answer your question? Be sure to mark it appropriately to help others find answers to their searches.

    Thursday, February 20, 2014 3:57 PM

Answers

  • Depends on how your pipeline input parameter is defined.  If you define it as an array (so users can pass multiple values on a command-line, or pipe input), then your process block will most likely have a "foreach" loop, and you'd use the "continue" statement to move on to the next record.

    If your pipeline input object is a single object, then "return" works fine (as it just aborts the current call to the Process block; Process will be called again for each remaining input object.)

    For example:

    function Test-Function
    {
        [CmdletBinding()]
        param (
            [Parameter(ValueFromPipeline)]
            [string[]]
            $String
        )
    
        process
        {
            foreach ($_string in $String)
            {
                if ($_string -eq 'Some Bad Thing')
                {
                    Write-Warning "Bad!"
                    continue
                }
    
                $_string
            }
        }
    }
    
    function Test-Function
    {
        [CmdletBinding()]
        param (
            [Parameter(ValueFromPipeline)]
            [string]
            $String
        )
    
        process
        {
            if ($String -eq 'Some Bad Thing')
            {
                Write-Warning "Bad!"
                return
            }
    
            $String
        }
    }
    
    

    • Marked as answer by Chase Roth Thursday, February 20, 2014 4:43 PM
    Thursday, February 20, 2014 4:18 PM

All replies

  • So I kept digging and found using "return" does what I am looking for, so far as I can tell.  Found it here:  http://stackoverflow.com/questions/7760013/why-does-continue-behave-like-break-in-a-foreach-object

    Is there any better way to do it or is "return" the proper way to do this?


    Find this post helpful? Does this post answer your question? Be sure to mark it appropriately to help others find answers to their searches.

    Thursday, February 20, 2014 4:13 PM
  • Depends on how your pipeline input parameter is defined.  If you define it as an array (so users can pass multiple values on a command-line, or pipe input), then your process block will most likely have a "foreach" loop, and you'd use the "continue" statement to move on to the next record.

    If your pipeline input object is a single object, then "return" works fine (as it just aborts the current call to the Process block; Process will be called again for each remaining input object.)

    For example:

    function Test-Function
    {
        [CmdletBinding()]
        param (
            [Parameter(ValueFromPipeline)]
            [string[]]
            $String
        )
    
        process
        {
            foreach ($_string in $String)
            {
                if ($_string -eq 'Some Bad Thing')
                {
                    Write-Warning "Bad!"
                    continue
                }
    
                $_string
            }
        }
    }
    
    function Test-Function
    {
        [CmdletBinding()]
        param (
            [Parameter(ValueFromPipeline)]
            [string]
            $String
        )
    
        process
        {
            if ($String -eq 'Some Bad Thing')
            {
                Write-Warning "Bad!"
                return
            }
    
            $String
        }
    }
    
    

    • Marked as answer by Chase Roth Thursday, February 20, 2014 4:43 PM
    Thursday, February 20, 2014 4:18 PM
  • I am using:

    [CmdletBinding()]
    Param(
        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [string]$SamAccountName,
        
        [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
        [string]$GivenName,
        
        [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
        [string]$Initials,
        
        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [string]$SurName,
        
        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [string]$EmployeeID,
        
        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [string]$Title,
        
        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [ValidateSet("BLDG1","BLDG2")]
        [string]$Building,
        
        [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
        [Int]$Enabled = $true,
    
        [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
        [Int]$EnableMail = $true,
        
        [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
        [Int]$HomeDir = $true,
    
        [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
        [string]$Password
        
    )
    
    Begin {}
    Process 
    {
    <...STUFF...>
    }
    End {}
    So based on what I think you're saying I am good with it in this particular script since the data is one row at a time and not input as an Array...?

    Find this post helpful? Does this post answer your question? Be sure to mark it appropriately to help others find answers to their searches.

    Thursday, February 20, 2014 4:23 PM
  • Yep, in that case, you'd be using "return" in your process block.
    Thursday, February 20, 2014 4:42 PM
  • Thanks for your help!

    Find this post helpful? Does this post answer your question? Be sure to mark it appropriately to help others find answers to their searches.

    Thursday, February 20, 2014 4:44 PM
  • Remember that you can use a pipeline filter:

    Get-ADUser -filter * | Where-Object{Test-Password $_.Password} | ...

    This is useful when you need to frequestly alter the filter.

    You can also create custom filters

    Gat-ADUser -filter * | Test-Password


    ¯\_(ツ)_/¯

    Thursday, February 20, 2014 5:32 PM
  • Another very useful technique that is too often ignored,  Use a PowerShell "Filter" function (Where-Object is a filter function).

    filter Test-Password{
        Param(
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [string]$password
        )
        # test password for complexity
        if($password.Length -gt 7){$_}
        else{Write-Host "Pasword is not complex: $password" -fore red }
    }
    Assume you feed this a CSV file with a column names "Password"
    $csv=@([pscustomobject]@{Password='hello1234'},[pscustomobject]@{Password='hello'})
    $csv | Test-Password
    The functions only passes the records it test for conformance.


    ¯\_(ツ)_/¯


    • Edited by jrv Thursday, February 20, 2014 5:46 PM
    Thursday, February 20, 2014 5:43 PM
  • Thanks for the additional info. I'll keep that in mind. I haven't seen the filter function thing before.

    Find this post helpful? Does this post answer your question? Be sure to mark it appropriately to help others find answers to their searches.

    Thursday, February 20, 2014 6:32 PM