A Better Delete Web

Posted on Posted in SharePoint 2007, STSADM Commands

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;
  11:  
  12:  InitParameters(keyValues);
  13:  
  14:  string url = Params["url"].Value.TrimEnd('/');
  15:  
  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:   }
  23:  
  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:   }
  31:  
  32:   if (web.Webs.Count > 0 && Params["recurse"].UserTypedIn)
  33:    DeleteSubWebs(web.Webs);
  34:  
  35:   web.Delete();
  36:  
  37:  }
  38:  
  39:  return 1;
  40: }
  41:  
  42: #endregion
  43:  
  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);
  54:  
  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.

Parameters:
        -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

24 thoughts on “A Better Delete Web

  1. 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.

  2. Gary,

    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….

    😛

    Dre

  3. 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 🙂

  4. Hi,
    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)
    DeleteSubWebs(web.Webs);

    web.Delete();
    }
    }
    }

  5. 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).

  6. Hi

    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

  7. 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.

  8. Hi, I am new to Shareppoint and have a issue deleting a site. It tells me that it cant delete the site as it has subsites but it does not seem to have any subsites.
    I thought this code may be worth giving a go.
    What do I need to do to make the code into a file? do i just copy it in to notepad and rename it as .aspx?

    Any help will be appreciated. Cheers.

    1. The code in the post is just showing what I put into the WSP that you can deploy to your servers. Go to the downloads page and download the WSP for your environment, then install per the instructions on the downloads page. You should be able to run the command as shown in the post.

  9. Hi Gary,

    when I run stsadm -help gl-deleteweb2 there is no gl-deleteweb2 operation. There are a handful of other gl operations, but not the one sepcified. I added and deployed your Lapointe.SharePoint.STSADM.Commands.wsp, am I missing something here?

    Thanks!

    1. Not sure why it isn’t showing up for you. Are you sure you typed it correctly? Did this file, stsadmcommands.wss.lapointe.xml, get deployed to the config directory? (I’ve not seen it with this package but with other things I’ve worked on I’ve seen issues where sometimes some files don’t get deployed properly – but you’d have an error in CA for the solution if that’s the case).

  10. Just downloaded and installed your stsadm pak for WSS 3.0 and it works.
    However I still have some sites that have “ghost” subsites so I cant delete these sites…. neither from your tool or from the webinterface.
    And Iam pretty sure those sites dont have and never had any subsites.

    Is there a way to use your tool to delete sub sites of a specified site only. (And not delete the specified site)??
    I have some sites where sub sites are created and I sometimes wish to delete all these sites, but I dont want to delete the site they are created on.

    Thanks for a great tool!

  11. Hi,

    This my code to delete files in specify folder in MOSS2007 by powershell.
    How I can recurse this scripts to delete subfolders and files ?

    param([string]$weburl,[string]$day)
    [void][System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.SharePoint”)

    $today= Get-Date

    $site = New-Object microsoft.sharepoint.spsite($weburl)
    $web = $site.openWeb()
    $sourcefolder=$web.GetFolder($weburl)
    $sourcefolder.name
    $sourcefolder.ParentFolder.Name
    $liste=$web.GetFolder($weburl)

    [INT]$j=$liste.Files.Count

    for([INT]$i=0; $i -lt $j;$i++)
    {
    [STRING]$nom=$liste.Files[$i].name
    if ($nom -ne “”) {
    write-output $liste.Files[$i].TimeLastModified
    $diff = $today – $liste.Files[$i].TimeLastModified
    Write-Output $diff.Days
    Write-Output $liste.Files[$i].name
    Write-Output $day
    if ($diff.days -ge $duree) {
    $liste.Files[$i].delete()
    Write-Output $liste.Files[$i].name “delete”
    $i–
    }
    else
    { Write-Output $liste.Files[$i].name “not delete”}
    }
    }
    $site.Dispose()

Leave a Reply

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

CAPTCHA

*