sus42

A Blog on Wndows Server and Microsoft Exchange by Thomas Pätzold

The Powershell Foreach Loop

leave a comment »


Have you ever thought about what happens when the collection is empty through wich you want to step with the foreach loop in Powershell 2.0?

Ok, but let´s start at the beginning.
What happens when the collection contains objects?
Think about a loop witch counts the files with the extension .txt in a given folder. The Code looks like

$path = "C:\temp"
$filter = "*.txt"
$count = 0

$files = get-childitem -path $path -filter $filter

foreach ($file in $files) {
        $count ++
}
Write-Host "There are $count files with the pattern $filer in folder $path"

What happens when the collection is empty?
The second example runs on an empty collection. Now run the same code with a filter witch doesn´t match a file or foldername. So Object $files should be empty. But what looks the output like?
foreach look with empty collection
In this example one file is found but why?
The reason is very simple because $files is a NULL Object. And a NULL Object is an object so there will be one cycle in the loop and at the end $count contains the value “1″. The NULL Object is a scalar but not a collection. But the foreach loop operates on a collection. So the NULL object has to be casted to a collection and now the collections contains one element (the Null object)

This is a real problem if the further scripts depends on this result.

Now it gets very strange. If you generate the collection within the header of the foreach loop you will get the correct result. The code looks like

$path = "C:\temp"
$filter = "*.txt"
$count = 0

foreach ($file in (get-childitem -path $path -filter $filter)) {
        $count ++
}
Write-Host "There are $count files with the pattern $filer in folder $path"

This is the output in Powershell in contrast to the first example.
The two examples with their Output

Now we look for a solution for this Problem:
There are two possible solutions.
1) You have to check with an if-statement if the collection is empty before stepping through the loop.
The Code looks like

$path = "C:\temp"
$filter = "*.txt"
$count = 0

$files = get-childitem -path $path -filter $filter
If ($files -ne $null) {
        foreach ($file in $files) {
                $count ++
        }
}
Write-Host "There are $count files with the pattern $filer in folder $path"

2) The second solution is to generate the collection within the header of the foreach loop. So you will get the correct result. The code looks like

$path = "C:\temp"
$filter = "*.txt"
$count = 0

foreach ($file in (get-childitem -path $path -filter $filter)) {
        $count ++
}
Write-Host "There are $count files with the pattern $filer in folder $path"

And this is the output in Powershell in contrast to the first example.
The two examples with their Output

3) The third solution is to generate explicit an array (collection) with the @() statement. If now the command generates a NULL object then the collection (array) is empty and your code will generate the expected result.
The code looks like:

$path = "C:\temp"
$filter = "*.txt"
$count = 0

$files = @(get-childitem -path $path -filter $filter)
If ($files -ne $null) {
        foreach ($file in $files) {
                $count ++
        }
}
Write-Host "There are $count files with the pattern $filer in folder $path"

Conclusion
I think this is an error in the implementation of the foreach loop. Perhaps we have to wait for the next version of the Windows Powershell to get this problem solved.
On Microsoft Connect you will get further infromation on this topic.

About these ads

Written by Thomas Pätzold

January 24, 2011 at 10:36 pm

Posted in Powershell, Scripting

Tagged with ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: