Announcing the Search Health Reports (SRx) for SharePoint Search Diagnostics


srxiconBrought to you by SearchEngineers@microsoft.com, the Search Health Reports (SRx) is a PowerShell-driven tool for surfacing complex diagnostics for SharePoint Search through new multifaceted reports. The SRx includes a battery of tests that leverage a customized SSA object extended with contextual data from many disparate sources.

Our goal with this project is straightforward – empower users to troubleshoot Search more effectively so they can focus on solving business problems using Search.

Getting Started

First, download the SRxCore.zip from TechNet Gallery to your SharePoint Search Farm and unzip the files on a SharePoint Server. Then, initialize the SRx environment by simply running the .\initSRx.ps1 script (which exists in the root of the unzipped SRx folder) as demonstrated in the screen shot below:

srxcore-init

This initialization script loads the custom PowerShell modules and creates a globally scoped $xSSA, an extended Search Service Application object with many custom properties and methods.

Worth noting:
The SRx does not persist after closing a PowerShell window, so each time you open a new PowerShell window, start by running .\initSRx.ps1 to initialize the SRx and you’ll be good to go from there.

Generating Test Results

[UPDATE 3/25/2016]  For a summary on each test, please refer to the following post: Search Health Reports (SRx) – Summary for each ‘Test’

From an initialized environment, you can then run a report including all of the tests with the following command:
New-SRxReport -RunAllTests

srxhealth-thehappypath

As seen above, this battery of tests verifies that applicable servers can be pinged, component-related processes and services are running, component states are all ‘Active’, internal Search WCF EndPoints can be browsed, Index components have sufficient space to complete a Master Merges, the Legacy Admin is synchronized with the Admin Component, and more.

When running this set of tests, you can also output more details about the test results by adding the Details flag, such as (and this is also an example of handling when things go bad):
New-SRxReport -RunAllTests -Details

SRxHealth-ThingsGoneBad

The SRx also extends and replaces my previously published Indexer Reports, which you can generate in the SRx using the following:
$xSSA | Get-SRxIndexReports -DiskReport

srx-indexreport

—-

Looking Forward…

As Search PFEs, we are working with several of our dedicated customers to build upon the SRx Core by developing the Search Health Reports Dashboard (SRx), which entails a custom SharePoint hosted site collection for rendering diagnostic gauges, KPIs, and proactive reporting. Over the last few months, this project significantly matured with expanding functionality and robustness – for that, a giant thank you goes out for the heavy lifting from Eric Dixon, Brent Groom, and Russ Maxwell.

Over the coming weeks, expect to see many more SRx related posts here (SharePoint Strategery), on SharePoint Brew (Russ Maxwell), and on Eric Dixon’s Search Blog …all of which roll up to our team blog (On Search). In these coming posts, anticipate more details on individual tests, announcements of new functionality, and recordings that demonstrate advanced usage (*including sneak peeks of the SRx Dashboard). Finally, we’ll continue to update the SRx Core on TechNet Gallery with the latest enhancements.

For any questions or feedback regarding this, please feel free to contact us at:
SearchEngineers@microsoft.com

…and to learn more about the Search Health Reports Dashboard (SRx), contact your TAM to help get us engaged.

 

 

 


And the legalese:
Disclaimer:
As the “Search Engineers”, we are a group of Microsoft PFEs focused primarily on SharePoint Search. We released the Search Health Reports (SRx) to help others get more out of Search, but the SRx should not be considered an official product . ALL information in this blog is provided “AS IS” with no warranties and confers no rights. This blog does not represent the thoughts, intentions, plans or strategies of my employer. All content is solely my opinion and provided with a best effort to be based in reality.

All examples, code samples, demonstrations, or anything resembling a “how-to” are provided “AS IS” without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose. Inappropriate comments will be deleted at the authors discretion. And yes, the spelling of strategery was intentional.

