Delete Web Application

Posted on Posted in SharePoint 2007, STSADM Commands

I had just finished creating the gl-createwebapp command and was about to go and delete the test web applications that I had created while testing the command and I discovered that there is no built in stsadm command for deleting a web application. I took a look at the code that is called when deleting via the browser and decided that it was simple enough that I could recreate it as a command – can’t have a create without a delete :).  The command I created is called gl-deletewebapp.

The only tricky spot I had was that there was a couple of pieces of code that required the use of internal classes – fortunately I’m getting pretty good at making calls to these internal classes so it didn’t really slow me down much. The main hang up was that the Unprovision() method of the SPWebApplication object doesn’t allow you to specify whether you want to delete the IIS web site or not – it just defaults to deleting it.

I wanted this command to function like the browser equivalent so I had to use the internal UnprovisionIisWebSites() method along with the RetractSolutions method of the SPSolutions class. And to make sure that I was mirroring the code executed when using the browser I had to also set a timer job using an internal only class (there’s gotta be a way around this one). The code to do all this is below:

   1: public override int Run(string command, System.Collections.Specialized.StringDictionary keyValues, out string output)
   2: {
   3:  output = string.Empty;
   4:  
   5:  InitParameters(keyValues);
   6:  
   7:  string url = Params["url"].Value;
   8:  bool deleteContent = Params["deletecontentdb"].UserTypedIn;
   9:  bool deleteIis = Params["deleteiiswebsite"].UserTypedIn;
  10:  
  11:  SPWebApplication webApp = SPWebApplication.Lookup(new Uri(url));
  12:  if (webApp.IisSettings.Count <= 0 && deleteContent)
  13:  {
  14:   DeleteContentDBs(webApp);
  15:   webApp.Delete();
  16:   return 1;
  17:  }
  18:  
  19:  int index = 0;
  20:  string[] serverComments = new string[webApp.IisSettings.Count];
  21:  string[] vdirs = new string[webApp.IisSettings.Count];
  22:  foreach (SPIisSettings iisSetting in webApp.IisSettings.Values)
  23:  {
  24:   vdirs[index] = iisSetting.Path.ToString();
  25:   serverComments[index] = iisSetting.ServerComment;
  26:   index++;
  27:  }
  28:  
  29:  // webApp.Unprovision() does not allow us to specify whether we want the site deleted so we have to use the internal version.
  30:  // SPWebApplication.UnprovisionIisWebSites(deleteIis, serverComments, webApp.ApplicationPool.Name);
  31:  MethodInfo unprovisionIisWebSites = webApp.GetType().GetMethod("UnprovisionIisWebSites",
  32:          BindingFlags.NonPublic | BindingFlags.Public |
  33:          BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Static,
  34:          null, new Type[] {typeof(bool), typeof(string[]), typeof(string)}, null);
  35:  
  36:  unprovisionIisWebSites.Invoke(webApp, new object[] { deleteIis, serverComments, webApp.ApplicationPool.Name });
  37:  
  38:  
  39:  // SPSolution.RetractSolutions(webApp.Farm, webApp.Id, vdirs, serverComments, true);
  40:  MethodInfo retractSolutions = typeof(SPSolution).GetMethod("RetractSolutions",
  41:       BindingFlags.NonPublic | BindingFlags.Public |
  42:       BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Static,
  43:       null, new Type[] {typeof(SPFarm), typeof(Guid), typeof(string[]), typeof(string[]), typeof(bool)}, null);
  44:  
  45:  retractSolutions.Invoke(null, new object[] { webApp.Farm, webApp.Id, vdirs, serverComments, true });
  46:  
  47:  
  48:  if (SPFarm.Local.TimerService.Instances.Count > 1)
  49:  {
  50:   // SPIisWebsiteUnprovisioningJobDefinition is an internal class so we need to use reflection to set it.
  51:  
  52:   // SPIisWebsiteUnprovisioningJobDefinition jobDef = new SPIisWebsiteUnprovisioningJobDefinition(deleteIis, serverComments, webApp.ApplicationPool.Name, vdirs, webApp.Id, true);
  53:   Type sPIisWebsiteUnprovisioningJobDefinitionType = Type.GetType("Microsoft.SharePoint.Administration.SPIisWebsiteUnprovisioningJobDefinition, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
  54:  
  55:   ConstructorInfo sPIisWebsiteUnprovisioningJobDefinitionConstructor =
  56:    sPIisWebsiteUnprovisioningJobDefinitionType.GetConstructor(
  57:     BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,
  58:     null,
  59:     new Type[] {typeof(bool), typeof(string[]), typeof(string), typeof(string[]), typeof(Guid), typeof(bool)}, null);
  60:   object jobDef = sPIisWebsiteUnprovisioningJobDefinitionConstructor.Invoke(new object[] { deleteIis, serverComments, webApp.ApplicationPool.Name, vdirs, webApp.Id, true });
  61:  
  62:  
  63:   // jobDef.Schedule = new SPOneTimeSchedule(DateTime.Now);
  64:   PropertyInfo scheduleProp = sPIisWebsiteUnprovisioningJobDefinitionType.GetProperty("Schedule",
  65:               BindingFlags.FlattenHierarchy |
  66:               BindingFlags.NonPublic |
  67:               BindingFlags.Instance |
  68:               BindingFlags.InvokeMethod |
  69:               BindingFlags.GetProperty |
  70:               BindingFlags.Public);
  71:  
  72:   scheduleProp.SetValue(jobDef, new SPOneTimeSchedule(DateTime.Now), null);
  73:  
  74:   // jobDef.Update();
  75:   MethodInfo update = sPIisWebsiteUnprovisioningJobDefinitionType.GetMethod("Update",
  76:              BindingFlags.NonPublic |
  77:              BindingFlags.Public |
  78:              BindingFlags.Instance |
  79:              BindingFlags.InvokeMethod |
  80:              BindingFlags.FlattenHierarchy,
  81:              null,
  82:              new Type[] { }, null);
  83:  
  84:  
  85:   update.Invoke(jobDef, new object[] { });
  86:  }
  87:  
  88:  if (deleteContent)
  89:   DeleteContentDBs(webApp);
  90:  
  91:  webApp.Delete();
  92:  
  93:  return 1;
  94: }
  95:  
  96:  
  97: private static void DeleteContentDBs(SPWebApplication webApp)
  98: {
  99:  foreach (SPContentDatabase db in webApp.ContentDatabases)
 100:  {
 101:   db.Unprovision();
 102:  }
 103: }

The syntax of the command can be seen below:

C:\>stsadm -help gl-deletewebapp

stsadm -o gl-deletewebapp

Deletes a web application.

Parameters:
        -url 
        [-deleteiiswebsite]
        [-deletecontentdb]

Here’s an example of how to delete a web application without deleting the IIS web site or the content database:

stsadm –o gl-deletewebapp -url "http://webappname"

Here’s another example which will delete the IIS web site and the content database:

stsadm -o gl-deletewebapp -url "http://webappname" -deleteiiswebsite -deletecontentdb

7 thoughts on “Delete Web Application

  1. This is sweet.

    It would be nice though if you could specify a farm item to delete, e.g,

    stsadm -o gl-deletewebapp -item “Farm\Windows SharePoint Services Web Application\webappname” -deleteiiswebsite -deletecontentdb

    Craig

  2. Hmm, when I specify -deleteiiswebsite, the site does not get deleted, though it did remove a host header. Any ideas?

  3. Not really sure why it’s not working. Any chance you can step through the code or add some Console.WriteLine statements to see what the execution path is? Are you getting any errors in the ULS logs or event log?

  4. I’m somewhat new to WSS. How do I import your webapp into my environment so I can try it?

    I have the problem where I tried extending a site, provisioning failed, and now I can’t extend or create any other site.
    Want to see if this will clean things up so I din’t have to re-install everything.

  5. Download the WSP file for your version (WSS or MOSS). Then run the following commands (using the MOSS version as an example):

    stsadm -o addsolution -filename c:\Lapointe.SharePoint.STSADM.Commands.WSP

    stsadm -o deploysolution -name Lapointe.SharePoint.STSADM.Commands.WSP -immediate -allowgacdeployment

    stsadm -o execadmsvcjobs

Leave a Reply

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

*