Tips for working with the SharePoint Object Model in PowerShell

One of the models used by SharePoint 2010's cmdlets is a kind of "deferred disposal" which means that SPWeb instances are not disposed until the pipeline in which they are involved in completes. This works like this:

function Get-SPWeb { 
     param([uri]$Url) 
 
     begin { 
         # get SPSite that owns the passed Url 
         $site = new-object microsoft.sharepoint.spsite $url 
         # return specific SPWeb instance 
         $site.OpenWeb()  
     } 
     end { 
         # this disposes owning spsite AND the returned web 
         $site.Dispose() 
     } 
}

Now here is how this works in practice (this is a single line):

ps> get-spweb "http://localhost/sites/test" | foreach-object { 
    $_.Title = "New Name"; $_.update() 
}

The first portion will obtain a single SPWeb instance and pass it to the ForEach-Object portion. Only when the foreach completes (and finishes changing the web's title) will the corresponding End block be called in get-spweb, which disposes the site and web. What's important is that entire pipeline is a single block of code that is executed in a single call.

This won't work interactively like this:

ps> $w = get-spweb "http://localhost/sites/test" # calls begin AND end 
ps> $w.title = "new name" 
ps> $w.update() # boom! web is already disposed

So in this latter example you'd have to use a different implementation of get-spweb (one that omits the end block, or suppresses it with a switch parameter) and then you'd have to dispose the site yourself.

Another important detail is that working interactively in powershell with sharepoint objects will cause you to leak memory if you don't take certain precautions. By default, powershell runs in MTA (multi-threaded apartment) and will use a pool of threads to execute your commands. Each line entered will use a different thread. Each time you access a COM object with a different thread, you will leak some memory from the unmanaged heap as a new heap is allocated for the context switch (without the old one being freed.) This can be alleviated by starting powershell.exe with the -STA switch. This will ensure that all commands and pipelines are executed with the same thread, avoiding the memory leak. That said, simply closing the powershell console will regain all of that memory again but long running scripts might starve your servers of memory if you're not careful, bringing down SharePoint (anything else that doesn't like to get starved of working set.) This is why the single-line approach works so well in the former example: the object is allocated and disposed in the same pipeline, and by extension, the same thread. No leak.

(from an answer I gave on Stack Overflow)

About the author

Irish, PowerShell MVP, .NET/ASP.NET/SharePoint Developer, Budding Architect. Developer. Montrealer. Opinionated. Montreal, Quebec.

Month List

Page List