Thursday, December 13, 2012

PowerShell Script to Create Search Scopes - SharePoint 2010

Manually creating search scopes is time consuming when the number of scopes and rules are large. PowerShell comes handy in this situation and following is an example script which creates search scopes based on an xml file.

Scenario: I have a root site collection and within that there are sub-sites for four states. Search scopes need to be created in a way that searching from a state should not return data from any other state but from the current state and any sub-site in the root level and current state site. Also data from custom lists need to be skipped.

Site Structure







StateSites.xml
<StateSites>
  <State name="Alberta" url="/alberta" />   
  <State name="Manitoba" url="/manitoba" />           
  <State name="Massachusetts" url="/massachusetts" />        
  <State name="Ontario" url="/ontario" />                    
</StateSites>

Following PowerShell script takes Search Service Application name and web application URL as inputs, read the ‘StateSites.xml’ and creates search scopes for each state mentioned in the XML file, in this case four scopes called ‘Alberta’, ‘Manitoba’, ‘Massachusetts’, and ‘Ontario’. Each scope contains rules to check the root URL and then exclude other states and list data.


#----------------------------------------------------
[string]$AdminServiceName = "SPAdminV4"
[string]$webAppUrl = "http://derdev02:40920"
[string]$SSAName = "Search Service Application"
[string]$scopeXML = "C:\SearchScopes\StateSites.xml"

function read-XML()
{
 try
 {
  Write-Host -f green "Creating Scopes...`n"
  if([string]::IsNullOrEmpty($scopeXML))
  {
   return
  }

  [xml]$scopeFile = Get-Content $scopeXML
  if($scopeFile -eq $null)
  {  
   return
  }
 
  $statesList = $scopeFile.StateSites.State
  foreach ($statenode in $statesList)
  {
   if($statenode -ne $null)
   {
    [string]$stateName = $statenode.Name
    [string]$stateUrl = $statenode.url
 
    write-host "Creating scope `'$stateName`'"
    CreateNew-ScopeState $stateName
   }
  } 
 }
 catch
 {
  Write-Host -red "Exception found"
  write-Host $_.exception.Message
 }
}

function CreateNew-ScopeState([string]$scopeName)
{  
 try
 {
  $SSA=Get-SPEnterPriseSearchServiceApplication -Identity $SSAName
  $newScopeDescription = "State - $scopeName"
  $scope=Get-SPEnterpriseSearchQueryScope -Identity $scopeName -SearchApplication $SSA -ea "silentlycontinue"
  $createdScope = $null

  if($scope -eq $null)
  {
   $createdScope = New-SPEnterpriseSearchQueryScope -Name $scopeName -Description $newScopeDescription -SearchApplication $SSA -DisplayInAdminUI $true
  }
  else
  {
   write-host -f yellow "`'$scopeName`' Scope already exists, now deleting and creating"
   Remove-SPEnterpriseSearchQueryScope -Identity $scopeName -SearchApplication $SSA -confirm:$false
   $createdScope = New-SPEnterpriseSearchQueryScope -Name $scopeName -Description  $newScopeDescription -SearchApplication $SSA -DisplayInAdminUI $true
  }
  $rule = New-SPEnterpriseSearchQueryScopeRule -RuleType "Url" -Url $webAppUrl -MatchingString "$webAppUrl/" -FilterBehavior "Require" -UrlScopeRuleType "Folder" -scope $createdScope
 
  [xml]$scopeFile = Get-Content $scopeXML
  if($scopeFile -eq $null)
  {  
   return
  }
  $statesList = $scopeFile.StateSites.State
  foreach ($statenode in $statesList)
  {
   if($statenode -ne $null)
   {
    [string]$stateName = $statenode.Name
    [string]$stateUrl = $statenode.url
    if($stateName -ne $scopeName)
    {
     [string]$matchString = "$webAppUrl" + "$stateUrl"
     $rule = New-SPEnterpriseSearchQueryScopeRule -RuleType "Url" -Url $webAppUrl -MatchingString $matchString -FilterBehavior "Exclude" -UrlScopeRuleType "Folder" -scope $createdScope                                     
    }
   }
  }
  $rule = New-SPEnterpriseSearchQueryScopeRule -RuleType PropertyQuery -ManagedProperty "contentclass" -PropertyValue "STS_List" -FilterBehavior "Exclude" -url $webAppUrl -scope $createdScope -SearchApplication $SSA
 }
 catch [System.Exception]
 {
  Write-Host -red "Exception found"
  write-Host $_.
 }
}

#Load sharepoint snapins and start admin services if its stoped.
function Setup-PowerShellEnviornment()
{
 #Ensure Microsoft.SharePoint.PowerShell is loaded
 $snapin="Microsoft.SharePoint.PowerShell"

 if (get-pssnapin $snapin -ea "silentlycontinue") {
  write-host -f Green "PSsnapin $snapin is loaded"
 }
 elseif (get-pssnapin $snapin -registered -ea "silentlycontinue") {
  write-host -f Green "PSsnapin $snapin is registered"
  Add-PSSnapin $snapin
  write-host -f Green "PSsnapin $snapin is loaded"
 }
 else {
  write-host -f orange "PSSnapin $snapin not found" -foregroundcolor Red
 }

 #if SPAdminV4 service is not started - start it
 if( $(Get-Service $AdminServiceName).Status -eq "Stopped") {
  #$IsAdminServiceWasRunning = $false
  Start-Service $AdminServiceName
 }
}

Setup-PowerShellEnviornment
read-XML
#----------------------------------------------------

How to test: Create 2 files (.xml and .ps1) and run .ps1 file in a SharePoint environment using Windows PowerShell or SharePoint 2010 Management Shell as an administrator. Make sure to update the 3 parameter at the top of the script.

No comments: