Provisioning Search on SharePoint 2013 Foundation Using PowerShell

Posted on Posted in SharePoint 2013

There was recently a twitter conversation between @cacallahan, @toddklindt, and @brianlala discussing provisioning Search on SharePoint Foundation and whether it was possible or not and somewhere during the conversation it was suggested that I might know how to do this (sorry guys for not responding immediately) – unfortunately I hadn’t actually done any work with SharePoint 2013 Foundation yet and so had not yet tried and thus didn’t know the answer (I knew there were issues and suspected a workaround was possible but I didn’t have a server built to test anything). Well, last night and today I managed to have some free time so I figured I’d take a look at the problem to see if my guess about a workaround was correct.

Before I get to the results of my discovery let’s first look at what the blocking issue is. It’s actually quite simple – the product team, for various reasons, have decided that for SharePoint 2013 Foundation you can only have one Search Service Application and you shouldn’t be able to modify the topology of the Service Application; this means that when you provision Search using the Farm Configuration Wizard it will create a default topology for you in which all roles are on a single server. So, to enforce these rules they chose to make it so that the PowerShell cmdlets would not allow you to provision the service application or run any method or cmdlet that would otherwise allow you to modify an existing topology (so you can’t change the topology created by the wizard). I totally get the reasoning for the restriction – if you need enterprise topology type structures then pony up the money and get off the free stuff. That said, I think they took the lazy way out by simply blocking the cmdlets when they could have easily put in other restrictions that would have achieved their goals while still allowing users to use PowerShell to provision the environment.

If you’re curious as to what happens when you try to provision the service using PowerShell on SharePoint Foundation 2013 here’s a screenshot which shows the error that is thrown:

SNAGHTML2aaf94c0

This error is thrown by a simple piece of code in the InternalValidate() method of the cmdlet which checks to make sure you are on Standard or Enterprise before allowing the cmdlet to execute (and any other cmdlets or methods that would otherwise affect the topology likewise perform this check).

To solve the problem I decided to start from the perspective of code run via the browser and drill down to see what I could find. So using Reflector I located the class and associated methods that are called by the Farm Configuration Wizard; this quickly led me to the public Microsoft.Office.Server.Search.Administration.SearchService.CreateApplication() static methods. So I did a quick test calling one of these methods and I was happy to find that the Search Service Application created perfectly – though there was one minor problem: the topology was empty. At first glance I figured this wouldn’t be an issue – I could simply clone the topology and add my components – unfortunately this is where I learned that they applied the SKU check to methods and cmdlets that would allow you to manipulate the topology. (On a side note, using these methods for Standard or Enterprise is potentially a great alternative to the New-SPEnterpriseSearchServiceApplication cmdlet as it lets you specify the names of databases that you can’t specify when using the cmdlet and because it creates an initially empty topology there’s less cleanup and manipulation of the cloned topology (assuming you don’t want to use what’s created) and it provisions slightly faster because it does less). So at this point I figured I’d hit the real road block – I could create the service application but it was useless as I couldn’t manipulate it.

This left me with only one option – to use reflection to call the internal method that the Farm Configuration Wizard calls to provision the service application. Now, before I get to the code that demonstrates how to do this I need to share a word of caution – using reflection to call internal methods is totally not supported. So what does this mean? Will Microsoft no longer support your Farm? Well, my understanding (and folks in the know please correct me if I’m in the wrong) is that Microsoft will continue to support you and that you will simply have to remove unsupported code before they will help you troubleshoot issues. Well, in this case it’s a one-time operation so there’s nothing really to remove; I figure the worst case scenario is that they’ll tell you that you need to recreate the service application using the Farm Configuration Wizard and then they’ll help you with your issue. But let’s take the question of supportability out of the equation for a second and look at it from a completely practical standpoint – if you were to look at the code that the Farm Configuration Wizard calls you’d see that, outside of some error checking and data validation and variable initialization, there’s effectively just two lines of code that do the provisioning of the service so I believe that the probability of getting it wrong is pretty low and the fact is search will either work or it won’t so if it doesn’t work then try again or just use the dang wizard. So, with all that said, if you decide to use any of this code you need to weigh the risks yourself and make an informed decision with those risks in mind. Alright, enough of that crap – you want to see the code so let’s get to the code.

To keep the PowerShell itself nice and simple I decide to derive this example from a script that Todd Klindt provides on his blog (the script I use is considerably more complex as it handles the changing of service options like the index folder and the service and crawl accounts, to name a few, and I don’t want the point of this post to be lost in all those details). Just to make sure the full chain of credit is provided I should note that Todd’s script is actually a derivative of what Spence Harbar provides on his blog but I wanted to reference Todd’s post specifically as it’s a bit shorter and more focused on the topic. Okay, background info – check; disclaimer – check; attribution – check – looks like it’s time for some code so here you go:

#Start the service instances
Start-SPEnterpriseSearchServiceInstance $env:computername
Start-SPEnterpriseSearchQueryAndSiteSettingsServiceInstance $env:computername

#Provide a unique name for the service application
$serviceAppName = Search Service Application

