Thursday, November 19, 2015

SharePoint 2013 Result Source Only Include Content From Current Site NOT Sub Sites

Hello Blog Readers,

Sorry for the delay in posts recently things at work in terms of projects, but I did have an extremely helpful Result Source Syntax you should know!  From the title of this blog article you have probably guessed what I will discuss, how to actually only search on the current site!

I can’t believe how many copy and paste blogs are out there since everyone’s “solution” of Path:{Site} or Path:{Site.URL} does not work!  I was so frustrated after clicking through pages of Google links (dear god I made it to page 3… where results go to die) that I just sat down and tried to figure out a solution myself.
For those of you who don’t want the journey or explanation the key to your success is to include this as part of your query:
WebId={Site.ID}

Why is The Path Solution Incorrect?
The Path solution is incorrect since Path:{Site} will include any content from your sub sites which matches the criteria.  This is because the child sites includes the path of the parent site, which means you will always get the data from the sub sites which inherit from the parent’s Path.  You may be thinking well Dan, why don’t you just use Path={Site} instead of contains.  If you have tried this syntax on its own, you most likely only received the Home Page of the site from which you were running the query from.  Content within the site obviously does not have the URL of the homepage, so using equals will only return the one page which matches the path exactly.  In short, you can use Path:{Site} when you are trying to exclude contents from parent sites, but include content from the current site and it’s children.

How to Return Results ONLY From the Current Site:
To only obtain results from the site from which the query is being run, WebId={Site.ID} should be used.  WebId is an out of the box managed property which houses the site’s GUID  / ID, so essentially what we are saying in the above is that we want to only return items where the WebId is equal to the current site’s GUID/ID from which the query is being issued from.

Simple Example Query:
SPContentType=”Item” AND WebId={Site.ID}

This query will only retrieve items which match the item content type display name and where the WebId is equal to the current sites GUID / ID.  If you were to try this same query from a top level site utilizing Path:{Site} instead of WebId, like the other blogs and sites suggest, you will retrieve Items with this content type from all of the sub sites beneath this path.  The query above will ONLY return items from the current site J
Best of Luck!

Dan

Monday, July 27, 2015

Apply a Retention Policy to a Set of Content Types Via PowerShell

Hello Readers!

Recently it seems that I have been doing more and more PowerShell, this time I needed to apply a retention policy to a set of Content Types.  In order to do this I wrote a PowerShell script which checks all of the content types within your site against a list of content types stored in an array.  If the content type name matches the name within the array we apply the policy.  My policy is extremely simple and simply marks the item as a record when today is equal to my field ExpirationDate.

Many users will need a policy much more robust than this and my advice is to download SharePoint 2013 manager in order to create them https://spm.codeplex.com/.  With SharePoint Manager 2013 you can open an existing policy that you have made via the GUI and extract the XML.  The script needs the XML markup in order to create the policy and writing it by hand is horrible!

So you may be wondering, what do I need to change?  The only parts of the script which would require modification would be the content type names within $parentCtypes and the XML for the retention policy.  After you have updated the XML for your policy and selected which Content Types to apply the policy to, you simply need to run the script.  The script will prompt you for the root site collection URL.

I actually struggled the most with trying to decipher the correct markup of the XML, the script itself was actually pretty simple.  Again, in order to get the markup for the policy I would create it via the GUI and then find the policy with SharePoint 2013 Manager and view the XML for the policy, it is way easier with a copy paste!  I wasted a ton of time trying to write the XML from scratch and advise you not to do the same!

param($url = $(Read-Host -prompt "Root Site Collection Path"))

#Get the PowerShell Snapin
Add-PSSnapin "Microsoft.SharePoint.PowerShell"

#Search Service Application
$ssa = Get-SPEnterpriseSearchServiceApplication
Write-Host $ssa.Name -ForegroundColor Magenta

#Get Site
$site = Get-SPSite $url

#Get Root Web
$web = $site.RootWeb

#Write Out That The Web Was Found
if($web -ne $null)
{
    Write-Host "The web is" $web "and the site is" $site.HostName -ForegroundColor Magenta

}

#Fill the array with base content types i.e. Exelon Content Page
$parentCtypes = @("Content Page");

