This post is the second of a series explaining how to audit your SharePoint farm.
- SharePoint health check (1): Auditing the SharePoint farm
- SharePoint health check (2): Extracting Customizations (this post)
- SharePoint health check (3): Auditing Customizations
Extracting Customizations from the Farm
When auditing the customizations of your SharePoint farm, the first step is to retrieve all of them in their currently deployed versions.
This can be achieved by some PowerShell code executed on one of the farms servers.
- Log in to one of your server on your SharePoint farm (you will require farm administrator permissions)
- Create a local folder to store the customizations.
- Open a SharePoint Management Shell (PowerShell) window and browse to that new folder.
- Extract all WSPs and/or Apps from SharePoint by running the following PowerShell scripts
- Full trust farm solutions
$ftcPath = "filepath to store the full trust farm solutions" (Get-SPFarm).Solutions | % { $_.SolutionFile.SaveAs($ftcPath + "\" + $_.Name) }
- Sandboxed solutions (from a single site)
$sbsPath = "filepath to store the sandboxed solutions" $site = Get-SPSite "http://<url to site>" $listTemplate = [Microsoft.SharePoint.SPListTemplateType]::SolutionCatalog $solGallery = $_.GetCatalog($listTemplate) $solGallery.Items | % { [System.IO.FileStream]$outStream = New-Object System.IO.FileStream(($sbsPath+"\"+$_.File.Name), [System.IO.FileMode]::Create); $fileData = $_.File.OpenBinary(); $outStream.Write($fileData, 0, $fileData.Length); $outStream.Close(); }
- SharePoint Apps (from a single web)
$appPath = "filepath to store the apps" $instances = Get-SPAppInstance -Web "http://<url to web>" foreach ($instance in $instances) { $filename = [RegEx]::Replace($instance.Title, "[{0}]" -f ([RegEx]::Escape([String][System.IO.Path]::GetInvalidFileNameChars())), '')+".app" Export-SPAppPackage -App $instance.App -Path ($webPath + "\"+ $filename) }
- Full trust farm solutions
- Copy the folder with your customizations to a network share, which is accessible from where you run SPCAF
I want them all!
The code above just illustrates how to get solutions and apps from a single instance of a site or web.
To extract all code customizations from the farm you can use the following complete script. It retrieves them from all sites and webs which are accessible by the account executing the script.
It creates a folder named after the current date, subfolders for full trust solutions, sandboxed solutions and apps as well as subfolders for each site or web that contains a customisation.
During execution it logs the processed sites, solutions and apps.
Exporting SharePoint Customizations Saving farm solutions to C:\Users\sp_admin\temp\20141009\FullTrust ftc.text1.wsp...Done ftc.text2.wsp...Done ftc.text3.wsp...Done Saving sandboxed solutions to C:\Users\sp_admin\temp\20141009\Sandboxed http://my.sp2013.dev.local...None http://my.sp2013.dev.local/personal/sp_admin...None http://my.sp2013.dev.local/personal/sp_searchcontent...None http://portal.sp2013.dev.local...1 MyCompany.Intranet.WebParts.wsp...Done http://portal.sp2013.dev.local/search...1 MyCompany.Intranet.Search.wsp...Done http://portal.sp2013.dev.local/sites/appcat...None http://portal.sp2013.dev.local/sites/community...None http://portal.sp2013.dev.local/sites/developer...None http://portal.sp2013.dev.local/sites/project...None http://portal.sp2013.dev.local/sites/team...None MyCompany.Intranet.WebParts.wsp...Done Saving Apps to (C:\Users\sp_admin\temp\20141009\Apps http://my.sp2013.dev.local...None http://my.sp2013.dev.local/personal/sp_admin...None http://portal.sp2013.dev.local...1 OneNoteClassNotebookCreator.app...Done http://portal.sp2013.dev.local/Docs...None http://app-5cb2120e29a29f.app.dev.local/edu1note...None http://portal.sp2013.dev.local/News...2 OneNoteClassNotebookCreator.app...Done MyNewsApp.app...Done http://portal.sp2013.dev.local/SearchCenter...None http://portal.sp2013.dev.local/SiteDirectory...None http://portal.sp2013.dev.local/Wiki...None http://portal.sp2013.dev.local/search...None http://portal.sp2013.dev.local/sites/appcat...None http://portal.sp2013.dev.local/sites/community...None http://portal.sp2013.dev.local/sites/developer...None http://portal.sp2013.dev.local/sites/project...None http://portal.sp2013.dev.local/sites/team...1 OneNoteClassNotebookCreator.app...Done Finished
Without further ado, her comes the complete script
### ### Exports all SharePoint farm solutions, sandboxed solutions and apps to the file system ### Author: Matthias Einig, http://www.twitter.com/mattein ### Url: http: www.spcaf.com ### Add-PSSnapin Microsoft.SharePoint.PowerShell Write-Host "Exporting SharePoint Customizations" # Preparation: (re)create folder named after the current date to collect all customizations $foldername = (Get-Date -Format "yyyyMMdd").ToString() rmdir $foldername -Recurse -ErrorAction SilentlyContinue $basePath = (mkdir $foldername).FullName # Collect all disposable objects Start-SPAssignment -Global try { # Step 1: Save all farm solutions $ftcPath = (mkdir ($basePath +"\FullTrust")).FullName Write-Host " Saving farm solutions to $ftcPath" (Get-SPFarm).Solutions | % { Write-Host " $($_.Name)..." -NoNewline try{ $_.SolutionFile.SaveAs($ftcPath + "\" + $_.Name) Write-Host -ForegroundColor Green "Done" } catch{ Write-Host -ForegroundColor Red "Failed" Write-Error $_.Exception.Message; } } # Step 2: Save all sandboxed solutions $sbsPath = (mkdir($basePath +"\Sandboxed")).FullName Write-Host " Saving sandboxed solutions to $sbsPath" # Get all accessible SharePoint sites in the farm # Warning: this might take a while, so consider to limit it to specific sites # Also it might retrieve duplicate solutions (in different versions) form different sites Get-SPSite -limit All -WarningAction SilentlyContinue | % { Write-Host " $($_.Url)..." -NoNewline try{ $listTemplate = [Microsoft.SharePoint.SPListTemplateType]::SolutionCatalog $solGallery = $_.GetCatalog($listTemplate) if($solGallery.ItemCount -gt 0) { Write-Host -ForegroundColor Green $solGallery.ItemCount # create subfolder for site with safe folder name removing the protocol and special chars $subfolder = [RegEx]::Replace($_.Url.Substring($_.url.IndexOf(":")+3), "[{0}]" -f ([RegEx]::Escape([String][System.IO.Path]::GetInvalidFileNameChars())), '') $sitePath = (mkdir ($sbsPath +"\"+ $subfolder)).FullName # save all sandboxed solutions of this site $solGallery.Items | % { Write-Host " $($_.File.Name)..." -NoNewline try{ [System.IO.FileStream]$outStream = New-Object System.IO.FileStream(($sitePath+"\"+$_.File.Name), [System.IO.FileMode]::Create); $fileData = $_.File.OpenBinary(); $outStream.Write($fileData, 0, $fileData.Length); $outStream.Close(); Write-Host -ForegroundColor Green "Done" } catch{ Write-Host -ForegroundColor Red "Failed" Write-Error $_.Exception.Message; } } } else{ Write-Host "None" } } catch{ Write-Host -ForegroundColor Red "Failed" Write-Error $_.Exception.Message; } } # Step 3: Save all SharePoint Apps $appPath = (mkdir($basePath +"\Apps")).FullName Write-Host " Saving Apps to $appPath" # Get all accessible SharePoint webs in the farm # Warning: this might take a while, so consider to limit it to specific sites # Also it might retrieve duplicate solutions (in different versions) form different sites Get-SPSite -Limit All -WarningAction SilentlyContinue | Get-SPWeb -Limit All -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | % { Write-Host " $($_.Url)..." -NoNewline try{ $instances = Get-SPAppInstance -Web $_.Url if($instances.Count -gt 0) { Write-Host -ForegroundColor Green $instances.Count # create subfolder for web with safe folder name removing the protocol and special chars $subfolder = [RegEx]::Replace($_.Url.Substring($_.url.IndexOf(":")+3), "[{0}]" -f ([RegEx]::Escape([String][System.IO.Path]::GetInvalidFileNameChars())), '') $webPath = (mkdir ($appPath +"\"+ $subfolder)).FullName # export all apps foreach ($instance in $instances) { # create safe file name $filename = [RegEx]::Replace($instance.Title, "[{0}]" -f ([RegEx]::Escape([String][System.IO.Path]::GetInvalidFileNameChars())), '')+".app" Write-Host " $filename..." -NoNewline try{ Export-SPAppPackage -App $instance.App -Path ($webPath + "\"+ $filename) Write-Host -ForegroundColor Green "Done" } catch{ Write-Host -ForegroundColor Red "Failed" Write-Error $_.Exception.Message; } } } else{ Write-Host "None" } } catch{ Write-Host -ForegroundColor Red "Failed" Write-Error $_.Exception.Message; } } } finally{ #Cleanup disposable objects Stop-SPAssignment -Global Write-Host "Finished" }
The entire script can be downloaded from GitHub
Great, what now?
Now that you have extracted all code customizations you might wonder what to do with them.
» Read on at “SharePoint health check (3): Auditing Customizations”