5

I'm trying to write a simple program that would connect to remote machines and query the indexing status.

Here's the code that does it on my machine. This works OK.

using System;
using Microsoft.Search.Interop;

namespace IndexStatus
{
    class Program
    {
        static void Main(string[] args)
        {
            CSearchManager manager = new CSearchManager();
            CSearchCatalogManager catalogManager = manager.GetCatalog("SystemIndex");
            _CatalogPausedReason pReason;
            _CatalogStatus pStatus;
            Console.WriteLine(catalogManager.NumberOfItems().ToString());
            int plIncrementalCount;
            int plNotificationQueue;
            int plHighPriorityQueue;
            catalogManager.NumberOfItemsToIndex(out plIncrementalCount, out plNotificationQueue, out plHighPriorityQueue);
            Console.WriteLine(plIncrementalCount.ToString());
            Console.WriteLine(plNotificationQueue.ToString());
            Console.WriteLine(plHighPriorityQueue.ToString());
            catalogManager.GetCatalogStatus(out pStatus, out pReason);
            Console.WriteLine(pStatus.ToString() + " " + pReason.ToString());
            Console.ReadLine();
        }
    }
}

However, when I call GetCatalog on "mycomputername.SystemIndex" instead of "SystemIndex", I get

An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in IndexStatus.exe

Additional information: Exception from HRESULT: 0x80042103

enter image description here

Visual Studio 2015 is running with admin permissions on Windows 8.1. The target computers will be Windows 7 systems mostly and the program will mostly be run from a Windows 10 system. I'm using Microsoft.Search.Interop.dll from Microsoft Windows Search 3.X SDK downloaded from here. I turned the firewall off in case that had anything to do with it, but apparently not.

I've checked that I get the same exception if I call the function on complete nonsense like "sdfd". And I've found this:

MSS_E_CATALOGNOTFOUND - 0x80042103 - (8451) WindowsSearchErrors.h

The specified catalog was not found. Check to see if it was deleted, or if there are errors in your application code.

I've tried to use "localhost" instead of the machine name, but that didn't help.

The MSDN docs say this:

Currently Microsoft Windows Desktop Search (WDS) 3.0 supports only one catalog and it is named SystemIndex.

I'm not sure how to understand this. Perhaps the method is not able to choose between different machines? If so, is there a way to connect to a remote catalog and make these queries, other than using something like PsExec?

Re Ben N's answer: This is starting to become deep water for me, but I'm more fascinated than afraid. :) Your code worked for me after several modifications:

CSearchManagerClass manager = System.Runtime.InteropServices.Marshal.CreateWrapperOfType(comManager, typeof(CSearchManagerClass));would not compile on Visual Studio 2015 and would give the following errors:

enter image description here enter image description here

The second error was easy to fix by just adding a cast:

CSearchManagerClass manager = (CSearchManagerClass)System.Runtime.InteropServices.Marshal.CreateWrapperOfType(comManager, typeof(CSearchManagerClass));

As for the "Interop type cannot be embedded" error message, I found this question. There are two suggested solutions:

  • Change the Embed Interop Types property of the Microsoft.Search.Interop reference to False.

  • Change CSearchManagerClass to CSearchManager.

The first solution makes the program compile, but it affects portability. Now the program won't run on a computer that doesn't have the .dll on it. The second solution compiles but throws

An unhandled exception of type 'System.ArgumentException' occurred in mscorlib.dll

Additional information: The type must be __ComObject or be derived from __ComObject.

on that exact line when I run it against my own machine.

But there is another problem, and this one I have no clue about. When I run it against my colleague's machine (I'm an administrator on his computer and Visual Studio is running with admin permissions), I'm getting

An unhandled exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dll

Additional information: Retrieving the COM class factory for remote component with CLSID {7D096C5F-AC08-4F1F-BEB7-5C22C517CE39} from machine computername failed due to the following error: 80070005 computername.

This does scare me a little bit because I know next to nothing about COM. I've checked that DCOM is enabled on his computer and on mine. But when I try to go to his computer in Component Services it shows as a enter image description here and DCOM Config is missing from the tree. And the same happens for other computers on the domain (even though I have admin rights on all workstations). This blog suggests it could be a firewall issue and if it is, it's not something that will be feasible to overcome.

Both of your answers are definitely bounty worthy already, but if you have any suggestions or would be able to shed some light on what's happening, I would be very grateful. If I can't make it work, it's fine, but I would definitely like to take as much knowledge as possible from this.

Community
  • 1
  • 1
Michał Masny
  • 229
  • 3
  • 19
  • [This](http://superuser.com/questions/1096861/how-can-i-get-useful-information-from-the-search-indexer-perfomance-counters) is a related SuperUser question asked in parallel. – Michał Masny Jul 07 '16 at 00:47

1 Answers1

1

GetCatalog doesn't support reaching out to a remote machine, but we can use COM to create a search manager object that refers to the service on the target computer.

// Assume targetMachine has the name of the target computer
Guid guid = new Guid("{7D096C5F-AC08-4F1F-BEB7-5C22C517CE39}");
Type managerType = Type.GetTypeFromCLSID(guid, targetMachine, true);
var comManager = Activator.CreateInstance(managerType);
CSearchManagerClass manager = (CSearchManagerClass)System.Runtime.InteropServices.Marshal.CreateWrapperOfType(comManager, typeof(CSearchManagerClass));

You should then the able to use manager as though it were the manager of the local machine. If there's a problem contacting the remote computer, a COMException will be thrown on the CreateInstance call.

For the PowerShell version of this, see my answer to your Super User question.

Community
  • 1
  • 1
Ben N
  • 2,883
  • 4
  • 26
  • 49
  • Thank you very much. I've edited my question to account for this, please take a look if you have time. – Michał Masny Jul 07 '16 at 19:03
  • My bad, I forgot the cast. It does have to be `CSearchManagerClass`, or else `CreateWrapperOfType` will fail. I don't believe there's a way to avoid the DLL dependency, though you could conceivably use something like [ILMerge](https://www.microsoft.com/en-us/download/details.aspx?id=17630). Unfortunately, I have no domain to test on, but it looks like you may have to enable [this Group Policy setting](https://technet.microsoft.com/en-us/library/cc738900) on the target machine(s). – Ben N Jul 07 '16 at 19:21
  • I gave all permissions to WSearch in DCOM Config to myself on the target computer and the exception changed to "Creating an instance of the COM component with CLSID {7D096C5F-AC08-4F1F-BEB7-5C22C517CE39} from the IClassFactory failed due to the following error: 800706ba The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)." That seems to be a firewall issue which I haven't been able to resolve. I think I'm satisfied now - the conclusion seems to be it's not really doable other than by calling the CreateInstance method on the target computer, in whatever way. – Michał Masny Jul 12 '16 at 14:42
  • @ymar That's unfortunate. Did enabling that Group Policy setting not help? It allegedly enables all the remote management ports. – Ben N Jul 12 '16 at 14:45
  • It didn't. I tried creating some custom firewall rules also, according to posts I've found on the internet but no luck. Still, I've learned quite a bit from this and I think it was worthwhile to try. Remotely modifying firewall settings and DCOM permissions seems like way too much hassle anyway when you can simply use something like PsExec to run the code on the target computer anyway. – Michał Masny Jul 12 '16 at 15:10
  • @ymar Whoops, you're right, that was the wrong link. [This MS article](http://social.technet.microsoft.com/wiki/contents/articles/4494.windows-server-troubleshooting-the-rpc-server-is-unavailable.aspx) suggests enabling file and print sharing; it also mentions some other tools that seem helpful. – Ben N Jul 12 '16 at 15:36