In the last two posts I covered how to create a simple site directory. Now what if you need to add a column to track something thats not gathered by the script from the object model? The previous two scripts would destroy the list during each run. In order to have persistent records in the list the script needs to update individual items.

#if list doesn't exist create it
$list = $null
$web = get-spweb
$list = $web.lists["Site List"]

if ($list -eq $null) {
    #create list
    $SPTemplate = $SPWeb.ListTemplates["Custom List"]

    #add fields to list
    $spFieldType = [Microsoft.SharePoint.SPFieldType]::Text
    $list = (Get-SPWeb -identity $URL).Lists[$Title]
    $List.Fields.Add("Secondary Contact",$spFieldType,$false)

    #create default view with added columns
    $listURL = $URL + "/Lists/Site%20List/AllItems.aspx"
    $SPWeb = Get-SPWeb $URL
    $spView = $SPWeb.GetViewFromUrl($listURL)
    $spView.ViewFields.Add("Secondary Contact")

#Add/update sites
$sites = Get-SPSite -WebApplication -limit all | where {$_ -notlike "*Office_Viewing_Service_Cache"}
foreach ($site in $sites) {
    $found = $null

    #get list
    $web = get-spweb
    $list = $web.lists["Site List"]
    $items = $list.items | select title

    foreach ($item in $items) {
        if ($item.Title -eq $site.URL.ToString()) {
            $found = $true
            #update item
            $SPItem = $List.Items | Where {$_["Title"] -eq $site.URL.ToString()}
            write-host "updating" $SPItem.Title.ToString()
            #update items
            $SPItem["Title"] = $site.URL
            $SPItem["Name"] = $site.RootWeb
            $SPItem["URL"] = $site.URL
            $SPItem["Owner"] = $site.Owner.displayname
            $SPItem["Secondary Contact"] = $site.SecondaryContact.DisplayName
        elseif ($item.Title -ne $site.URL.ToString()) {
            $found = $false

    If ($found -eq $false) {
        #add items
        write-host "adding" $site.URL
        $newItem = $list.Items.Add()
        $newItem["Title"] = $site.URL
        $newItem["Name"] = $site.RootWeb
        $newItem["URL"] = $site.URL
        $newItem["Owner"] = $site.Owner.displayname
        $newItem["Secondary Contact"] = $site.SecondaryContact.DisplayName

#Remove old items
#get list
$web = get-spweb
$list = $web.lists["Site List"]
$items = $list.items

foreach ($item in $items) {
    $site = $null

    $site = get-spweb $item.Title.ToString()
    if ($site -eq $null) {
        #remove item
        write-host "Removing" $item.Title.ToString()

The first section of the script checks to see if a custom list exists. If it doesn’t, then the script creates it. This is the same process as the last two scripts.

The next section handles updates and adds to the list. Get-SPSite returns all site collections. The main foreach loop in this section loops through each site collection. It then uses two other foreach statements to check each item thats currently in the list against the current site collection in the loop iteration. If it exists it updates the specified columns. If it doesn’t exist then it adds an entry for the site.

The second section of the script handles site deletions. It gets all entries from the directory list and checks to see if a site collection exists at the given URL. If it doesn’t it deletes the entry from the list.

Once the script has run, you can add additional columns to the list through the SharePoint web interface to track other information with each site. Since only object model data for the precreated columns is updated, additional added data will not be affected during additional runs. But new sites will continue to be added to the list and deleted sites removed. This can also be modified to work with the blog directory idea from part 2 of this series.