Community Server Extraction Tool

[If you're looking for the properties article, click here]

*nix and Windows folks can argue back and forth about any aspect of their operating system — graphics, ease of use, functionality etc and pretty much keep toe to toe. But Windows SUCKS ROYALLY when it comes to remote administration. Really.

For instance, AfricaDotNet is hosted on a windows box, and the only means they allow me to interface is some ludicrous control panel application that leaves me at the mercy of the imagination of the developers. This particular control panel makes heavy use of Ajax, so refreshing pages does not work when it invariably times out. Everything is buried in hundreds of clicks and icons.

The biggest problem is that I cannot interact with the windows box on my terms. I can’t telnet, I can’t remote desktop. I am stuck with that doofusy web application.

I long for the day I can putty or better yet remotely open a command windows (on PowerShell) that allows me to use tools much taken for granted like wget …

 

Problem

 

The folks at Telligent kindly donated a professional licence for their excellent CommunityServer. The DotNetNuke we had used had become a howling dog and the next time I hear DNN it will be too soon.

 So the first step is to actually get the software into the server. Since I can’t remote desktop or telnet, I am forced to download the installer to my own box and then FTP it up to the server. With the sinking feeling that the control panel does not allow me to unzip files at server side, I looked for the feature.

No such luck.

So I extracted the files onto my disk and checked the properties. Yikes! Several thousand files over several hundred folders. Uploading that over a dialup CDMA (charged by the minute!) would keep me busy for at least a calendar month, and lighter of the pocket to boot!

And then it occurred to me — could I not write a small web application that could unzip files at the server side?

I could!

When it comes to unzipping files, at no cost, two obvious options come to mind

  1. The excellent SharpZipLib
  2. J#’s java.util.zip

I chose the former because i don’t want to start mucking around with J# (No offence, J#!). J# has always struck me as the oddbod cousin from out of town. Which is nothing compared to JScript.NET. But I digress.

 

Design

 

The design is pretty straightforward

  1. Build an asp.net page that accepts a zip filename in a textbox, and a button
  2. Clicking the button extracts the zipfile to the current folder

The actual events after clicking the button are as follows:

  • Check if the zip file exists
  • Determine the current location on the server side
  • Open the zip file
  • Extract each entry in the zip file
  • Create the directories and files as appropriate
  • Inform the user of the success, or lack therefore

The only requirement is the SharpZipLib library, which you can get here. It also manipulates tar, gzip and a few other files

 

Code

 

The code is pretty straightforward, as shown. The bulk of it is in the button click event. Perhaps later I will get around to extracting it into a class of its own

 

   1: protected void Button1_Click(object sender, EventArgs e)
   2: {
   3:     //  Get the location of the zip file on the server side
   4:     string CommunityServerZipFile = Server.MapPath(string.Format(@"~/{0}", txtName.Text));
   5:     // Get the log file name
   6:     string installLogFile = Server.MapPath("~/Log.txt");
   7:     //some temporary variables
   8:     string directoryToCreate = string.Empty;
   9:     string fileToCreate = string.Empty;
  10:     StringBuilder sb = new StringBuilder();
  11:     //
  12:     // Check if the fule exists!
  13:     //
  14:     if (!File.Exists(CommunityServerZipFile))
  15:         lbl.Text = "Could not find the community server zipfile!";
  16:     else
  17:     {
  18:         try
  19:         {
  20:             //
  21:             // Begin capturing our log messages
  22:             //
  23:             sb.AppendLine(string.Format("Started at {0}", DateTime.Now));
  24:             //
  25:             // Open the stream
  26:             //
  27:             ZipInputStream s = new ZipInputStream(File.OpenRead(CommunityServerZipFile));
  28:             ZipEntry theEntry;
  29:             //
  30:             // Loop through the zip file file looking for all entries
  31:             //
  32:             while ((theEntry = s.GetNextEntry()) != null)
  33:             {
  34:                 string directoryName = Path.GetDirectoryName(theEntry.Name);
  35:                 string fileName = Path.GetFileName(theEntry.Name);
  36:                 //
  37:                 // create directory
  38:                 //
  39:                 directoryToCreate = string.Format("~/{0}", directoryName);
  40:                 if (!Directory.Exists(Server.MapPath(directoryToCreate)))
  41:                     Directory.CreateDirectory(Server.MapPath(directoryToCreate));
  42:                 //
  43:                 // create file
  44:                 //
  45:                 if (fileName != String.Empty)
  46:                 {
  47:                     fileToCreate = Server.MapPath(string.Format("~/{0}", theEntry.Name));
  48:                     FileStream streamWriter = File.Create(fileToCreate);
  49:                     sb.AppendLine(string.Format("Created file: {0}", fileToCreate));
  50:                     int size = 2048;
  51:                     byte[] data = new byte[2048];
  52:                     //
  53:                     // This extra check allows empty files to be created
  54:                     //
  55:                     if (theEntry.Size > 0)
  56:                     {
  57:                         while (true)
  58:                         {
  59:                             size = s.Read(data, 0, data.Length);
  60:                             if (size > 0)
  61:                                 streamWriter.Write(data, 0, size);
  62:                             else
  63:                                 break;
  64:                         }
  65:                     }
  66:                     streamWriter.Close();
  67:                 }
  68:             }
  69:             s.Close();
  70:             sb.AppendLine(string.Format("Succeeded at {0}", DateTime.Now));
  71:             File.AppendAllText(installLogFile, sb.ToString());
  72:             lbl.Text = "Extraction complete!";
  73:             hl.Visible = true;
  74:         }
  75:         catch (Exception ex)
  76:         {
  77:             lbl.Text = ex.Message;
  78:             sb.AppendLine(string.Format("{0} Aborted at {1}", ex.Message,DateTime.Now));
  79:         }
  80:     }
  81: }

 

Play close attention to this bit:

 

   1: if (theEntry.Size > 0)
   2: {
   3:     while (true)
   4:     {
   5:         size = s.Read(data, 0, data.Length);
   6:         if (size > 0)
   7:             streamWriter.Write(data, 0, size);
   8:         else
   9:             break;
  10:     }
  11: }
  12: streamWriter.Close();

 

Why? Because zero length files are a perfectly acceptable occurence. Much of the code i’ve seen seems to ignore this fact. CommunityServer has several zero length files. If you don’t put that check the following line will trip up completely

 

   1: size = s.Read(data, 0, data.Length);
   2: if (size > 0)

 

Why? Because data.Length will evaluate to a big fat zero and the CLR will throw an exception

I believe the rest is fairly straight forward, but let me know if not.

I have also attached the complete webpage and included DLLs should you need to extract community server at the servers die.

BTW the code assumes you have zipped the CONTENTS of the CommunityServer web folder, not the folder itself. If you extract in the root, the files will come out expecting to be in the root.

 

Caveats

 

  • The Identity you run your web application as must have read/write permissions to your folder in the web server
  • Once done delete the extraction tool, or enhance it so it doesn’t run twice. It will happily overwrite your files, including modified ones like web.config
  • You will need ASP.NET on the server. I’ve run it on v 2.0.

 

Results

 

After 5 minutes of coding and uploading, the site is now up and running, saving Yay!!!

Have fun!

 

Downloads

Community Server Extraction Tool. This is the complete source, (RARed) and not the published website so you can be sure I’m not formatting your hard disk behind the scenes :). Usual disclaimers apply — I take no responsibility for any way you might shoot yourself in the foot

kick it on DotNetKicks.com

 

Other posts

2 responses


  1. > I long for the day I can putty or better yet remotely open a command windows (on PowerShell) that allows me to use tools much taken for granted like wget …

    Yup. We’re working on it.

    Jeffrey Snover [MSFT]
    Windows PowerShell/MMC Architect
    Visit the Windows PowerShell Team blog at: http://blogs.msdn.com/PowerShell
    Visit the Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx


  2. Great solution to a common headache… thanks!

Leave a Reply