#Get the application pools to use (make sure you change the value for your environment)
$svcPool = Get-SPServiceApplicationPool SharePoint Services App Pool
$adminPool = Get-SPServiceApplicationPool SharePoint Services App Pool

#Get the service from the service instance so we can call a method on it

$searchServiceInstance = Get-SPEnterpriseSearchServiceInstanceLocal
$searchService = $searchServiceInstance.Service

#Use reflection to provision the default topology just as the wizard would
$bindings = @(InvokeMethod, NonPublic, Instance)
$types = @([string], [Type], [Microsoft.SharePoint.Administration.SPIisWebServiceApplicationPool], [Microsoft.SharePoint.Administration.SPIisWebServiceApplicationPool])
$values = @($serviceAppName, [Microsoft.Office.Server.Search.Administration.SearchServiceApplication], [Microsoft.SharePoint.Administration.SPIisWebServiceApplicationPool]$svcPool, [Microsoft.SharePoint.Administration.SPIisWebServiceApplicationPool]$adminPool)
$methodInfo = $searchService.GetType().GetMethod(CreateApplicationWithDefaultTopology, $bindings, $null, $types, $null)
$searchServiceApp = $methodInfo.Invoke($searchService, $values)

#Create the search service application proxy (we get to use the cmdlet for this!)
$searchProxy = New-SPEnterpriseSearchServiceApplicationProxy -Name $serviceAppName Proxy -SearchApplication $searchServiceApp

#Provision the search service application
$searchServiceApp.Provision()

 

Basically there’s two things that need to be done: first we need to use reflection to get the MethodInfo object for the CreateApplicationWithDefaultTopology() method of the Microsoft.Office.Server.Search.Administration.SearchService class and we’ll use this object to invoke the actual method, passing in the parameter types and values (and yes, the cast of the SPIisWebServiceApplicationPool objects is necessary otherwise you’ll get an error about trying to convert PSObjects to SPIisWebServiceApplicationPool types); the next thing we need to do, after the service application is created, is to create the service application proxy and then call the Provision() method on the search service application that we previously created (if you miss this step you’ll get errors about things like the admin component not be started and whatnot).

Once completed you’ll get a fully functional, PowerShell provisioned search service application. If you navigate to the search administration page you should see something that looks just like this (just like if you used the wizard):

image

So there you have it – it is indeed possible to provision the service using PowerShell – I’ll let you determine whether you should or not 🙂

Happy PowerShelling!

-Gary

