Extending SharePoint STSADM Command Line Utility


Today I tried creating a Stsadm command line utility extension provided by the SharePoint platform and therefore I followed instructions specified on MSDN site, a very good article can be found here.

Sometimes we want to perform some tasks related to SharePoint sites, but somehow we end up facing errors when done using the UI, or some settings which explicitly need to be done using code behind. So instead of writing multiple console applications to execute these operations on the server, this time I decided to write a customer Stsadm command.

The example below shows how we can change the culture of the web, I have already posted about this when I was doing this using a console application so th code remains the same but some modifications in the functions.

First of all we need to understand how Stsadm works; when you go to 12 hive folder you will see a folder with the name "CONFIG". All the Stsadm commands are kept in this location. So when you create your own commands then you need to have a definition file which we need to place in 12\CONFIG folder with a naming convention like Stsadmcommands.sample.xml (note : the word sample could be anything as you want).

Then we need to have a class file which will act as code behind for the command. The class should be inheriting from the OOB interface ISPStsadmCommand. Once this is done then we need to implement two methods of this interface in a custom class.

#region ISPStsadmCommand Members

 

string ISPStsadmCommand.GetHelpMessage(string command)

{

   throw new NotImplementedException();

}

 

int ISPStsadmCommand.Run(string command, StringDictionary keyValues, out string output)

{

    throw new NotImplementedException();

}

 

#endregion

Ok so far so good, before diving into the code, people might have a question like, why one should create these for? And the answer is:

There are some times when we want to perform certain operations on SP platform and we end up writing a number of customer console applications for each of those operations: this can simplify the approach as we can write multiple commands in a single file and use them.

Some good operation using Stsadm (not available with OOB SP STSADM) are done by Gary lapointe, and you can take a look at those here.

 

Here is the definition file with syntax:

<?xml version="1.0" encoding="utf-8" ?>

<commands>

<command name="setwebculture" class="MyCustomStsadmCommand.ChangeWebLocale,   MyCustomStsadmCommand,

  Version=1.0.0.0,

  Culture=neutral,

  PublicKeyToken=64622bec6a4399fa"/>

</commands>

and here is the code behind:

 

namespace MyCustomStsadmCommand

{

 public class ChangeWebLocale : ISPStsadmCommand

 {

  #region ISPStsadmCommand Members

 

  public string GetHelpMessage(string command)

  {

     return "-url <full url to a root web in SharePoint Site Collection> -culturename -recursive";

  }

 

  public int Run(string command, StringDictionary keyValues, out string output)

  {

     command = command.ToLowerInvariant();

 

     switch (command)

     {

       case "setwebculture":

        return this.ChangeCulture(keyValues, out output);

 

       default:

         throw new InvalidOperationException();

      }

 

   }

 

   private int ChangeCulture(StringDictionary keyValues, out string output)

   {

     if (!keyValues.ContainsKey("url"))

     {

      throw new InvalidOperationException("The url parameter was not specified.");

     }

     if (!keyValues.ContainsKey("culturename"))

     {

      throw new InvalidOperationException("The CultureName parameter was not specified.");

     }

 

     String url = keyValues["url"];

     String cultureName = keyValues["culturename"];

     String recursive = keyValues["recursive"];

     bool _isRecursive = false;

     if (string.IsNullOrEmpty(recursive))

     {

       recursive = "False";

     }

     bool _IsRecursive = bool.TryParse(recursive, out _isRecursive);

 

     SPWeb web = null;

     StringBuilder sb = null;

 

     try

     {

       CultureInfo _cultureInfo = new CultureInfo(cultureName);

       sb = new StringBuilder();

       using (SPSite site = new SPSite(url))

        {

         using (web = site.OpenWeb())

         {

           if (_isRecursive)

           {

             RecursiveChangeCulture(web, _cultureInfo, sb);

           }

           else

           {

             web.AllowUnsafeUpdates = true;

             web.Locale = _cultureInfo;

             web.Update();

             web.AllowUnsafeUpdates = false;

             sb.AppendLine("culture changed for " + web.Title + " to " + _cultureInfo.EnglishName);

            }

          }

         }

      }

      catch (Exception ex)

      {

       throw new InvalidOperationException("Error Details: " + ex.Message);

      }

 

     output = sb.ToString();

     sb.Remove(0, sb.Length);

     return 0;

   }

 

 private void RecursiveChangeCulture(SPWeb web, CultureInfo _c, StringBuilder _sb)

 {

    if (web != null)

    {

     web.AllowUnsafeUpdates = true;

     CultureInfo _previousLocale = web.Locale;

     web.Locale = _c;

     _sb.AppendLine("culture changed for " + web.Title + " from " + _previousLocale.EnglishName + " to " + _c.EnglishName);

     web.Update();

     web.AllowUnsafeUpdates = false;

 

     foreach (SPWeb _web in web.Webs)

     {

         RecursiveChangeCulture(_web, _c, _sb);

     }

  }

 }

 

 #endregion

}

}