http://www.developer.com/

Back to article

Extend Your SharePoint Control with Custom Stsadm Commands


June 18, 2009

The SharePoint Team Services Administration application (stsadm), a command-line tool Microsoft introduced with SharePoint 2003, is the default way to administer and configure Windows SharePoint Services (WSS 3.0) and Microsoft Office SharePoint Server (MOSS), the company's premier tools for collaboration and knowledge workers. The 2007 version of stsadm offers an extended, richer set of commands, and introduces the ability to develop and configure custom commands.

Stsadm is a command-line program that doesn't provide an interface or other interaction with the user, making it a perfect candidate for use in scripts and automated operations. The program needs to run locally in one of the front-end SharePoint servers in the farm, and requires users to have administrative rights.

You can find stsadm in the directory C:\Program files\Common Files\microsoft shared\Web Server Extensions\12\BIN on any server where SharePoint is installed. To make stsadm usable directly from a command prompt without having to enter the complete path, add its path to the system variables: On the server, navigate to Start → Computer → Properties → Advanced system settings. In the window that appears, select Environment Variables from the Advanced tab, and add a new System variable. The next time that you want to use the tool, you can simply enter stsadm in the command line.

Command Set

Stsadm contains 184 instructions to manage and administer different aspects of SharePoint. If you execute the stsadm command with no arguments, a complete list of commands appears on the screen. The directives can be separated into several different categories:

  • Site maintenance: create, delete and enumerate sites
  • Web maintenance: create, delete and enumerate Webs and sub-Webs
  • User maintenance: add, delete, enumerate and migrate users
  • Manipulate SharePoint Objects: backup and restore, installation and management of WebParts, Features, Solutions, and templates
  • Server management: Add, delete, or enumerate databases, managed paths, Web Applications, and SharePoint Jobs

You can perform almost all these operations from the SharePoint interface; however, there are some exceptions, which you can execute only from the command-line stsadm tool:

  • Execadmsvcjobs: Forces all configured SharePoint Jobs to run immediately.
  • Createsiteinnewdb: Creates a new Site Collection using its own database.
  • Getproperty and setproperty: Supports configuring diverse SharePoint properties
    • Configures the number of days a "New" icon appears in new List and Library items
    • Configures scanning time if new alerts need to be sent
    • Configures the maximum number of Site templates
    • Configures the maximum size of Blobs to be used in SQL server

You can find the complete command list on-line. Here's the syntax for stsadm:

stsadm -o OperationName -ParameterValue"

For example, to review all sites under the portal, use stsadm -o enumsites -url http://ServerName, where enumsites is the operation name, url is the parameter name, and http://ServerName is the parameter value. The operation name is required; parameters may be obligatory or optional. When values contain spaces, place them inside quotation marks.

As stated previously, stsadm is not interactive, which means you must take care to ensure that parameters and syntax are written correctly. Also, if something is not defined accurately, the operation completes with an error message—leaving you to reinitiate the entire command. On the other hand, stsadm allows developers and administrators to create batch files that run various commands in a timely way. For example, an administrator might write a batch file that initiates Windows Task Scheduler and creates a new batch to generate nightly SharePoint backups. Developers might use the tool to install or uninstall SharePoint components by automatically integrating them in the Visual Studio script engine. For example, you might do this to install components after a successful compilation. 

When the built-in commands aren't enough, SharePoint 2007 supports the creation and configuration of custom stsadm operations. Although the default commands are extensive and quite complete, they don't include some operations of potential value to developers.

Two that come to mind immediately are:

  • Enumerating features in a site
  • The ability to delete web sites recursively

When you need such capabilities, creating new specialized, automatic commands can be extremely useful. The rest of this article shows how to build and add these two specialized custom commands to stsadm.

Programming New Commands