foreach ($ctype in $web.ContentTypes)
{
    foreach($i in $parentCtypes)
    {
        if($ctype.Name -eq $i)
        {
            Write-Host $ctype.Name "is the same as" $i -ForegroundColor Magenta
            $ctypePolicy = [Microsoft.Office.RecordsManagement.InformationPolicy.Policy]::GetPolicy($ctype);
            if($ctypePolicy -ne $null)
            {
                Write-Host $ctype.Name "Has an existing Policy" $ctypePolicy "and is being deleted" -ForegroundColor Magenta
                [Microsoft.Office.RecordsManagement.InformationPolicy.Policy]::DeletePolicy($ctype);
            }
            [Microsoft.Office.RecordsManagement.InformationPolicy.Policy]::CreatePolicy($ctype, $null);
            $ctypePolicy = [Microsoft.Office.RecordsManagement.InformationPolicy.Policy]::GetPolicy($ctype);
            $ctypePolicy.Items.Add("Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration",
                "<Schedules nextStageId='2'>"+
                    "<Schedule type='Default'>"+
                        "<stages>"+
                            "<data stageId='1'>"+
                                "<formula id='Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Formula.BuiltIn'>"+
                                    "<number>0</number>"+
                                    "<property>ExpirationDate</property>"+
                                    "<propertyId>8c06beca-0777-48f7-91c7-6da68bc07b69</propertyId>"+
                                    "<period>days</period>"+
                                "</formula>"+
                                "<action type='action' id='Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Action.Record' />"+
                            "</data>"+
                        "</stages>"+
                    "</Schedule>"+
                "</Schedules>");
                $ctypePolicy.Update();
                $ctype.Update();
            Write-Host "The Policy For" $ctype.Name "Has Been Created And Applied!" -ForegroundColor Green
        }
    }
}

Good Luck!

Dan

Thursday, April 9, 2015

SharePoint 2013: Create Result Sources With PowerShell

Hello Readers!

Sorry for the delay in posts recently, between work and personal events I have been totally swamped (in a good way)!

What I wanted to share today is PowerShell script which provisions result sources at the Site Collection level.  The script will loop through each result source within the script, check to see if it exists, if it does it will blow it away and re-create it or if it is brand new just create   This script is useful for automating deployments or if you need to create the same result sources on multiple site collections.


If you need to deploy result sources at the Search Service Application Level, simply swap out: SPSite with Ssa at our $searchOwner line.  Your site collection URL and Search Service Application are both params which will be prompted.


$searchOwner = New-Object Microsoft.Office.Server.Search.Administration.SearchObjectOwner([Microsoft.Office.Server.Search.Administration.SearchObjectLevel]::SPSite, $site.RootWeb)

The real question though, what do you need to update in order to use this script?  Luckily, the only parts you need to update are the actual result sources themselves!  This is under the Result Sources Start Here Section.  The below example is for a result source which finds anything with the ContentTypeId matching Article.  For the below section I did not need a sort order, but if you do un-comment out the sortCollection and queryProperties line.  You can swap out "Created" with the Managed property you need to sort by.  You can also swap out Descending with Ascending if desired.  The name of the result source is input between the single quotes, my example result source below will be called Articles.


# Articles
Write-Host -ForegroundColor Green "Starting To Build  Articles Result Source"
# define query and sorting
$query = "ContentTypeId:0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39003F11102A7C0343B0836EDF8DA14F33ED00B679312D96584105BCFD3A33F39BD3AF*"
$queryProperties = New-Object Microsoft.Office.Server.Search.Query.Rules.QueryTransformProperties
$sortCollection = New-Object Microsoft.Office.Server.Search.Query.SortCollection    
##This can be updated if a sort order is required
#$sortCollection.Add("Created", [Microsoft.Office.Server.Search.Query.SortDirection]::Descending) 
#$queryProperties["SortList"] = [Microsoft.Office.Server.Search.Query.SortCollection]$sortCollection
# create result source
CreateResultSource $searchOwner $fedManager ' Articles' $queryProperties $query 
Write-Host -ForegroundColor Yellow " Articles Result Source Complete"

How to use this script:
  1. Update the script to include each result source you need created, you can swap out my example result sources with your own
  2. Run the script
  3. When prompted: input your root site collection url: i.e. http://danstestsite.local
  4. When prompted: input your search service application name (make sure to put it in double quotes) i.e. "Search Service Application"
  5. Check out the new result sources at your site collection level!
