I had to automate update of result source and query of a search result web part in a search page as part of deployment script to move changes from DEV to TEST, UAT and PROD.
The XML definition of a search result web part is
<webParts>
<webPart xmlns=”http://schemas.microsoft.com/WebPart/v3″>
<metaData>
<type name=”Microsoft.Office.Server.Search.WebControls.ResultScriptWebPart, Microsoft.Office.Server.Search, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c” />
<importErrorMessage>Cannot import this Web Part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name=”MaxPagesBeforeCurrent” type=”int”>4</property>
<property name=”ShowBestBets” type=”bool”>True</property>
<property name=”Height” type=”string” />
<property name=”AdvancedSearchPageAddress” type=”string”>advanced.aspx</property>
<property name=”AllowZoneChange” type=”bool”>True</property>
<property name=”UseSharedDataProvider” type=”bool”>False</property>
<property name=”ShowPreferencesLink” type=”bool”>True</property>
<property name=”EmptyMessage” type=”string” />
<property name=”ScrollToTopOnRedraw” type=”bool”>True</property>
<property name=”ShowDefinitions” type=”bool”>True</property>
<property name=”SelectedPropertiesJson” type=”string”>null</property>
<property name=”ShowViewDuplicates” type=”bool”>False</property>
<property name=”CatalogIconImageUrl” type=”string” />
<property name=”RepositionLanguageDropDown” type=”bool”>True</property>
<property name=”PreloadedItemTemplateIdsJson” type=”string”>[“~sitecollection/_catalogs/masterpage/Display Templates/Search/Group_Default.js”,”~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Default.js”,”~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Site.js”,”~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Word.js”,”~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_PowerPoint.js”,”~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Person_CompactHorizontal.js”,”~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_BestBet.js”,”~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_WebPage.js”]</property>
<property name=”ResultsPerPage” type=”int”>10</property>
<property name=”EmitStyleReference” type=”bool”>True</property>
<property name=”ShowPaging” type=”bool”>True</property>
<property name=”ResultTypeId” type=”string” />
<property name=”ShowUpScopeMessage” type=”bool”>False</property>
<property name=”AllowMinimize” type=”bool”>True</property>
<property name=”AllowClose” type=”bool”>True</property>
<property name=”HelpMode” type=”helpmode”>Modeless</property>
<property name=”Title” type=”string”>Search Results</property>
<property name=”ShowResults” type=”bool”>True</property>
<property name=”MaxPagesAfterCurrent” type=”int”>1</property>
<property name=”ShowResultCount” type=”bool”>True</property>
<property name=”Hidden” type=”bool”>False</property>
<property name=”ItemTemplateId” type=”string” />
<property name=”ItemBodyTemplateId” type=”string”>~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_CommonItem_Body.js</property>
<property name=”UseSimplifiedQueryBuilder” type=”bool”>False</property>
<property name=”HitHighlightedPropertiesJson” type=”string”>[“Title”,”Path”,”Author”,”SectionNames”,”SiteDescription”]</property>
<property name=”AvailableSortsJson” type=”string”>[{“name”:”Relevance”,”sorts”:[]},{“name”:”Date(Newest)”,”sorts”:[{“p”:”Write”,”d”:1}]},{“name”:”Date(Oldest)”,”sorts”:[{“p”:”Write”,”d”:0}]},{“name”:”Lifetime Views”,”sorts”:[{“p”:”ViewsLifeTime”,”d”:1}]},{“name”:”Recent Views”,”sorts”:[{“p”:”ViewsRecent”,”d”:1}]}]</property>
<property name=”DataProviderJSON” type=”string”>{“QueryGroupName”:”Default”,”QueryPropertiesTemplateUrl”:”sitesearch://webroot”,”IgnoreQueryPropertiesTemplateUrl”:false,”SourceID”:null,”SourceName”:null,”SourceLevel”:null,”CollapseSpecification”:””,”QueryTemplate”:”{searchboxquery}”,”FallbackSort”:null,”FallbackSortJson”:”null”,”RankRules”:null,”RankRulesJson”:”null”,”AsynchronousResultRetrieval”:false,”SendContentBeforeQuery”:true,”BatchClientQuery”:true,”FallbackLanguage”:-1,”FallbackRankingModelID”:””,”EnableStemming”:true,”EnablePhonetic”:false,”EnableNicknames”:false,”EnableInterleaving”:true,”EnableQueryRules”:true,”EnableOrderingHitHighlightedProperty”:false,”HitHighlightedMultivaluePropertyLimit”:-1,”IgnoreContextualScope”:false,”ScopeResultsToCurrentSite”:false,”TrimDuplicates”:true,”Properties”:{},”PropertiesJson”:”{}”,”ClientType”:”AllResultsQuery”,”UpdateAjaxNavigate”:true,”SummaryLength”:180,”DesiredSnippetLength”:90,”PersonalizedQuery”:false,”FallbackRefinementFilters”:null,”IgnoreStaleServerQuery”:true,”RenderTemplateId”:””,”AlternateErrorMessage”:null,”Title”:””}</property>
<property name=”ChromeState” type=”chromestate”>Normal</property>
<property name=”AllowHide” type=”bool”>True</property>
<property name=”AllowEdit” type=”bool”>True</property>
<property name=”StatesJson” type=”string”>{}</property>
<property name=”RenderTemplateId” type=”string” />
<property name=”ShowPersonalFavorites” type=”bool”>True</property>
<property name=”ShowSortOptions” type=”bool”>False</property>
<property name=”ChromeType” type=”chrometype”>None</property>
<property name=”AllowConnect” type=”bool”>True</property>
<property name=”HelpUrl” type=”string” />
<property name=”ShowLanguageOptions” type=”bool”>True</property>
<property name=”Description” type=”string”>Displays the search results and the properties associated with them.</property>
<property name=”ServerIncludeScriptsJson” type=”string”>null</property>
<property name=”TitleUrl” type=”string” />
<property name=”AlternateErrorMessage” type=”string” null=”true” />
<property name=”ShowAlertMe” type=”bool”>True</property>
<property name=”ShowDidYouMean” type=”bool”>True</property>
<property name=”QueryGroupName” type=”string”>Default</property>
<property name=”Width” type=”string” />
<property name=”ShowAdvancedLink” type=”bool”>True</property>
<property name=”ExportMode” type=”exportmode”>All</property>
<property name=”Direction” type=”direction”>NotSet</property>
<property name=”BypassResultTypes” type=”bool”>False</property>
<property name=”GroupTemplateId” type=”string” />
<property name=”TitleIconImageUrl” type=”string” />
<property name=”MissingAssembly” type=”string”>Cannot import this Web Part.</property>
</properties>
</data>
</webPart>
</webParts>
The webpart property DataProviderJSON needs to be updated. The property is in Json format which is converted to JSON using PowerShell ConvertFrom-Json method. The PowerShell ConvertTo-Json method is used to convert back to JSON before updating the “DataProviderJSON ” property.
The properties SourceId and SourceName refer to the result source.
On SharePoint On Premises environment , the SourceId can be found from navigating to central administration>Manage Service Applications>Search Service application>Result Sources.
The format of the URL is http:///_admin/search/EditResultSourceSSA.aspx?level=service&appid={c21b4115-4e78-4d93-a4e7-24a9472c9b19}&sourceid=886883b4%2Db44c%2D4870%2Da0ff%2D1c0f81b2d9c8
In SharePoint Online, navigate to SharePoint Admin>Search>Manage Result sources and click on the result source you wish to find Id. The URL format is
https://-admin.sharepoint.com/_layouts/15/searchadmin/EditResultSource.aspx?level=tenant&sourceid=203fba36-2763-4060-9931-911ac8c0583b&view=1
Extract and decode the sourceid parameter from the url.
To update the query text, the QueryTemplate needs to be changed. In the example below it is set to value “contentclass:STS_Web contentclass:STS_Site -SPSiteURL:personal {searchboxquery}” which means returns all sites or web based on the search criteria.
Referring to my post “Add Refiners to Refinement web part“, I had to write a script in PowerShell using CSOM SharePoint assemblies to update the result web part property DataProviderJSON.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function GetWebPartByTitle() | |
{ | |
param( | |
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)] | |
[Microsoft.SharePoint.Client.WebParts.WebPartDefinitionCollection] $webParts, | |
[Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)] | |
[string] $webPartTitle | |
) | |
if($webparts.Count -gt 0){ | |
Write-Host "Looping through all webparts" | |
foreach($wp in $webparts){ | |
$ctx.Load($wp.WebPart.Properties) | |
$ctx.ExecuteQuery() | |
$propValues = $wp.WebPart.Properties.FieldValues; | |
if($propValues["Title"] -eq $webPartTitle) | |
{ | |
return $wp; | |
} | |
} | |
} | |
return $null; | |
} | |
#return webpart based on title passed | |
#return webpart based on title passed | |
function UpdateSearchResultsDataProviderWebPart | |
{ | |
param( | |
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)] | |
[Microsoft.SharePoint.Client.ClientContext]$ctx, | |
[Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)] | |
[string]$pageUrl | |
) | |
$web = $ctx.Web; | |
$page = $web.GetFileByServerRelativeUrl($pageUrl); | |
$ctx.Load($web); | |
$ctx.Load($page); | |
$ctx.ExecuteQuery(); | |
#Check if page already checked out. If so, undo check out | |
if($page.CheckOutType -eq [Microsoft.SharePoint.Client.CheckOutType]::Online){ | |
try{ | |
Write-Host "Undo Checkout" | |
$page.UndoCheckOut() | |
$ctx.load($page) | |
$ctx.ExecuteQuery() | |
} | |
catch{ | |
write-host "Error in checkout.. $($_.Exception.Message)" -foregroundcolor red | |
} | |
} | |
#If page is not checked out, then check out | |
if($page.CheckOutType -eq [Microsoft.SharePoint.Client.CheckOutType]::None){ | |
Write-Host "Checkout" | |
$page.CheckOut() | |
$ctx.Load($page) | |
$ctx.ExecuteQuery() | |
} | |
# Find the Search Results web part | |
$lwpm =$page.GetLimitedWebPartManager([Microsoft.SharePoint.Client.WebParts.PersonalizationScope]::Shared); | |
$webParts = $lwpm.WebParts; | |
$ctx.Load($webParts); | |
$ctx.ExecuteQuery(); | |
$rwp = GetWebPartByTitle -webParts $webParts -webPartTitle 'Search Results' | |
$dataProviderjson = $rwp.WebPart.Properties["DataProviderJSON"] | ConvertFrom-Json | |
$dataProviderjson.SourceId = "886883b4-b44c-4870%2Da0ff-1c0f81b2d9c8" | |
$dataProviderjson.SourceName = "Local SharePoint Results" | |
$dataProviderjson.QueryTemplate = "contentclass:STS_Web contentclass:STS_Site -SPSiteURL:personal {searchboxquery}" | |
$rwp.WebPart.Properties["DataProviderJSON"] = ConvertTo-Json $dataProviderjson -Compress | |
# Save the changes | |
$rwp.SaveWebPartChanges(); | |
$page.CheckIn('Changed search result web part', [Microsoft.SharePoint.Client.CheckinType]::MajorCheckIn) | |
$page.Publish('Changed search result web part'); | |
$ctx.load($page); | |
$ctx.ExecuteQuery(); | |
} | |
Use the following script to call function UpdateSearchResultsDataProviderWebPart .
$ctx=New-Object Microsoft.SharePoint.Client.ClientContext($SiteCollectionUrl);
$ctx.Credentials = New-Object System.Net.NetworkCredential($Username, $password);
$rootWeb = $ctx.Web
$ctx.Load($rootWeb)
$ctx.ExecuteQuery();
UpdateSearchResultsDataProviderWebPart -ctx $ctx -pageUrl "/Search/Pages/SiteDirectory.aspx"