To generate new operations you need Visual Studio (2005 or 2008) and one of its default program languages (C# or VB). Launch Visual Studio and create a new project of the type "Class Library", giving it a unique name (ToolsSpsadm in the following example). The class should inherit from the ISPStsadmCommand Interface and must have at least two methods: GetHelpMessage and Run:

using System; 
using System.Collections.Specialized; 
using System.Text; 
using Microsoft.SharePoint; 
using Microsoft.SharePoint.StsAdmin;   
namespace ToolsSpsadm 
{
   public class ClassToolssSpsadm : ISPStsadmCommand  
   {
      public string GetHelpMessage(string command) {}
      public int Run(string command, 
         StringDictionary keyValues, out string output) {}
   }
}

The GetHelpMessage method runs with the stsadm help function and displays messages indicating its syntax and operation parameters. The example uses only one parameter (URL) to configure the URL of a site. The method looks like this:

public string GetHelpMessage(string command)
{
   return "-url <URL complete in Site and SharePoint>";
}

For example, to get help on the EnumerateFeatures command, you would use the command stsadm -help –EnumerateFeatures. That executes the GetHelpMessage method and the help message appears.

The Run method contains the source code to execute the operations. A switch statement selects one of the commands, if there is more than one in the class:

public int Run(string command, StringDictionary keyValues, 
   out string output)
{
   command = command.ToLowerInvariant();
   switch (command)
   {
      case "enumeratefeatures":  
         //Attention: all in lower case to prevent the error: 
         // 'Operation not valid because of the actual 
         // state of the object')
         return this.EnumerateFeatures(keyValues, out output); 
      case "eliminatewebrecursively ": 
         return this.EliminateWebRecursively(keyValues, out output); 
      default:
         throw new InvalidOperationException(); 
   } 
}

The example class exposes two commands: EnumerateFeatures and EliminateWebRecursively. The command parameter contains the name of the operation to be executed and the switch statement selects the matching method. Note that all strings are converted to lower case to prevent the error "Operation not valid because of the actual state of the object" that occurs if the case statement has any uppercase letters.

The first method, EnumerateFeatures, does just that: Given the URL of a site, it returns the installed and activated Features in that site:

private int EnumerateFeatures(
   StringDictionary keyValues, out string output)
{
   if (!keyValues.ContainsKey("url"))
      throw new InvalidOperationException(
         "The URL parameter was not specified"); 
   } 
   String myUrl = keyValues["url"];
   SPFeatureCollection AllFeatures = null;
   SPSite mySite = null;
   SPWeb myWeb = null;
   StringBuilder myOutput = new StringBuilder();
   try
   {
      mySite = new SPSite(myUrl);
      myWeb = mySite.OpenWeb();
      AllFeatures = myWeb.Features;
      myOutput.AppendLine("Features in '" + miWeb.Url + "':\n");  
      foreach (SPFeature oneFeature in AllFeatures)
      {
         myOutput.AppendLine(oneFeature.Definition.DisplayName + 
            "\t\t(" + oneFeature.DefinitionId + ")");
      }
   }
   catch (Exception ex)
   {
      throw new InvalidOperationException(
         "Error searching the URL '" + myUrl + 
         "'. Check the URL format and ensure that the Site exists." + 
         "Details: " + ex.Message);
   }
   finally 
   {
      if (mySite != null) mySite.Dispose();
      if (myWeb != null) myWeb.Dispose();
      myOutput.AppendLine("EnumerateFeatures finished");
   }
   output = myOutput.ToString();
   return 0;
}

The StringDictionary parameter contains pairs consisting of operation names and their values. The output parameter is a string that, at the end of the method, contains all the return data. The first lines check that the url parameter has been passed; otherwise, the method returns an error message and aborts the operation. Next, the code creates SharePoint objects to contain the Site, Web, and the Features Collection in that Web, and then instantiates them. Finally, it creates a StringBuilder to collect the output. After instantiating the SharePoint objects, it loops through the Features, appending information to the StringBuilder. If an error occurs, the method generates a general exception that indicates the type of problem. Finally, when the process completes, it disposes of the created SharePoint objects, and assigns the contents of the StringBuilder to the output string.

Adding a Recursive Site Delete Command

The second class method solves a default SharePoint issue: If there is a main web site with sub-sites, it is impossible to delete the main site directly. Instead, you must delete each sub-site before deleting the main site. This can be a messy and lengthy process if there are many sub-sites. The EliminateWebRecursively method deletes sub-sites recursively:

private int EliminateWebRecursively(
   StringDictionary keyValues, out string output)
{
   if (!keyValues.ContainsKey("url"))
   {
      throw new InvalidOperationException(
         "The URL parameter is not specified");
   }
   String myUrl = keyValues["url"];
   SPSite mySite = null;
   SPWeb myWeb = null;
   StringBuilder myOutput = new StringBuilder();
   try
   {
      mySite = new SPSite(myUrl);
      myWeb = mySite.OpenWeb();
      if (myWeb == null)  
         myOutput.AppendLine(
         "Web '" + myUrl + "' not found");
      else
      {
         if (mySite.Url == myWeb.Url)
         {
            throw new InvalidOperationException(
                  "Web '" + myUrl + "' not found");
         }
         RecursionEliminateWebs(myWeb.Webs);
         if (myWeb.Url == myUrl)
            myWeb.Delete();// This is the Top level Web 
      }
   }
   catch (Exception ex)
   {
      throw new InvalidOperationException(
         "Error searching the URL '" + myUrl + 
         "'. Check the URL format and ensure that " +
         "the site exists." + "Details: " + ex.Message);
   }
   finally
   {
      if (mySite != null) mySite.Dispose();
      if (myWeb != null) myWeb.Dispose();
      myOutput.AppendLine("EliminateWebRecursively is finished");
   }
   output = myOutput.ToString();
   return 0;
}

