SharePoint 2013 Hybrid Search: Create result Source & Query Rule - Automation

 

I know the topic starts with Hybrid Search for SharePoint 2013. But this blog is not about configuring end-to-end Hybrid Search.

The Parent blog is https://blogs.msdn.com/b/spses/archive/2013/10/22/office-365-configure-hybrid-search-with-directory-synchronization.aspx

 

I was in process of automating the whole Hybrid process (most of the steps atleast from SharePoint using PowerShell).

The blog by Manas has most of the steps with scripts. However there are some manual steps involved too.

Thos steps are:

1. Creating a Result Source

2. Creating the Query Rule.

I wrote some scripts to create the result Source & the Query Rule.

Script to create the Result Source:

 #**************************************************************************************
# Input Arguments
#**************************************************************************************

param([Parameter(Mandatory=$true)] [string]$RemoteSharePointUrl, [Parameter(Mandatory=$true)] [string]$ResultSourceName );


#**************************************************************************************

#**************************************************************************************
# References and Snapins
#**************************************************************************************

if(-not (Get-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue))
{
    Add-PSSnapin Microsoft.SharePoint.PowerShell -ea SilentlyContinue;
}

#**************************************************************************************

#**************************************************************************************
# Variable and Constants
#**************************************************************************************
$startTime=$(Get-Date);
if($debug)
{
    $RemoteSharePointUrl = "https://myspo.sharepoint.com";
    $ResultSourceName = "SharePoint Online";
    
}

$ProviderID = "1e0c8601-2e5d-4ccb-9561-53743b5dbde7";
$logDir = $myinvocation.mycommand.path.Replace($MyInvocation.MyCommand.name,"") + "\logs\";
$logFile = $logDir + $(Get-Date -format "dd_MM_yyyy_HH_mm_ss") + '.log';

if (!(test-path $logDir)) 
{
    $dir = New-Item -ItemType directory -Path $logDir;
    $file = New-Item -ItemType file $logFile;

}
else
{
    if (!(test-path $logFile)) 
    {        
        $file = New-Item -ItemType file $logFile;
    }
}
#**************************************************************************************
# Primary Statement Blocks
#**************************************************************************************

try
{
    #Get the Search Service Appliaction 
    $SSA = Get-SPEnterpriseSearchServiceApplication ;
    "Search Service Applicaion Object initialized " >> $logFile;

    #Get the Search Service Appliaction Owner
    $SSAOwner = Get-SPEnterpriseSearchOwner -Level SSA ;
    "Search Service Applicaion Owner initialized " >> $logFile;

    $hash = @{            
            Name = $ResultSourceName;                
            Protocol = "Remote SharePoint";            
            Type = "SharePoint Search Results";
            RemoteSiteURL = $RemoteSharePointUrl;
            ProviderID = $ProviderID;
            QueryTemplate = "{searchTerms}";
            Credentials = "Default";
            SearchServiceApplication = $SSA.Name;
        }                           

    $resultObj = New-Object PSObject -Property $hash ;

    "Trying to find if the result source exists......." >> $logFile;
    #Try getting the result source
    $resultSource = Get-SPEnterpriseSearchResultSource -Owner $SSAOwner -SearchApplication $SSA -Identity $ResultSourceName;

    #Resul source does not exists, create one
    if(-not $resultSource)
    {
        
        Write-Host -ForegroundColor White "Result Source not found.... Creating Result Source .....";
        Write-Host -ForegroundColor White "Creating Result Source with values ";
        "Result Source not found.... Creating Result Source ....." >> $logFile;
        "Creating Result Source with values " >> $logFile;
        
        $resultObj;
        $resultObj >> $logFile;
        try
        {
            $resultSource = New-SPEnterpriseSearchResultSource -Name $ResultSourceName -Owner $SSAOwner -ProviderId $ProviderID -SearchApplication $SSA -RemoteUrl $RemoteSharePointUrl;    
            Write-Host -ForegroundColor Green "Success !! ";
            Write-Host -ForegroundColor Green "Created result Source $ResultSourceName";

            "Success !! Created result Source $ResultSourceName" >> $logFile

            Write-Host;
            Write-Host -ForegroundColor DarkCyan "************ Verification Step ***********";
            Write-Host -ForegroundColor DarkCyan "Result Source Properties ";
            $resultSource ;
            Write-Host -ForegroundColor DarkCyan "************ Verification Complete ***********";

            "************ Verification Step ***********" >> $logFile;
            $resultSource >> $logFile;

        }
        catch
        {
            Write-Host -ForegroundColor Red $_;
            "Error : $_ ">> $logFile;
        
        }
    }
    else
    {
        Write-Host -ForegroundColor Yellow "Duplicate Result Source exists !! No action taken...."  ;
        "Duplicate Result Source exists !! No action taken...." >> $logFile;
        Write-Host;
        Write-Host -ForegroundColor DarkCyan "************ Verification Step ***********";
        Write-Host -ForegroundColor DarkCyan "Result Source Properties ";
        $resultSource ;

        "************ Verification Step ***********" >> $logFile;
        $resultSource >> $logFile;
    }
    

}
catch
{
    Write-Host -ForegroundColor Red $_;
    "Error : $_ ">> $logFile;
}