Full Script:


## Getting the ducks in a row
param($url = $(Read-Host -prompt "Site Colleciton Root URL"), $ssaName = $(Read-Host -prompt "Search Service Application Name"))

#Funciton To Create Result Sources
function CreateResultSource($searchOwner, $fedManager, $name, $queryProperties, $query)
{  
   # check if result source already exists
   $resultSource = $fedManager.GetSourceByName($name, $searchOwner)

   if ($resultSource -eq $null) 
   {    
        Write-Host -f cyan "Creating Result Source <"$name">."
        
        #create result source
        $resultSource = $fedManager.CreateSource($searchOwner)      
        $resultSource.Name = $name
        $resultSource.CreateQueryTransform($queryProperties, $query)
        $resultSource.ProviderId = $fedManager.ListProviders()["Local SharePoint Provider"].Id
        $resultSource.Commit()
   }
   else
   {
        Write-Host -f Green "Result Source" $name "already exists, updating" $name "result source"

        # print properties of existing result source 
        $source = $fedManager.GetSourceByName($name, $searchOwner) 
        $fedManager.RemoveSource($source)
          #create result source
        $resultSource = $fedManager.CreateSource($searchOwner)      
        $resultSource.Name = $name
        $resultSource.CreateQueryTransform($queryProperties, $query)
        $resultSource.ProviderId = $fedManager.ListProviders()["Local SharePoint Provider"].Id
        $resultSource.Commit()
   }
   return $resultSource
}

Write-Host -ForegroundColor Green "Script Warming Up And Adding Snapins"
Add-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue

Start-SPAssignment -Global

#Get SP Site and SP Web
##$url = (Read-Host -Prompt "Site Collection URL")
$url = $url.Trim()
$web = get-spweb $url
$site = get-spsite $url -WarningAction SilentlyContinue

#Get Search Service Applicaiton
$ssa = Get-SPEnterpriseSearchServiceApplication $ssaName -ErrorAction SilentlyContinue
if($ssa -eq $null) {
    $ssa = @(Get-SPEnterpriseSearchServiceApplication)[0]
}

#Output results from SSA
Write-host -ForegroundColor Cyan ("Using search app {0}" -f $ssa.Name)