As you can see, the structure is very similar to the first method. It checks to ensure that the StringDictionary contains a url key and associated value, and that the value points to a valid site. After passing these checks, it calls the RecursionEliminateWebs function to eliminate all the sub-sites from the main site, from top to button:

private void RecursionEliminateWebs(SPWebCollection AllWebs)
{
   foreach (SPWeb oneWeb in AllWebs)
   {
      if (oneWeb.Webs.Count > 0)
      {
         RecursionEliminateWebs(oneWeb.Webs);
      }
      oneWeb.Delete();
   }
}

After the recursion completes, the calling code deletes the main site. The final block, again, disposes of the created objects and generates a success message.

Compile the class, signing it with a safe name, and copy the DLL to the Global Assembly Cache (GAC). To ensure that stsadm treats the code as one of its own operations, create an XML file in the directory C:\Program Files\Common Files\Microsoft shared\Web Server Extensions\12\CONFIG. The name of the file must have the form stsadmcommands.[UniqueName].xml. The example uses the name stsadmcommands.ToolsSpsadm.xml. The [UniqueName] portion may be any string or GUID and cannot be repeated in the directory. The file indicates the operation name and the class that contains the code. For this example, the XML file would look like this:

<?xml version="1.0" encoding="utf-8" ?>
<commands>
 <command
   name="EnumerateFeatures"
   class="ToolsSpsadm.ClassToolsSpsadm, ToolsSpsadm, 
      Version=1.0.0.0, Culture=neutral, 
      PublicKeyToken=98de5564275127d9"/>
 <command
   name="EliminateWebRecursively"
   class="ToolsSpsadm.ClassToolsSpsadm, ToolsSpsadm,
      Version=1.0.0.0, Culture=neutral,
      PublicKeyToken=98de5564275127d9"/>
  </commands>

Replace the name, class, Version, and PublicKeyToken with the appropriate values for your own code. At this point, stsadm should recognize the new methods and display the new operations in its list.

Author's Note: Avoid modifying the default XML file with custom command registration, because SharePoint Service Packs can overwrite that file, thus deleting your custom registration information.

One way to simplify the process is to create a custom solution to install the tools in SharePoint. The solution manifest copies the assembly to the GAC, and the XML configuration file to the correct directory:

<?xml version="1.0" encoding="utf-8" ?> 
<Solution xmlns="http://schemas.microsoft.com/sharepoint/" 
  SolutionId="5470D10C-573C-6ba3-920D-ABCD2DC73325"
  DeploymentServerType="WebFrontEnd">
  <Assemblies>
    <Assembly DeploymentTarget="GlobalAssemblyCache" 
      Location="ToolsSpsadm.dll" />
  </Assemblies>
  <RootFiles>
    <RootFile Location="CONFIG\stsadmcommands.ToolsSpsadm.xml"/>
  </RootFiles>
</Solution>

Install the Solution using stsadm and activate it from SharePoint Central Administration, or by using stsadm again.

As you can see, stsadm is the tool par excellence for SharePoint administrators and developers, letting them manage and configure the system in a swift and straightforward manner. Stsadm is not an interactive tool—it has no interface—but it works well as a command-line program, and may be used in combination with scripts to automate SharePoint tasks. By default, stsadm contains an extensive list of commands that cover almost all administrative tasks, but as this article has shown, if you find yourself performing tasks that stsadm lacks, you can create custom commands to fulfill those needs.

About the Author

Gustavo Velez is a Manager in the Solutions Development department at Avanade Netherlands, a global consultancy company. He has many years experience developing Windows and Office applications, and more than seven years of daily programming experience with SharePoint. The author's articles can be found in many of the leading trade magazines in English, Dutch, German and Spanish. He is also pleased to be Webmaster of http://www.gavd.net, the only Spanish-language site dedicated to SharePoint. Spanish-language readers may want to consult Velez's book, Programación con SharePoint 2007. His latest book, Workflows and SharePoint: Going with the Flow went on the market in March, 2009. Velez has been awarded MVP status for SharePoint MOSS.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date