Lars Nielsen's Discoveries

April 2, 2012

PowerShell ForEach behaviour with null and empty lists

Filed under: Administration,Development,SharePoint — Lars Nielsen @ 6:23 pm
Tags: ,

Watch out when using ForEach in Powershell scripts.

Here’s a simple script that enumerates the site collections that have “portal” in the URL, and lists their URL’s:

Get-SPSite | Where-Object {$_.Url -like "*portal*"}

If you wanted to something more complex with each SPSite you might want to use a ForEach loop like this:

$sites = Get-SPSite | Where-Object {$_.Url -like "*portal*"}
foreach ($site in $sites) {
  Write-Host "Site is SPSite Url=$site"
}

This will output something like this:

Site is SPSite Url=http://portal.mydomain.com
Site is SPSite Url=http://portal.mydomain.com/sites/site1
Site is SPSite Url=http://portal.mydomain.com/sites/site2

But what if you change the condition in the Where-Object to something which doesn’t match any of your site collections, like this:

$sites = Get-SPSite | Where-Object {$_.Url -like "*8h78fw7rhfr78*"}
foreach ($site in $sites) {
  Write-Host "Site is SPSite Url=$site"
}

How many times will the ForEach loop execute in this case? If you’re a C# developer you’ll say zero – it won’t execute at all. Or you might expect an error – depending on whether $sites is a zero-length array, or null. But actually in Powershell this script above outputs this:

Site is SPSite Url=

The ForEach loop does execute, once, with a null value.

However, if you don’t use the $sites variable then it behaves differently, so if you do this:

foreach ($site in (Get-SPSite | Where-Object {$_.Url -like "*J9898fsh*"})) {
     Write-Host "Site is $site"
  }

It will output nothing and the ForEach loop doesn’t execute.

I think this is because of the way ForEach works will $null values. If you want to use variables and ForEach you need to include an explicit check for null values, which in fact you would normally do in C# anyway to be on the safe side:

$sites = Get-SPSite | Where-Object {$_.Url -like "*J9898fsh*"}
if ($sites -ne $null) {
   foreach ($site in $sites) {
     Write-Host "Site is $site"
   }
}

In this case the ForEach loop will not execute when $sites is null, neither when $sites is a zero-length array.

Advertisements

4 Comments »

  1. This bug with foreach is fixed in Powershell V3. Give a try.

    Comment by techibee.com — October 11, 2012 @ 2:56 pm

  2. Thank you.. helped me

    Comment by Soo — November 19, 2013 @ 10:25 am

  3. Thanks for this post verifying the bug. That’s super retarded. If there are zero elements in the collection, it should run zero times. The language (for each) that’s used should have made that super obvious. Glad they fixed it in version 3 at least. It’s sad that we can’t even count on the computer language itself and have to be “on the safe side” because we can’t know for sure what a command will do. ?? You computer programmers out there are a hearty bunch I guess. This job is apparently amazingly difficult to get right.

    Comment by dude — December 20, 2013 @ 8:20 pm

  4. Hello

    to avoid this bug/feature (scalar value), you have to enclose Get-SPSite … with @()
    Powershell will create an empty array

    $sites = @(Get-SPSite | Where-Object {$_.Url -like “*8h78fw7rhfr78*”})
    foreach ($site in $sites) {
    Write-Host “Site is SPSite Url=$site”
    }

    Comment by St├ęphane O. — July 17, 2016 @ 1:02 am


RSS feed for comments on this post. TrackBack URI

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

Create a free website or blog at WordPress.com.

%d bloggers like this: