Powershell to report memory leaks and assembly info on SharePoint 2013/2010 custom solutions.


Issue:

Recently I was involved in a task to troubleshoot performance related issues on a SharePoint farm. On analyzing the farm I found more than 50 WSP’s are deployed. On further analysis some of these solutions had two major performance related issues:

SharePoint Objects are not disposed properly:

Windows SharePoint Services object model contains objects which are not managed by ASP.Net windows garbage collector. Developers must take precautions when using these objects to avoid their long-term retention in memory in the Microsoft .NET Framework.

In scenarios in which you use SharePoint objects extensively—for example, in SharePoint sites that use custom Web Parts—you can cause the following unusual behaviors by not disposing of SharePoint objects when you are finished with them. This results in

  • Frequent recycles of the Windows SharePoint Services application pool, especially during peak usage
  • Application crashes that appear as heap corruption in the debugger
  • High memory use for Microsoft Internet Information Services (IIS) worker processes
  • Poor system and application performance

For more details refer this link

http://msdn.microsoft.com/en-us/library/aa973248(v=office.12).aspx

 Production solutions built in debug mode instead of release mode:

The default build setting during development is “Debug” mode and it is a common mistake to allow this development time setting to find its way onto production servers during deployment.  This can often leads to

  • The compilation of ASP.NET pages takes longer (since some batch optimizations are disabled)
  • Code can execute slower (since some additional debug paths are enabled)
  • Much more memory is used within the application at runtime
  • Improper recycles of App pools etc

More details here: http://weblogs.asp.net/scottgu/Don_1920_t-run-production-ASP.NET-Applications-with-debug_3D001D20_true_1D20_-enabled

Solution:

Though the only known solution is re-build these custom WSP’s using best practices, its important to develop a detailed report on each custom assemblies on GAC and provide a report to fix these issues. So idea is to build a powershell script to

1) Export all the WSP solutions

2) Extract the WSP’s

3) Run SPDispose check on each DLL

4) Identify the assembly is in “Debug” or release mode

5) Export the report to CSV

EXCEL's

 

 

Before running the script install SPDisposeCheck tool from here

http://download.microsoft.com/download/B/4/D/B4D279A0-E159-40BF-A5E8-F49ABDBE95C7/SPDisposeCheck.msi

Download this script here:
Get-SPDisposeReport.ps1

Powershell:

</pre>
<pre>
#
#.SYNOPSIS
#Creates SP Dispose report on all WSP's
#
#.EXAMPLE
#.\Get-SPDisposeReport.ps1
#

Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue

#Variables
$wspdir = "D:\WSP\WSPReport1" #Location to export all WSP's
$exportdir = "$wspdir\Export-$((get-date).toString('yyyyMMdd'))\"
$CSVLocation = "$wspdir\SPDisposeResults.csv"

#create directory
[IO.Directory]::CreateDirectory($wspdir)

#Function to export all WSP's
function Export-AllWSPs
{
 Write-Host Exporting solutions to $wspdir
 foreach ($solution in Get-SPSolution)
 {
 $id = $Solution.SolutionID
 $title = $Solution.Name
 $filename = $Solution.SolutionFile.Name
 Write-Host "Exporting $title to ¦\$filename" -nonewline
 try {
 $solution.SolutionFile.SaveAs("$wspdir\$filename")
 Write-Host "– done" -foreground green
 }
 catch
 {
 Write-Host "– error : $_" -foreground red
 }
 }

}

#Function to extract all WSP Packages
function Extract-AllWSPs
{
 #Retrieve the wsp files in this folder and subfolders
 $s = [system.IO.SearchOption]::AllDirectories
 $fileEntries = [IO.Directory]::GetFiles($wspdir,"*.wsp",$s);
 foreach($fullFileName in $fileEntries)
 {
 $fileName = $(Get-Item $fullFileName).Name;
 $dirName = $fileName.Replace(".wsp","");
 $extractPath = $exportdir + $dirName;
 $dir = [IO.Directory]::CreateDirectory($extractPath) 

 #uncab
 Write-Host "Export $fileName started" -ForegroundColor Red
 $destination = $extractPath
 C:\Windows\System32\extrac32.exe $fullFileName /e /Y /L $destination
 }

}

#Function to get Assembly details
function Get-AssemblyCustomProperty
 {
 param
 (
 $assembly,
 $TypeNameLike,
 $Property = $null
 )

 $value = $null
 foreach ($attribute in $assembly.GetCustomAttributes($false))
 {
 if ($attribute.GetType().ToString() -like "*$TypeNameLike*")
 {
 if ($Property -ne $null)
 {
 # Select-Object -ExpandProperty fails if property value is $null
 try {
 $value = $attribute | Select-Object -ExpandProperty $Property
 }
 catch {
 $value = $null
 }
 }
 else
 {
 $value = $attribute
 }
 break;
 }
 }

 $value
 }

#Function to report SP Dispose check results
Function Get-SPDisposeResults()
{

 #Pause for 5 secs to ensure extract is complete
 Start-Sleep -s 5
 $Dir = get-childitem $wspdir -recurse
 $List = $Dir | where {$_.extension -eq ".dll"}
 $List | ForEach-Object {

 [string]$report = & "C:\Program Files (x86)\Microsoft\SharePoint Dispose Check\SPDisposeCheck.exe" $_.fullname
 #remove repetitive strings
 $report = $report -replace "Note: This tool may report errors which are not actually memory leaks, otherwise known as false positives. Further investigation should be done to identify and correct real errors. It is designed to assist developers in making sure their code adheres to best practices for memory allocation when using SharePoint APIs. Please see the following for more information: http://blogs.msdn.com/rogerla/ http://msdn2.microsoft.com/en-us/library/aa973248.aspx http://msdn2.microsoft.com/en-us/library/bb687949.aspx", ""
 $build = "RELEASE";
 try {
 $info = @{}
 $assembly = [Reflection.Assembly]::LoadFile($_.FullName)
 $attr = $assembly.GetCustomAttributes([Diagnostics.DebuggableAttribute], $false)
 $info.IsJITTrackingEnabled = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Diagnostics.DebuggableAttribute' -Property 'IsJITTrackingEnabled'
 #$info.IsJITOptimizerDisabled = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Diagnostics.DebuggableAttribute' -Property 'IsJITOptimizerDisabled'
 #$info.DebuggingFlags = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Diagnostics.DebuggableAttribute' -Property 'DebuggingFlags'
 #Write-Host $_.FullName: +" IsJITTrackingEnabled "+ $info.IsJITTrackingEnabled
 #Write-Host $_.FullName: +" IsJITOptimizerDisabled "+ $info.IsJITOptimizerDisabled
 #Write-Host $_.FullName: +" DebuggingFlags "+ $info.DebuggingFlags

 } catch {
 throw $_
 }

 Write-Host $report

 # Create a hash table with all the data
 $hash = @{
 "Assembly" = $_.name
 "Report" = $report
 "Debug Mode enabled" = $info.IsJITTrackingEnabled

 }
 # Convert the hash to an object and output to the pipeline
 New-Object PSObject -Property $hash
 }
}

#Function calls
Export-AllWSPs
Extract-AllWSPs
Get-SPDisposeResults | Export-Csv -NoTypeInformation -Path $CSVLocation

 

Advertisements

One thought on “Powershell to report memory leaks and assembly info on SharePoint 2013/2010 custom solutions.

  1. Pingback: Office 365 Developer Podcast: Episode 006 with Thorsten Hans | Office 365 Deployment Autoblog

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