32 thoughts on “Provisioning Search on SharePoint 2013 Foundation Using PowerShell

  1. Thanks for taking the time to check into this whole New Search service application cmdlet thing for me. I really appreciate it.

    Apparently they’re supposed to be meeting today (thurs. 2/28) to see about the cmdlet. I am truly, truly hoping they see that there are better ways than block the cmdlet altogether (and apparently the topology one too)- and that it can check to see if there is one already there before throwing an error. One can hope.

    But if that isn’t possible, at least now I can try to use PowerShell to provision staging and demos at least. In terms of teaching my people- well, it’s not the simplest of things, but with your blog and “simple” script, I can walk them through what they are doing and why.

    I do have a little question though- concerning the topology. What, exactly, do you mean that SPF admins should not be able to control topology? Shouldn’t I be able to at least *name* my databases something other than the GUIDs the default gets? I should have to “pony up” for that? I guess I am missing something (and mind you, I am a WSS/SPF specialist, I haven’t explored enterprise search in my customers’ environments)? In WSS 3.0 you could have more than one search server on the farm, (only one indexer) but I can’t with SPF 2013? I apologize if the question seems naive, but, after all this, it seems another thing I need to look into.

    1. Glad I could help and I hope they do come up with a supported solution.

      Regarding the topology – don’t misunderstand, I totally agree that admins should be able to control not just the database names but also the location of individual components (perhaps I ddidn’t word my statement properly to reflect that); however, I do understand their reasoning for not allowing the location of components to be changed (it’s totally a marketing thing – they want to keep SPF simple and if your needs dictate more then they want you to pay the money to upgrade – we may not agree with it or like it but it does make good business sense). What irritates me is that they could have easily maintained that restriction but still provided me with a cmdlet (call it New-SPEnterpriseSearchDefaultTopology or something) which allows me to do what I’ve done in the post but also specify the database names. Seriously, I could create the cmdlet myself with a series of calls to internal methods using reflection so why couldn’t they? (speaking of, you can technically change the topology you just have to use reflection to do it – you could easily export the topology, change the XML, import the topology (which will error on the activation but it will do the import) and then call the ActivateSilently() internal method on the imported topology). So in terms of architecture they’ve definitely scaled back from what you could do in 2010 – it’s unfortunate but there you go.

  2. Hi Gary,

    Would be able to share the more complex script, as I would also like to change the index folder and crawler service account.

    Thanks

    1. Can’t share it at the moment as it’s part of a larger application that I have. In general though the pieces to set the account and directories is no different than it is for the standard version of 2013 (and is basically the same as it was for 2010) so you should be able to reference other scripts which do this (including some old ones I have on my blog).

  3. Gary,
    Is there a way to set the names of the databases that it will create, is this something else that would need to go into $types and $values, if so would you be able to tell us how?

    1. It’s not possible to do without using a lot more reflection to call internal methods. The best you can do with the smallest amount of reflection is to replicate what the farm configuration wizard does (which is what I’ve done here).

  4. Good morning!

    I tried the script and was successful, until I got to the last line: $searchServiceApp.Provision()

    I was greeted with an angry error:
    Exception calling “Provision” with “0” argument(s): “The SDDL string contains an invalid sid or a sid that cannot be translated.
    Parameter name: sddlForm”
    At line:1 char:1
    + $searchServiceApp.Provision()
    + CategoryInfo :NotSpecified (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException

    Could you please help tell me where I went wrong? I’m a little new to powershell and sharepoint, in general, and I’m running into way too many problems.

    1. I’m guessing you’re using a standalone installation of SharePoint rather than a complete install? Some things to consider: make sure you have a WSS_WPG and WSS_ADMIN_WPG group; make sure your search account is in the WSS_ADMIN_WPG group and that the account has full control to “C:\Program Files\Microsoft Office Servers\15.0\Data\Office Server\Analytics_guid” (or “C:\Program Files\Windows SharePoint Services\15.0\Data” if foundation). If that doesn’t work maybe try adding your search service account as a local administrator (don’t leave it there and make sure you reboot after adding it (or at least restart all affected services)).

      1. “full control to “C:\Program Files\Microsoft Office Servers\15.0\Data\Office Server\Analytics_guid”

        did the trick. Change the latest “analytics” Folder and give full control the user.

  5. Hi Gary,
    your script seems to works fine… until the last command:

    #Provision the search service application
    $searchServiceApp.Provision()

    my powershell tells always the same:

    Exception calling “Provision” with “0” argument(s): “The SDDL string contains an invalid sid or a sid that cannot be translated. Parameter name: sddlForm

    what’s my problem? 🙁

    Thanks in advice

  6. Hi,
    Cool, very helpfull your Script.

    is it possible to give the database name in the script? i search for a solution so i can create in sharepoint foundation 2013 a search servie application with custom parameters.

    many thanks

    1. It is possible using a lot of reflection but you’d be even further in unsupported land. If you’re using Foundation then I think the best approach is just to accept that it’s free and there’s going to be limitations.

  7. Hi Gary,

    Thank you for the script.

    Would it be possible for us to create the search service application in partioned mode?

    I have created the SSA using the above script and it is working fine. Now I want to use the same on another environment and I want to create the SSA in partioned mode.

    Would the -partitioned switch work here?

    Thanks in advance

    1. It can be done but you’d have to use a boat load of reflection to make it work. I’d honestly seriously question your requirements if you’re using SPF with multi-tenancy (or even just using multi-tenancy in general – there are very few good use cases for using it as it is very difficult to get right).

  8. I am using the defaults for my app pools but the script says that they objects are not found.
    What am I doing wrong?

    $svcPool = Get-SPServiceApplicationPool “SharePoint – 80”
    $adminPool = Get-SPServiceApplicationPool “SharePoint Central Administration v4”

  9. Did a Get-SPSearchServiceApplication Pool. The default is this:

    $svcPool = Get-SPServiceApplicationPool “SharePoint Web Services Default”
    $adminPool = Get-SPServiceApplicationPool “SharePoint Web Services System”

    Works now

  10. Thanks for your script, it really helped me.

    When I browse to the Search Administration page, the two sections “System Status” ans “Search Application Topology” do not show. They are stuck with “Loading …” gif.

    Appart from that, everything seems to work fine (I can crawl and search my items).

    Do you have any idea how to solve this problem ?

    1. Hi Olivier,
      Was this issue ever fixed on your end? What did you have to do to fix the issue?
      We’ve similar issue at our end and are left with no options other than rebuilding Search Service Application.

  11. Hi Gary
    Thanks for the great work in digging into this and sharing your findings. I’m in the same boat as Rahul above trying to get Search working in Partitioned mode in Foundation (we running a multitenant service on Foundation).
    I’ve been looking to replicate your work above with a similar method in the same assembly (CreateApplication (overload with SPPartitionOption)) but I’ve run into an issue with the type SPPartitionOptions.

    Its in the Microsoft.Office.Server assembly (Microsoft.Office.Server.Utilities.SPPartitionOption) as an ‘Internal enum’. I’ve tried loading the assembly a number of ways (loadwithpartial, loadfrom, getassembly) but no matter what I try I get an error that powershell ‘cannot find type [Microsoft.office.server.utilities.sppartitionoptions] make sure the assembly containing this type is loaded.

    Do you know if I can even use an internal enum type in this way? I’m trying to pass it in as you do in a ‘invokemethod’ but cant even get past the step of declaring the types.

    Any help would be appreciated.

    Kind regards
    Riccardo

  12. Hi, can you please let me know how I can change the Search Index Location for SharePoint 2013 FOUNDATION using PowerShell?

  13. Does this mean by using the PowerShell in this blog post, it is possible to have cross site collection search in SharePoint Foundation 2013. If so what do is used as the search center?

Leave a Reply

Your email address will not be published. Required fields are marked *

*