# load Search assembly
Write-Host -ForegroundColor Green "Loading Search Assemblies"
[void] [Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.Search")

# create manager instances
$fedManager = New-Object Microsoft.Office.Server.Search.Administration.Query.FederationManager($ssa)
    Write-Host -ForegroundColor Green "The fed manager is" $fedManager


#Update SPSite to Ssa if you want them provisioned at Search Service Level
$searchOwner = New-Object Microsoft.Office.Server.Search.Administration.SearchObjectOwner([Microsoft.Office.Server.Search.Administration.SearchObjectLevel]::SPSite, $site.RootWeb)
    Write-Host -ForegroundColor Cyan "The Search Owner is" $searchOwner

###################################################################################
#Result Sources Start Here
###################################################################################


# Articles
Write-Host -ForegroundColor Green "Starting To Build  Articles Result Source"
# define query and sorting
$query = "ContentTypeId:0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39003F11102A7C0343B0836EDF8DA14F33ED00B679312D96584105BCFD3A33F39BD3AF*"
$queryProperties = New-Object Microsoft.Office.Server.Search.Query.Rules.QueryTransformProperties
$sortCollection = New-Object Microsoft.Office.Server.Search.Query.SortCollection    
##This can be updated if a sort order is required
#$sortCollection.Add("Created", [Microsoft.Office.Server.Search.Query.SortDirection]::Descending) 
#$queryProperties["SortList"] = [Microsoft.Office.Server.Search.Query.SortCollection]$sortCollection
# create result source
CreateResultSource $searchOwner $fedManager ' Articles' $queryProperties $query 
Write-Host -ForegroundColor cyan " Articles Result Source Complete"


#Statistic
Write-Host -ForegroundColor Green "Starting To Build Statistic Result Source"
$query = "ContentTypeId:0x0100AAF9B8EBA36A47F6BB7BA54A5D01B1B8001B7C18A4B6C343C88F4D4293F72F397400ABFD858ADE3B44A0988105611D2187B1*"
$queryProperties = New-Object Microsoft.Office.Server.Search.Query.Rules.QueryTransformProperties
$sortCollection = New-Object Microsoft.Office.Server.Search.Query.SortCollection    
CreateResultSource $searchOwner $fedManager ' Statistics' $queryProperties $query 
Write-Host -ForegroundColor cyan "Statistic Result Source Complete"

#Event Documents
Write-Host -ForegroundColor Green "Starting To Build Call To Event Documents Result Source"
$query = "ContentTypeId:0x01010069411AE48AE74A3096A71D0C77BC6CBD* AND ManagedTerm:{Term.Id}"
$queryProperties = New-Object Microsoft.Office.Server.Search.Query.Rules.QueryTransformProperties
$sortCollection = New-Object Microsoft.Office.Server.Search.Query.SortCollection    
CreateResultSource $searchOwner $fedManager 'Event Documents' $queryProperties $query 
Write-Host -ForegroundColor cyan "Event Documents Result Source Complete"

#Event Images
Write-Host -ForegroundColor Green "Starting To Build Event Images Result Source"
$query = "ContentTypeId:0x010102002042E861E3D14C70B595912F16571C8C* AND ManagedTerm:{Term.Id}"
$queryProperties = New-Object Microsoft.Office.Server.Search.Query.Rules.QueryTransformProperties
$sortCollection = New-Object Microsoft.Office.Server.Search.Query.SortCollection    
CreateResultSource $searchOwner $fedManager 'Event Images' $queryProperties $query 
Write-Host -ForegroundColor cyan "Event Images Result Source Complete"



###################################################################################
#Result Sources End Here
###################################################################################
Well that is really it folks, hopefully this helps to automate some deployments or at the very least was an interesting read! Dan

Monday, January 5, 2015

Date Slider Refiner (slider with bar graph) Not Working for a Custom Managed Date Property!

I am assuming if you are reading this article you have hit the frustrating wall of your custom date refiner showing the graph and slider incorrectly.  The refiner looks correct until you actually use the refiner and realize that range is numeric instead of last year, six months, etc!

Well if you are looking for a fix you are in the right spot friend.  The refiner is not working correctly due to your managed property name!  Believe it or not the managed property name will impact the date slider refiner.

For this example I have created a new managed property of date type called date_Published which has an associated crawled property and all of the correct settings.  When I modify my refinement panel and add date_Published as a refiner using the slider with bar graph, it looks correct but the values are all numeric integers!

After a great deal of sleuthing I realized that if you append on two numbers to the end of your managed property between 0 – 9 the property will render correctly, aka managed_PropName[0-9][0-9].  When I updated my managed property to the name date_Published85 the refiner rendered correctly!

Final Results


Hope This Helps!

Dan

Friday, January 2, 2015

How to Add Totals to Search Refiners in SharePoint 2013

So for every Search project I work on this requirement always surfaces, which is why I am confused to why Microsoft did not default the refiners to include the totals.  Including totals in your refiners is actually very easy and only requires a small modification to your Search Filter refiner.  Depending on whether you are utilizing a single option refiner or the multi value refiner will determine which filter refiner you will need to update.


Single Selection
              Filter_Default
Multiple Selections
             
Filter_MultiValue
The first step to modifying the refiner(s) is to locate them

How to Locate Your Filter Files:
(Note: We do not want to modify the JS Files, any updates we make to the HTML files will propagate to the linked JS files.)

  1.   Site Settings
  2.  Master pages and page layouts
  3.  Display Templates
  4.   Filters
  5. Save a copy of either the Filter_Default.html and/or Filter_MultiValue.html files to your desktop
How to Modify Your Filter Display Templates
Now that we have saved copies of the filter display templates, it is time to edit them in order to display totals.

  1. Open the files in a text editor i.e. Notepad++, Notepad, SharePoint Designer, Visual Studio, etc 
  2. Modify ShowCounts: to equal true
Original

<!--#_
 
    this.Options = {
        ShowClientPeoplePicker: false,
        ShowCounts: false
    };
Updated
<!--#_
 
    this.Options = {
        ShowClientPeoplePicker: false,
        ShowCounts: true
    };

After making the update from false to true you will need to upload the new file and publish the changes.  By using the exact same file name your changes should be saved as a new version to the file, if you were not modifying it directly.

Best Of Luck!
Dan