Monthly Archive

Categories

foreach, pipelines and $_

I’ve recently seen a few questions where people have been using a pipeline inside a foreach loop and experienced problems when they’ve tried to access properties on the looping objects. To illustrate we’ll start with a CSV file containing emailaddresses and job titles.

£> Import-Csv -Path C:\Test\userdata.txt

emailaddress             title   
------------             -----   
gdreen@Manticore.org     Boss    
dbrown@Manticore.org     Underling
dwhite@Manticore.org     Underling
jdaven@Manticore.org     Minion  
fgreen@Manticore.org     Minion  
dgreensmth@Manticore.org Minion  
dgreenly@Manticore.org   Minion

This is definitely an employee friendly organisation Smile

At the moment AD doesn’t contain any job title information

£> $users = Import-Csv -Path C:\Test\userdata.txt

foreach ($user in $users){
$mail = $user.EmailAddress

Get-ADUser -Filter {EmailAddress -eq $mail} -Properties Title |
select Name, Title

}

Name                                      Title                                  
----                                      -----                                  
Dave Green                                                                       
Dave Brown                                                                       
Dave White                                                                       
Jo Daven                                                                         
Fred Green                                                                       
Dale Greensmith                                                                  
Dave Greenly

 

The approach that causes problems is this:

£> $users = Import-Csv -Path C:\Test\userdata.txt

foreach ($user in $users){
$mail = $user.EmailAddress

Get-ADUser -Filter {EmailAddress -eq $mail} -Properties Title |
foreach {Set-ADUser -Identity $_ -Title $_.Title} |

Get-ADUser -Filter {EmailAddress -eq $mail} -Properties Title |
select Name, Title
}

Name                                      Title                                  
----                                      -----                                  
Dave Green                                                                       
Dave Brown                                                                       
Dave White                                                                       
Jo Daven                                                                         
Fred Green                                                                       
Dale Greensmith                                                                  
Dave Greenly     

 

When you use foreach as a keyword the $_ and $psitem variables aren’t available. These variables represent the current object on the pipeline.  The foreach keyword loop doesn’t have a pipeline as such.

 

Inside the foreach a pipeline is created

Get-ADUser -Filter {EmailAddress -eq $mail} -Properties Title |
foreach {Set-ADUser -Identity $_ -Title $_.Title -PassThru} |
select Name, Title

 

$_ is used correctly to identify the object on which Set-ADUser is to work – its the current object on the pipeline.

 

The use of  $_.Title  to set the user’s job title is where the problem really bites.  $_.Title  refers to the Title property of the current object on the pipeline so you are setting the Title to its existing value.

 

You need to reach back to the $user object that represents the current object from the set you are looping through with foreach to get the correct value

£> $users = Import-Csv -Path C:\Test\userdata.txt

foreach ($user in $users){
$mail = $user.EmailAddress

Get-ADUser -Filter {EmailAddress -eq $mail} -Properties Title |
foreach {Set-ADUser -Identity $_ -Title $user.Title} |

Get-ADUser -Filter {EmailAddress -eq $mail} -Properties Title |
select Name, Title
}

Name                                      Title                                  
----                                      -----                                  
Dave Green                                Boss                                   
Dave Brown                                Underling                              
Dave White                                Underling                              
Jo Daven                                  Minion                                 
Fred Green                                Minion                                 
Dale Greensmith                           Minion                                 
Dave Greenly                              Minion  

 

You’ll see similar problems if you have nested foreach-object loops or a switch statement inside a foreach-object loop.  $_ always refers to the current context and you have to either reach back to the looping variable in the csae of a foreach or set variables on the data in the outer foreach before entering the nested foreach.

Comments are closed.