Retrieving SharePoint Enterprise Search Service Application monitoring information through Powershell requires some deeper digging than I imagined! We can get the last search crawl results from the CrawlHistory, we can get the current CrawlState (or CrawlStatus, 100% equal, see below), but to get the information that is shown in Central Administration under Search Administration proved to be a tough one. I really wanted to have the recent crawl rate and recent query rate. This article also provides some insight in using the hidden methods inside DLL’s, in this case the Microsoft.Office.Server.Search.dll.
The solution
Eventually through using reflection with ILSpy and some c# logic I managed to get it. In the end the code seems fairly simple. We need to call a nonpublic method “get_Monitoring“, using bindingflags, which retrieves an object of the type “Microsoft.Office.Server.Search.Administration.SearchServiceApplicationMonitoring”, which provides us with the properties QueriesPerMinute (recent query rate) and CrawlDocumentsPerSecond (recent crawl rate).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
PS C:\> $ssa = Get-SPEnterpriseSearchServiceApplication PS C:\> ($ssa.GetType().InvokeMember("get_Monitoring",("NonPublic", "Instance", "InvokeMethod"),$null,$ssa,$null)) | Select QueriesPerMinute,CrawlDocumentsPerSecond | fl QueriesPerMinute : 0.2727273 CrawlDocumentsPerSecond : 0.35 #The whole output doesn't give anything else of interest: PS C:\> ($ssa.GetType().InvokeMember("get_Monitoring",("NonPublic", "Instance", "InvokeMethod"),$null,$ssa,$null)) QueriesPerMinute : 0.2727273 CrawlDocumentsPerSecond : 0.35 Name : Monitoring_7F19A5D194F942e6A9856FCFD6EE6F63 TypeName : Microsoft.Office.Server.Search.Administration.SearchServiceApplicationMonitoring DisplayName : Monitoring_7F19A5D194F942e6A9856FCFD6EE6F63 Id : e33834a7-537c-4d85-869c-ab5f182adaef Status : Online Parent : SearchServiceApplication Name=Search Service Application Version : 3325918 Properties : {} Farm : SPFarm Name=SPLAB_Config UpgradedPersistedProperties : {} |

Search Service Application: Search Administration -vs- Powershell QueriesPerMinute & CrawlDocumentsPerSecond
An explanation of how this works
Each (SharePoint) object in Powershell, like an SPWebApplication or an SPServiceApplication, has certain public properties and methods. You get these by simply using the dot and tab, using ‘| Get-Member’, or just ‘| Format-List’.
Each (SharePoint) object can also have a set of nonpublic, private or protected properties and methods. To get these, we need to invoke some .NET within Powershell. We do this on the Type. So we get an object, get it’s type ‘.GetType()’ and then we use ‘.GetMembers()’. However, like I said, when we are looking for nonpublic/private/protected methods and properties, we need to use a specific set of bindingflags. To get all members/methods/properties, we need to use all bindings. We can set this as a variable, and then call the ‘.GetMembers()’ method using that variable. Once we have found an interesting method, we need to invoke it on the type object, for instance with ‘.GetType().InvokeMember(…..)’. More info on this .NET C# logic at msdn.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
$AllBindings = [System.Reflection.BindingFlags]::CreateInstance , [System.Reflection.BindingFlags]::FlattenHierarchy , [System.Reflection.BindingFlags]::GetField , [System.Reflection.BindingFlags]::GetProperty , [System.Reflection.BindingFlags]::IgnoreCase , [System.Reflection.BindingFlags]::Instance , [System.Reflection.BindingFlags]::InvokeMethod , [System.Reflection.BindingFlags]::NonPublic , [System.Reflection.BindingFlags]::Public , [System.Reflection.BindingFlags]::SetField , [System.Reflection.BindingFlags]::SetProperty , [System.Reflection.BindingFlags]::Static (Get-SPEnterpriseSearchServiceApplication).GetType().GetMembers($AllBindings) | ft -a # $ssa = Get-SPEnterpriseSearchServiceApplication # #Some insight in the InvokeMember and GetMember methods: # $ssa.GetType().InvokeMember ##OverloadDefinitions #System.Object InvokeMember(string name, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object target, System.Object[] args) # $ssa.GetType().GetMember ##OverloadDefinitions #System.Reflection.MemberInfo[] GetMember(string name, System.Reflection.BindingFlags bindingAttr) # # $ssa.GetType().GetMember("get_Monitoring", [Enum]::GetValues([System.Reflection.BindingFlags])).Invoke ##OverloadDefinitions #System.Object Invoke(System.Object obj, System.Object[] parameters) # # #We can also use the enum values of the BindingFlags instead of the custom array of bindings #The enum values: [Enum]::GetValues([System.Reflection.BindingFlags]) #This can also be used with the GetMember and Invoke methods, instead of InvokeMember: $ssa.GetType().GetMember("get_Monitoring", [Enum]::GetValues([System.Reflection.BindingFlags])).Invoke($ssa,$null) |
CrawlStatus vs CrawlState
When working with the Search Service Application Content Sources, we can find some interesting information on the status and we can also perform actions on this specific content source. Looking at the properties of a Crawl Content Source you might have wondered, what do they mean. Quite funny to have CrawlState and CrawlStatus properties, which you would expect to be different (why else would you have 2 properties), when they are exactly the same.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
PS C:\> $ContentSource = Get-SPEnterpriseSearchServiceApplication | Get-SPEnterpriseSearchCrawlContentSource PS C:\> $ContentSource.CrawlState Idle PS C:\> $ContentSource.CrawlStatus Idle PS C:\> $ContentSource.CrawlState.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True CrawlStatus System.Enum PS C:\> [Enum]::GetValues($ContentSource.CrawlState.GetType()) Idle CrawlingFull Paused Throttled Recovering ShuttingDown CrawlingIncremental ProcessingNotifications CrawlStopping CrawlPausing CrawlResuming CrawlStarting CrawlCompleting PS C:\> |