MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Wednesday, September 19, 2007

Manage Content Database Settings

We've recently started making some decisions as to the layout of our primary intranet site (the information architecture of the site that is). One of the things we decided was that we wanted all divisions to be in separate site collections but for each of them to share a single database. We also wanted to create a central document center site and knowledge base site which would, along with all remaining root content, be in it's own database. Our current structure just has everything in one large site collection. In order to accomplish this I needed to take the primary content database offline while I moved/converted divisional web sites into site collections.

I was able to use the existing addcontentdb command to create the new content database but I needed to create a new command, called gl-managecontentdbsettings, to take the existing one offline (I already have a command to convert a sub-web to a site collection). I decided that rather than just limit the command to changing the status I'd go ahead and make it so that it could adjust any of the properties that you could otherwise adjust via the browser by going to the Manage Content Database Settings page (Central Administration > Application Management > Content Databases > Manage Content Database Settings). This included the status, the maximum number of allowed sites, the number of sites allowed before a warning is sent, and the search server (there's already a built in command to remove a content database so I didn't worry about that).

The code to do all of this was extremely simple - the only thing that made me pause for a bit was the setting of the search server (I had to dig into Microsoft's code to see how that was accomplished but in the end it turned out to be pretty simple):

   1: public override int Run(string command, StringDictionary keyValues, out string output)
   2: {
   3:     output = string.Empty;
   4:  
   5:     InitParameters(keyValues);
   6:  
   7:     string dbname = Params["dbname"].Value;
   8:  
   9:     using (SPSite site = new SPSite(Params["webapp"].Value))
  10:     {
  11:         SPContentDatabase db = null;
  12:         foreach (SPContentDatabase tempDB in site.WebApplication.ContentDatabases)
  13:         {
  14:             if (tempDB.Name.ToLower() == dbname.ToLower())
  15:             {
  16:                 db = tempDB;
  17:                 break;
  18:             }
  19:         }
  20:         if (db == null)
  21:             throw new Exception("Content database not found.");
  22:  
  23:         bool modified = false;
  24:         if (Params["status"].UserTypedIn)
  25:         {
  26:             db.Status = (SPObjectStatus)Enum.Parse(typeof(SPObjectStatus), Params["status"].Value, true);
  27:             modified = true;
  28:         }
  29:  
  30:         if (Params["maxsites"].UserTypedIn)
  31:         {
  32:             db.MaximumSiteCount = int.Parse(Params["maxsites"].Value);
  33:             modified = true;
  34:         }
  35:         else if (Params["setmaxsitestocurrent"].UserTypedIn)
  36:         {
  37:             if (db.CurrentSiteCount < db.WarningSiteCount)
  38:                 db.WarningSiteCount = db.CurrentSiteCount - 1;
  39:             db.MaximumSiteCount = db.CurrentSiteCount;
  40:             modified = true;
  41:         }
  42:  
  43:         if (Params["warningsitecount"].UserTypedIn)
  44:         {
  45:             db.WarningSiteCount = int.Parse(Params["warningsitecount"].Value);
  46:             modified = true;
  47:         }
  48:  
  49:         if (Params["searchserver"].UserTypedIn && !string.IsNullOrEmpty(Params["searchserver"].Value))
  50:         {
  51:             // If they specified a search server then we need to try and find a valid
  52:             // matching search server using the server address property.
  53:             SPSearchService service = SPFarm.Local.Services.GetValue("SPSearch");
  54:             SPServiceInstance searchServiceServer = null;
  55:             foreach (SPServiceInstance tempsvc in service.Instances)
  56:             {
  57:                 if (!(tempsvc is SPSearchServiceInstance))
  58:                     continue;
  59:  
  60:                 if (tempsvc.Status != SPObjectStatus.Online)
  61:                     continue;
  62:  
  63:                 if (tempsvc.Server.Address.ToLowerInvariant() == Params["searchserver"].Value.ToLowerInvariant())
  64:                 {
  65:                     // We found a match so bug out of the loop.
  66:                     searchServiceServer = tempsvc;
  67:                     break;
  68:                 }
  69:             }
  70:             if (searchServiceServer != null)
  71:             {
  72:                 db.SearchServiceInstance = searchServiceServer;
  73:                 modified = true;
  74:             }
  75:             else
  76:                 throw new Exception("Search server not found.");
  77:         }
  78:         else if (Params["searchserver"].UserTypedIn)
  79:         {
  80:             // The user specified the searchserver switch with no value which is what we use to indicate
  81:             // clearing the value.
  82:             db.SearchServiceInstance = null;
  83:             modified = true;
  84:         }
  85:  
  86:         if (modified)
  87:             db.Update();
  88:     }
  89:  
  90:     return 1;
  91: }

The command I created is detailed below.

Using this command is straightforward. The only odd part is the setting of the search server. If you want to set the value simply provide the server name along with the "-searchserver" switch. But if you want to clear the value just provide the "-searchserver" switch alone with no value (not "" but literally no value). I probably should have done this differently but it works. The other thing that's odd is that if you look in the browser you'll see that the drop down for status contains "Ready" and "Offline" - this actually corresponds to "Online" and "Disabled" (which is strange because the SPObjectStatus enum contains an "Offline" value but if you tried to use that to set it offline it doesn't appear to have an affect (at least it doesn't change the value in the browser - I didn't actually test if it prevents new sites from being created). The syntax of the command can be seen below:

C:\>stsadm -help gl-managecontentdbsettings

stsadm -o gl-managecontentdbsettings

Sets the status and site limits for a content database.

Parameters:
        -dbname <content database name>
        -webapp <web application url>
        [-status <online | disabled>]
        [-maxsites <maximum number of sites allowed in the db / -setmaxsitestocurrent (sets the max value to the current value to keep the database online but prevent new sites from beeing added)>]
        [-warningsitecount <number of sites before a warning event is generated>]
        [-searchserver <search server (leave empty to clear the search server)>]

Here’s an example of how to set all the properties of a content database:

stsadm –o gl-managecontentdbsettings -webapp "http://intranet/" -dbname intranet1_site_pair -status disabled -maxsites 15000 -warningsitecount 9000 -searchserver spsearchsvr

5 comments:

LenN said...

Greetings, Gary:

First, I love your contributions, thanks.

Second, how would I use a command to extract existing properties of a database? For example, I want to first see existing values for existing number of sites and Max Sites for a particular database on a particular farm before I go back and set the values.

I'm trying to use an extra content database for annual archival purposes. So the sites will be moved ( read export/imported ) to the archival database and left running for a calendar year,then detached, and replaced with a new archival database. I do not want ssc to have new sites going there, so I want to set MaxSites to whatever new value for existing sites, and see that confirmed as as followup to the Set.

Of course, with a good number of farms, databases and collections, I would rather use code than hitting all those CA pages manually.

Keep up the great work, sir!

Gary Lapointe said...

Your best bet would be to use some powershell to get and inspect the databases.

Anonymous said...

You can use the bellow cmd to check the site status:

$webApplication = Get-SPWebApplication("http://webapplication")
$contentDB=$webApplication.ContentDatabases
$contentDB|select CurrentSiteCount,WarningSiteCount,MaximumSiteCount,Id ,Name

Juran said...

Hi

I am trying to create a site's site collection. Once I create the site / Web application I try to create the site collection right after. It gives me an error: The Office SharePoint Server Standard Web application features feature must be activated at the web application level before this feature can be activated.

Right, now when I try to activate this feature it says access denied but I am set up as an administrator on the site with full access to everything. I can also chage the default port 80 site's stuff but not anything now?

This worked fine when I created previous sites?

What am I doing wrong?

Is there something I can do?

The Database was previously set up with a different user. Can it be that it still tries to use the previous account? If so, where can I go and chage the user of the content db?

Jurie

Benjamin Athawes said...

Pingback from http://suguk.org/forums/24564/ShowThread.aspx#24564

Thanks for the info.