$endTime=$(Get-Date);
Write-Host -ForegroundColor Yellow "Processed the script in $(($endTime-$startTime).TotalSeconds) seconds .......";

"Ending Transcript..." >> $logFile;

Script to create the Query Rule:

 

 #**************************************************************************************
# Input Arguments
#**************************************************************************************

param([Parameter(Mandatory=$true)] [string]$queryRuleName, [Parameter(Mandatory=$true)] [string]$resultSourceName );


#**************************************************************************************

#**************************************************************************************
# References and Snapins
#**************************************************************************************

if(-not (Get-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue))
{
    Add-PSSnapin Microsoft.SharePoint.PowerShell -ea SilentlyContinue;
}

#**************************************************************************************

#**************************************************************************************
# Variable and Constants
#**************************************************************************************
$startTime=$(Get-Date);
$debug = $false;
if($debug)
{
    $queryRuleName = "SharePoint Online QR - 2";
    $resultSourceName = "SharePoint Online";
}

$logDir = $myinvocation.mycommand.path.Replace($MyInvocation.MyCommand.name,"") + "\logs\";
$logFile = $logDir + $(Get-Date -format "dd_MM_yyyy_HH_mm_ss") + '.log';

if (!(test-path $logDir)) 
{
    $dir = New-Item -ItemType directory -Path $logDir;
    $file = New-Item -ItemType file $logFile;

}
else
{
    if (!(test-path $logFile)) 
    {        
        $file = New-Item -ItemType file $logFile;
    }
}


#**************************************************************************************
# Primary Statement Blocks
#**************************************************************************************

