I've moved my blog to!. 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.

Thursday, September 20, 2007

A Better Delete Web

I recently had to use the built-in deleteweb command to delete a web site and was irritated to find that the command wouldn't let me delete the web because it had sub-webs. I simply couldn't live with that as it's extremely frustrating to have to delete all the child webs one at a time. So I created a better deleteweb command, called simply gl-deleteweb2. It behaves exactly like the built-in deleteweb command except that you can pass in a "recurse" switch to have it delete recursively (delete the web and all it's children). What was really nice is that it took me literally 2 minutes to create this command (nice change from some of the more challenging ones I've had lately).

The code is extremely simple:

   1: /// <summary>
   2: /// Runs the specified command.
   3: /// </summary>
   4: /// <param name="command">The command.</param>
   5: /// <param name="keyValues">The key values.</param>
   6: /// <param name="output">The output.</param>
   7: /// <returns></returns>
   8: public override int Run(string command, StringDictionary keyValues, out string output)
   9: {
  10:  output = string.Empty;
  12:  InitParameters(keyValues);
  14:  string url = Params["url"].Value.TrimEnd('/');
  16:  using (SPSite site = new SPSite(url))
  17:  using (SPWeb web = site.OpenWeb())
  18:  {
  19:   if (web.IsRootWeb)
  20:   {
  21:    throw new SPException(SPResource.GetString("CannotDelRootwebByDelweb", new object[0]));
  22:   }
  24:   if (web.Webs.Count > 0 && !Params["recurse"].UserTypedIn)
  25:   {
  26:    throw new SPException(
  27:     string.Format(
  28:      "Error deleting Web site \"{0}\".  You can't delete a site that has subsites unless you pass the \"recurse\" flag into the command.",
  29:      web.ServerRelativeUrl));
  30:   }
  32:   if (web.Webs.Count > 0 && Params["recurse"].UserTypedIn)
  33:    DeleteSubWebs(web.Webs);
  35:   web.Delete();
  37:  }
  39:  return 1;
  40: }
  42: #endregion
  44: /// <summary>
  45: /// Deletes the sub webs.
  46: /// </summary>
  47: /// <param name="webs">The webs.</param>
  48: private static void DeleteSubWebs(SPWebCollection webs)
  49: {
  50:  foreach (SPWeb web in webs)
  51:  {
  52:   if (web.Webs.Count > 0)
  53:    DeleteSubWebs(web.Webs);
  55:   web.Delete();
  56:  }
  57: }

Use this command just like deleteweb but pass in "-recurse" if you want to delete a web with sub-webs (this keeps the action explicit so the user understands that it will delete all sub-webs). The syntax of the command can be seen below:

C:\>stsadm -help gl-deleteweb2

stsadm -o gl-deleteweb2

Deletes a web.

        -url <url of web to delete>
        [-recurse (delete all sub-sites)]

Here’s an example of how to delete a web recursively:

stsadm –o gl-deleteweb2 -url "http://intranet/WebWithChildren" -recurse


Phodchara said...

im used this command line delete subsite, but can't. that error showed "Cannot complete this action. Please try it again." How i can delete this subsite site?

Gary Lapointe said...

Unfortunately I can't help you with this one. I've seen this error a few times though never when trying to delete a web. I've searched in vain to find something about this error but the error occurs within an unmanaged assembly so I can't see what would typically cause this error in code. You may want to try deleting all the sub-sites manually or deleting from the browser (that will at least tell you which site is specifically having issues). Beyond that you're best bet will be to contact Microsoft.

moti said...

is a good idea

Anonymous said...


just used your extensions to delete a web with many many subsites (30+) - worked like a charm. Thank you for providing this valuable tool. It saved me a LOT of time....



Skooter said...

Hi, will this also work with WSS 2.0? Hope I don't sound too nooby, hehe.

Gary Lapointe said...

Unfortunately no - all these commands are specific to WSS v3/MOSS 2007. However, some of the APIs are the or at least real close with WSS2 so it might be possible to refactor some of the code to work with v2 but you'd be on your own with that one :)

Orlando said...

Great work you've got here.
In this particular command (gl-deleteweb2) there is a memory leak in the DeleteSubWebs method. You're not disposing the deleted SPWeb object.
This is my rewrite of your method to dispose the deleted web.

private static void DeleteSubWebs(SPWebCollection webs)
int webCount = webs.Count;
for (int i = webCount - 1; i >= 0; i--)
using (SPWeb web = webs[i])
if (web.Webs.Count > 0)


Gary Lapointe said...

Thanks for the feedback. I have a fix for that which will go out later today.

venkatx5 said...

Where to paste the .cs code and compile? How can I change the stsadm.exe file?

Gary Lapointe said...

Venkatx5 - download the WSP (from the downloads page) and deploy using the instructions provided on that page - there's no need to do anything with the source (I just provide that for reference).

P Cooney said...


Thanks for this tool, I'm sure it works but not for me.

I get the following:

C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN>stsa
dm -o gl-deleteweb2 -url http://dslwnsharepoint/sysmgmt/css/mch/ -recurse

Error deleting Web site "/sysmgmt/css/mch/opp2". You can't delete a site that has subsites.

so same as before I loaded the command

Any suggestions

Gary Lapointe said...

My code basically just does a recursive delete starting at the leaf webs and working it's way up the chain. If it isn't deleting a child then most likely you don't have access to the child or it's been orphaned so the Webs collection isn't getting populated correctly. Make sure you are the site collection admin and if so try running the databaserepair command.