Comments (12)

  1. Rene says:

    Thanx a lot for this, unfortunately the Ping-SQLIO-Tests cannot handle SQL-Aliases, so it reports that the SQL-Servers are not pingable, because it pings the alias.

  2. Jas says:

    This is pure brilliance – thank you !

    Looking forward to testing this out.

  3. bspender says:

    Thank you for checking this out and the feedback!

     – I'll see what we can do on the SQL Aliases…

    And in the meantime, if you want to avoid that test, you can simply rename the .TestTest-[whatever].ps1 with a .txt file extension (and the "RunAllTests" will skip that one.

    Appreciated,

    –Brian

  4. jlai says:

    Thanks for this tool. It Looks great but I get this exception:

    Evaluating rule Test-SSACrawlNotStuckInStarting…

    Testing Crawl…

    =================================================================

    Caught exception while evaluating Test-SSACrawlNotStuckInStarting

    Exception: A positional parameter cannot be found that accepts argument '$null'.

    —————————————————————–

    At C:SRxCoreResourcesTestsCoreTest-SSACrawlNotStuckInStarting.ps1:24 char:25

    +         $crawlsInTransition | foreach {

    +                               ~~~~~~~~~

    System.Management.Automation.ParameterBindingException: A positional parameter cannot be found that accepts argument '$null'.

      at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)

      at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)

      at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

      at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

      at System.Management.Automation.Interpreter.Interpreter.Run(InterpretedFrame frame)

      at System.Management.Automation.Interpreter.LightLambda.RunVoid1[T0](T0 arg0)

      at System.Management.Automation.ScriptBlock.InvokeWithPipeImpl(Boolean createLocalScope, ErrorHandlingBehavior errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Pi

    pe outputPipe, InvocationInfo invocationInfo, Object[] args)

      at System.Management.Automation.ScriptBlock.<>c__DisplayClass4.<InvokeWithPipe>b__2()

      at System.Management.Automation.Runspaces.RunspaceBase.RunActionIfNoRunningPipelinesWithThreadCheck(Action action)

      at System.Management.Automation.ScriptBlock.InvokeWithPipe(Boolean useLocalScope, ErrorHandlingBehavior errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Pipe outp

    utPipe, InvocationInfo invocationInfo, Object[] args)

      at System.Management.Automation.ScriptBlock.InvokeUsingCmdlet(Cmdlet contextCmdlet, Boolean useLocalScope, ErrorHandlingBehavior errorHandlingBehavior, Object dollarUnder, Object input, Obj

    ect scriptThis, Object[] args)

      at Microsoft.PowerShell.Commands.ForEachObjectCommand.ProcessRecord()

      at System.Management.Automation.CommandProcessor.ProcessRecord()

    =================================================================

    Finished evaluating rule Test-SSACrawlNotStuckInStarting. Time: [0:0:0.452]

  5. Rene says:

    Hi Brian,

    I've included the resolution of the SQL Aliases, pasting the complete script, our changes can be found between "Begin of custom code" and "End of custom code". It has been successfully tested:

    # make sure the the $xSSA has been instantiated

    if(-not $xSSA._hasSRx) {

       throw [System.NullReferenceException] "This test requires a valid `$xSSA"

    }

    # $xSSA will be in scope

    $ruleObject = New-Object PSObject

    $ruleObject | Add-Member Name "Test-OSPingSQLServer"  

    $ruleObject | Add-Member ExpectedValue "0"  

    $ruleObject | Add-Member Category @("infrastructure");  

    $ruleObject | Add-Member ActualValue $(

    $unreachable = $(New-Object System.Collections.ArrayList)

    $dbServerInstances = (Get-SPDatabase).Server | foreach {$_.address} | SELECT -Unique

    <#

    Begin of custom code

    #>

    #Get all aliases

    $allAliases=Get-ItemProperty -Path 'HKLM:SOFTWAREMicrosoftMSSQLServerClientConnectTo'

    write-host $allAliases

    $dbServerInstancesFromAlias=@();

    #Resolv the aliases

    foreach($dbServerInstance in $dbServerInstances){

    $value=$xSSA._GetServer($dbServerInstance).Name;

    $resolvedAlias=$allAliases.$value

    if($resolvedAlias){

    #get the Instance-Name

    $resolvedAlias=$resolvedAlias.Substring($resolvedAlias.IndexOf(",")+1)

    #remove the instances, so that we can ping the servers

    $resolvedAlias=$resolvedAlias.Substring(0,$resolvedAlias.IndexOf(""));

    write-host "Resolved $($dbServerInstance) to $($resolvedAlias)"

    #Fill the array with the servernames,

    $dbServerInstancesFromAlias+=$resolvedAlias;

    }

    }

    if($dbServerInstancesFromAlias.Count -gt 0){

    $dbServerInstances=$dbServerInstancesFromAlias;

    }

    <#

    End of custom code

    #>

    $dbServerInstances | foreach {

    $serverName = $_

    if (-not $xSSA._GetServer($serverName).canPing()) { $unreachable.Add($serverName) | Out-Null }  

    }

    if ($dbServerInstances.Count -gt 0) {

    if ($unreachable.count -eq 0) {$unreachable = 0}

    $unreachable

    } else { 'unknown' }  #something else is wrong if no instances are reported

    );

    $ruleObject | Add-Member Success $($ruleObject.ActualValue -eq $ruleObject.ExpectedValue)

    $ruleObject | Add-Member Message $(if($ruleObject.Success){

    @{

                   level = "Normal";

                   headline = "Each SQL instance can be pinged";

    }

    } else {

    @{

                   level = $(

    if ($ruleObject.ActualValue -ieq 'unknown') { "Warning" }

    else { "Error" }

    );

                   headline = $(

    if ($ruleObject.ActualValue -ieq 'unknown') {

    "Unexpected : No SQL Server instances could be identified for this SSA"

    } else {

    $outString = "The following SQL Servers cannot be pinged: "

    $delim = ""

    $ruleObject.ActualValue | foreach {

    $outString += $delim + $_

    $delim = ", "

    }

    }

    $outString

    );

    }

    })

    #And then just return the object as the last step…

    $ruleObject

  6. bspender says:

    Hi jlai,

    I found what should be causing that bug and fixed it… look  .TestsCoreTest-SSACrawlNotStuckInStarting.ps1 and look at [line 20]:

    if (($crawlsInTransition.count -eq $null) -or ($crawlsInTransition.count -eq 0)) {0}

    Should instead be:

    if (($crawlsInTransition -eq $null) -or ($crawlsInTransition.count -eq 0)) {0}

    …in other words, if $crawlsInTransition is $null, then $null.count is 0 …meaning that was a useless test 🙂  (and not what I was intending).

    Another related bug I found (that seems to only impact the PowerShell ISE) is I .ModulesCoreEnable-SRxDatabaseUtilities.psm1 on [line 76]

    $queryString = Get-Content $templateFile

    Should instead be:

    [string]$queryString = Get-Content $templateFile

    ——–

    For both cases, we'll get the updated code posted by Monday…

  7. John Guilbert says:

    It would be nice to have brief description on each one. Critical or not critical for example.

  8. bspender says:

    Hi John – completely agree …and that is the next blog post coming (there will be a TechNet wiki article for that lists each out and gives basic summary of each… and a blog post giving even more context) …and we're planning on writing even more detailed documentation for each test, too.

    Appreciated!

  9. Rohit says:

    I want to understand where do i need to change in order to get the result in a custom csv when doing

    "New-SRxReport -RunAllTests -Details"

    I lost the flow of the script after Write-Srx .

    Cold you please give me insight. This is a wonderful script .A real lifesaver, if there ever was one 🙂

  10. Hi Rohit,

    I think you're looking for something like this:

       Test-SRx -All | Export-Csv c:tempsrx.csv

    Note that the data and detail property values, when they are objects, won't get fully expanded in the csv file.  

  11. Rohit says:

    Thanks Eric.  I want to extract the data from "New-SRxReport -RunAllTests"   which shows status as Normal/Failed into an csv/HTML  which can be sent in an email body.

    I am not able to extract this data using export CSV

  12. Dean Gross says:

    Are there any plans to put Search Health info into the SPO Admin Center?

Skip to main content