try
{

    Write-Host -ForegroundColor White "Srcipt execution started ... ";

    #Get the Search Service Appliaction 
    $SSA = Get-SPEnterpriseSearchServiceApplication ;
    "Search Service Applicaion Object initialized " >> $logFile;

    #Get the Search Service Appliaction Owner
    $SSAOwner = Get-SPEnterpriseSearchOwner -Level SSA ;
    "Search Service Applicaion Owner initialized " >> $logFile;

    $resultSource = Get-SPEnterpriseSearchResultSource -Owner $SSAOwner -SearchApplication $SSA -Identity $resultSourceName;

    if($resultSource)
    {
        Write-Host ;
        Write-Host -ForegroundColor White "Result Source Object with name $resultSourceName found.. Continuing to create the rule for the source ...";
        Write-Host ;
        "Result Source Object found.. Continuing to create the rule for the source ..." >> $logFile;
        $resultSource >> $logFile;
        "" >> $logFile;

        $hash = @{            
                    Name = $resultSourceName;
                    SearchServiceApplication = $SSA.Name;
                 }                           

        $resultObj = New-Object PSObject -Property $hash ;

        #Get the Query Rule Manager
        $QueryRuleManager = New-Object Microsoft.Office.Server.Search.Query.Rules.QueryRuleManager($SSA);
         "Query Rule Manger object created ..." >> $logFile;


        # Create a search object filter using a $SearchOwner object  (Site collection level - in this case)
        $SearchObjectFilter =  New-Object Microsoft.Office.Server.Search.Administration.SearchObjectFilter($SSAOwner);

        $QueryRules = $QueryRuleManager.GetQueryRules($SearchObjectFilter);
        "Searching the query rules to find a duplicate...." >> $logFile;

        $queryRule = $QueryRules | Where-Object{$_.DisplayName -eq $queryRuleName };
        
        
        # Create a new rule as a active one if does not exists
        if(-not $queryRule)
        {
            Write-Host -ForegroundColor White "Creating New Query Rule with Name  $queryRuleName";
             "Creating New Query Rule .... " >> $logFile;
            
            $queryRule = $QueryRules.CreateQueryRule($queryRuleName,$null,$null,$true);
            
            #Add the Result Source..
            $QuerySourceContextCondition = $QueryRule.CreateSourceContextCondition($resultSource);

            # Create result block for the Query Rule
            $QueryRuleAction = $QueryRule.CreateQueryAction([Microsoft.Office.Server.Search.Query.Rules.QueryActionType]::CreateResultBlock);

            #Set the values as seen when creating through UI.
            $QueryRuleAction.QueryTransform.OverrideProperties = New-Object Microsoft.Office.Server.Search.Query.Rules.QueryTransformProperties;
            $QueryRuleAction.QueryTransform.SourceId = $resultSource.Id;
            $QueryRuleAction.QueryTransform.QueryTemplate = "{subjectTerms}";
            $QueryRuleAction.ResultTitle.DefaultLanguageString = 'Results for "{subjectTerms}"';
            $QueryRuleAction.GroupTemplateId = "~sitecollection/_catalogs/masterpage/Display Templates/Search/Group_Default.js";
            $QueryRuleAction.AlwaysShow = $true;

            #Update the object
            $QueryRule.Update();

            Write-Host -ForegroundColor Green "Success !! New Query Rule Created ...";
            Write-Host ;
           
            "Success: New Query Rule created.. "  >> $logFile;
            "" >> $logFile;

            
        }
        else
        {
            Write-Host -ForegroundColor Yellow "Dupliacte Query Rule found.. No action taken ...";
            Write-Host ;
            "No Action: Dupliacte Query Rule found.. No action taken ...">> $logFile;
            $QueryRule  >> $logFile;
        }

        Write-Host -ForegroundColor DarkCyan "************ Verification Step ***********";
        Write-Host -ForegroundColor DarkCyan "Query Rule Properties ";

        $QueryRule | fl;
            
        Write-Host -ForegroundColor DarkCyan "************ Verification Complete ***********";
            
        "************ Verification Step ***********" >> $logFile;
        $QueryRule  >> $logFile;
        "************ Verification Complete ***********" >> $logFile;
    }
    else
    {
        Write-Host -ForegroundColor Yellow "Result Source with the name - $resultSourceName not found .. Query Rule not created ...";
        "No Action: Result Source with the name - $resultSourceName not found .. Query Rule not created ..."  >> $logFile;
    }
    
}
catch
{
    Write-Host -ForegroundColor Red $_;
    "Error: $_ "  >> $logFile;
}

$endTime=$(Get-Date);
Write-Host -ForegroundColor Yellow "Processed the script in $(($endTime-$startTime).TotalSeconds) seconds .......";

"Ending Transcript..." >> $logFile;

 

N.B. – Query Rules can be very complicated and can have different combinations. The above script creates the Query Rule as mentioned in the blog by Manas for Hybrid Search.

HybridSearch -Automation.zip