Add to Technorati Favorites
Welcome to ThePowerShellGuy.com Sign in | Join | Help

how to go to the next item in a For loop in PowerShell

I got the following PowerShell question by mail :

Hello there, I am a System Engineer / System Admin who has been using Powershell to automate some tasks, and the one thing I can’t seem to find anywhere is documentation on how to go to the next item in a For loop.  Here is an example:

Foreach

  ($line in $inFile)

{

  If ($line –eq “”) { go to the next item in the for loop}

  Write-host “This is not a blank line”

}

How is this accomplished in Powershell?

Best Regards,

EM (removed full name)

 

It is a bit tricky to find how to do this, but when we know how it is easy, there is a special variable $foreach in PowerShell that is filled when we use the Foreach Statement ( Note ! only the foreach statement does provide this $foreach variable not the Foreach-Object Cmdlet we use in the pipeline ! )  Bruce Payette does a good explanation in his book : PowerShell in Action , but when you did not read or have his book it's hard to search for and easy to overlook,

So I decided to answer his question on my blog. 

I made 3 sample scripts to show how this works, ( you can just past the code into the PowerShell console to try the examples (see output below) :

* edit * I added another script to show how you can do the same thing with the foreach-object Cmdlet, and corrected my former solution that was incorrect. 

First I made a script to show the members of the $foreach variable to be able to explore it, as it is filled by the foreach statement we need to create a loop first, that enables us to take a look at the content of the $foreach variable , ( note also the comma added to prevent the variable from enumerating ! )

Foreach ($i in 1) {
    ,$foreach | get-member
}

In the output we can see that the variable contains an object that contains the array we loop trough wrapped by an enumerator ( hence the comma was needed to show it )

TypeName: System.Array+SZArrayEnumerator

that we can use and that exposes the following functionality

MoveNext (Method)
Reset (Method)
ToString (Method)
Current (Property)

We can use the MoveNext method for our task in the following example I use it to skip the even numbers in a loop from one to ten:

* Edit * Warning ! this is actually a bad usage example, as it contains a bug and does NOT show the right way to do this, see the correct examples and explanation of the mistake I did make that I added in another edit you can find later in this post 

Foreach ($i in 1..10) {
    if ($i%2) {$foreach.moveNext()}
    $i
}

As you see in the results a boolean is returned to indicate if the MoveNext() suceeded, as this is not wanted most of the times I cast it to [void] to disregard this information ( the out-Null cmdlet can also be used for this)

Foreach ($i in 1..10) {
    if ($i%2) {[void]$foreach.moveNext()}
    $i
}

 

Below you can see the results of pasting in the code above into the PowerShell Console :

 

[PoSH]> Foreach ($i in 1) {                                                                                             
>>  ,$foreach | get-member                                                                                              
>> }                                                                                                                    
>>                                                                                                                      
                                                                                                                        
                                                                                                                        
   TypeName: System.Array+SZArrayEnumerator                                                                             
                                                                                                                        
Name        MemberType Definition                                                                                       
----        ---------- ----------                                                                                       
Clone       Method     System.Object Clone()                                                                            
Equals      Method     System.Boolean Equals(Object obj)                                                                
GetHashCode Method     System.Int32 GetHashCode()                                                                       
GetType     Method     System.Type GetType()                                                                            
get_Current Method     System.Object get_Current()                                                                      
MoveNext    Method     System.Boolean MoveNext()                                                                        
Reset       Method     System.Void Reset()                                                                              
ToString    Method     System.String ToString()                                                                         
Current     Property   System.Object Current {get;}                                                                     
                                                                                                                        
                                                                                                                        
[PoSH]>                                                                                                                 
[PoSH]> Foreach ($i in 1..10) {                                                                                         
>>  if ($i%2) {$foreach.moveNext()}                                                                                     
>>  $i                                                                                                                  
>> }                                                                                                                    
>>                                                                                                                      
True                                                                                                                    
1                                                                                                                       
True                                                                                                                    
3                                                                                                                       
True                                                                                                                    
5                                                                                                                       
True                                                                                                                    
7                                                                                                                       
True                                                                                                                    
9                                                                                                                       
[PoSH]> Foreach ($i in 1..10) {                                                                                         
>>  if ($i%2) {[void]$foreach.moveNext()}                                                                               
>>  $i                                                                                                                  
>> }                                                                                                                    
>>                                                                                                                      
1                                                                                                                       
3                                                                                                                       
5                                                                                                                       
7                                                                                                                       
9                                                                                                                       
[PoSH]>                                                                            

 

*edit* When I did make a foreach-object example, I found a bug in the examples given above in the even/odd logic used above and gave a wrong usage example, even as the output does seem to be correct.

did you spot the error in the logic allready ?

Using Foreach Object

let's start the search for the error I made with looking at the foreach-object example I created showing how to do the same thing with foreach-object :

1..10 |% {
    if ($_%2) {return}
   $_
}

We have no $foreach variable, but as foreach-object calls the provided scriptblock for every object in the pipeline, we can just use the return command to return from the scriptblock without proccessing the rest of the scriptblock for the current object and continue the loop.

  but when we look at the output we see the results are different

[PoSH]> 1..10 |% {                                                                                                      
>>     if ($_%2) {return}                                                                                               
>>    $_                                                                                                                
>> }                                                                                                                    
>>                                                                                                                      
2                                                                                                                       
4                                                                                                                       
6                                                                                                                       
8                                                                                                                       
10                                                                                                                      
[PoSH]> 

 This version does show the even numbers and does skip the Odd numbers the exact opposite of my former foreach statement example.

As I did expect the result to be the same one of the two solutions had to be wrong, and on further examination it did turn out to be the former example using the foreach statement that was incorrect, as we can see if we start the range at an even number .

[PoSH]> Foreach ($i in 2..10) {                                                                                         
>>  if ($i%2) {[void]$foreach.moveNext()}                                                                               
>>  $i                                                                                                                  
>> }                                                                                                                    
>>                                                                                                                      
2                                                                                                                       
3                                                                                                                       
5                                                                                                                       
7                                                                                                                       
9                                                                                                                       
[PoSH]>                                                                       

We can see that in this case, the result of my solution is incorrect  but as the reason behind this might still not be obvious

as a last hint before the spoiler, a correct solution in this case would have been :

[PoSH]> Foreach ($i in 1..10) {                                                                                         
>>  if ($i%2) {[void]$foreach.moveNext()}                                                                               
>>  $foreach.current                                                                                                    
>> }                                                                                                                    
>>                                                                                                                      
2                                                                                                                       
4                                                                                                                       
6                                                                                                                       
8                                                                                                                       
10                                                                                                                      
[PoSH]>                                                                         

 The $i variable did not get updated by the call to MoveNext() and we need to use $foreach.current to get the object that actualy is current.

 The reason behind this and the thing to keep in mind when using the MoveNext Method is that

$foreach.moveNext() does NOT skip the rest of the code for the current loop at all and does NOT start a new loop to proccess either,

This is the reason that $i was not updated and actualy the old value still was returned,  at the next loop the $i variable was updated again so that in reallity 2 items where skipped instead of one item as intended, as no new loop is started , the variable also $i is not updated hence it still contains the former item, while only $foreach.current is updated ,giving the false impression that all did work correctly.

 

I hope these examples, next to answering the question also show that in this case the variable $foreach might a bit hard to find if you do not know that it is there (as it is only there inside the loop itself so we can not use the variable:\ drive to find it ) but that after we know that it is there we can use the interactive nature of PowerShell to discover how this variable works and how we can use it !

Enjoy,

Greetings /\/\o\/\/

Published Tuesday, October 23, 2007 3:01 PM by MoW

Comments

# re: how to go to the next item in a For loop in PowerShell

He may also be looking for the "continue" statement which will skip the remaining statements in the for loop and then go on to the next item in the loop.

Tuesday, October 23, 2007 3:33 PM by Bryce

# Interesting Finds: October 24, 2007

Wednesday, October 24, 2007 10:15 AM by Jason Haley

# A simpler way or another mistake?

Running:

foreach ($i in 1..10) {

 $i

 $foreach.movenext()

}

produces:

1

3

5

7

9

The IF statement is eliminated. However, the rookie I am has to ask: Is there something inherently wrong with this way of accomplishing the task?

Wednesday, October 24, 2007 11:22 AM by Clint

# re: how to go to the next item in a For loop in PowerShell

Hi Clint,

No, I just (maybe badly) picked this odd / even example to show the use of the $foreach variable.

The if statement is in the original example, I wanted to keep close to that so I used it also.

Your example might have been better when the target is only to get the odd numbers.

in that case another way would be to use the where statement like this :

[PoSH]> 1..10 |? {$_%2}

1

3

5

7

9

Enjoy,

Greetings /\/\o\/\/

Friday, October 26, 2007 5:24 AM by MoW
Anonymous comments are disabled