We ware asked to enable a new rule that site/sub site cannot be deleted if any document declared as record. Of course I have added new web deleting event receiver and used a web scoped feature to register the event on web.
But we have more than 100000 sub sites in our SharePoint farm. And enabling web scoped feature for all existing sites became a risk and performance hit.
I had created two scripts to resolve this issue. 1. PS script to collect all site collection from a web application and store it in a XML file. 2. PS script will read the XML file and process the site collection one by one as we got a provision to pass number site to be processed at one time. It reduced the performance hit and trace issue if any feature failed to activate
PowerShell script to Fetch All Site Collection:
# This script to generate XML file which contains all site collections in web application
# .\1_GetsiteCollections.ps1 -url "http://kmsnet:5500/"
param
(
[string]$url # Web application URL
)
If ((Get-PSSnapIn -Name Microsoft.SharePoint.PowerShell -ErrorAction Stop) -eq $null )
{ Add-PSSnapIn -Name Microsoft.SharePoint.PowerShell }
#Start-Transcript
if($url)
{
[string]$filepath = $(get-location).Path;
# XML file generation code
$ErrorActionPreference = "SilentlyContinue"
#$ErrorActionPreference = "Stop"
# Create a new XML File with config root node
[System.XML.XMLDocument]$oXMLDocument=New-Object System.XML.XMLDocument
# New Node
[System.XML.XMLElement]$oXMLRoot=$oXMLDocument.CreateElement("SiteCollection")
# Append as child to an existing node
$oXMLDocument.appendChild($oXMLRoot)
$site = get-spsite $url
$WebApp = $site.webapplication
$Count =0;
try
{
foreach ($spsite in $WebApp.sites)
{
[System.XML.XMLElement]$oXMLSystem=$oXMLRoot.appendChild($oXMLDocument.CreateElement("site"))
$Count +=1;
$oXMLSystem.SetAttribute("Count",$($Count))
$oXMLSystem.SetAttribute("URL",$($spsite.Url))
$oXMLSystem.SetAttribute("GUID",$($spsite.ID))
$oXMLSystem.SetAttribute("Status","New")
}
$xmlPath=$filepath + "\SiteCollXML";
New-Item -force -ItemType directory -Path $xmlPath;
$Filename = $filepath + "\SiteCollXML\SiteURL.xml"
$oXMLDocument.Save($Filename )
Write-host " Site collection file is generated : " $Filename
}
catch
{
# $Error;
$ErrorMessage = $_.Exception.Message
write-host $ErrorMessage
$FailedItem = $_.Exception.ItemName
write-host $FailedItem
}
}
else
{
Write-host "Please provide the Web Application Url...!!!" -foregroundcolor "Yellow"
}
PowerShell Script to process each site collection.
# .\2_EnableWebScopedFeature.ps1 -count 5 -Enable Y -FeatureId "12f73b57-1db8-4272-9d95-d8c1cc9f3d41"
param
(
[int]$count =$(throw "Count is mandatory, please provide a value."), # No. of site collections to be processed
[string]$Enable =$(throw "Pass y/Y to Activate the feature else pass n/N to deactivate the deature"),
[string]$FeatureId =$(throw "Pass feature Id")
)
Start-Transcript
If ((Get-PSSnapIn -Name Microsoft.SharePoint.PowerShell -ErrorAction Stop) -eq $null )
{ Add-PSSnapIn -Name Microsoft.SharePoint.PowerShell }
write-host "Successfully added SharePoint PowerShell snapins"
#$ErrorActionPreference = "Stop"
$ErrorActionPreference = "SilentlyContinue"
$curDir=$(get-location).Path;
$LogTime = Get-Date -Format yyyy-MM-dd_h-mm
$LogFile = $curDir + "\Logs1-$LogTime.txt"
$DocIDFile = $curDir + "\Log2-$LogTime.txt"
write-host "Log file Location : " $LogFile
$filePath = $curDir + "\SiteCollXML\SiteURL.xml"
#write-host "source XMl file Path is $filePath "
write-host " Doc Id file " $DocIDFile
$SiteCollectionsXML = [xml](gc $filePath)
try
{
write-host "$count number of site collection requested to process";
$currentcount = 0
$DocIDcount = 0
$SiteCollectionsXML = [xml](gc $filePath)
$newItems=$SiteCollectionsXML.SiteCollection.site | where { $_.Status -eq "New"}
$node="";
foreach ($sColl in $newItems)
{
if ([int]$currentcount -lt $count)
{
write-host "Start: Site Collection ";
try
{
$currentcount = $currentcount + 1
$node = $SiteCollectionsXML.SiteCollection.site | where {$_.GUID -eq $sColl.GUID}
$node.Status = "New"
$objsite = Get-SPSite $sColl.URL;
if($Enable -eq "Y" -and $Enable -eq "y")
{
$objsite | Get-SPWeb -limit all | ForEach-Object {Enable-SPFeature -Identity $FeatureId -Url $_.Url -Confirm:$false -ErrorAction:SilentlyContinue -Force}
$node.Status = "Feature Activated"
}
if($Enable -eq "N" -and $Enable -eq "n")
{
$objsite | Get-SPWeb -limit all | ForEach-Object {Disable-SPFeature -Identity $FeatureId -Url $_.Url -Force -Confirm:$false -ErrorAction:SilentlyContinue}
$node.Status = "Feature Dectivated"
}
$objsite.Dispose();
}
catch
{
$ex = $_.Exception
$node.Status = "Failed to Activate: $ex.Message"
Write-Error "Error on $siteURL details: $ex.Message"
continue
}
finally
{
$objsite.Dispose();
$SiteCollectionsXML.Save($filePath);
}
}
}
$SiteCollectionsXML.Save($filePath)
}
catch
{
$ErrorMessage = $_.Exception.Message
write-host $ErrorMessage
$FailedItem = $_.Exception.ItemName
write-host $FailedItem
$node = $SiteCollectionsXML.SiteCollection.site | where {$_.GUID -eq $Guid}
$node.Status = "Error"
Add-Content -path $LogFile -value ("`n" + "Site URL : " + ($SiteCollectionUrl) + ' Site GUID : ' + ($Guid) + ' Error: ' + ($ErrorMessage) )
$SiteCollections.Save($filePath)
}
Stop-Transcript
XML Output
<SiteCollection>
<site Count="1" URL="http://kmsnet:5500" GUID="870c5dbb-c1b8-417a-89b3-c428369b7e45" Status="Feature Activated" />
<site Count="2" URL="http://kmsnet:5500/SC1/" GUID="888b3fd3-48a1-41c5-b1c9-bd5b9102b29f" Status="Feature Activated" />
<site Count="3" URL="http://kmsnet:5500/SC2" GUID="9f6f0d3b-1e02-42e0-8fbd-070b298576dc" Status="Feature Activated" />
</SiteCollection>