Friday, July 29, 2011

Exporting IE Bookmarks/Favorites programmatically / .NET

A thought came in my mind yesterday while I was sitting idle and doing nothing (except browsing on InternetJ).. Thought was to get the list of URLs through .NET code which we save or mark using browser IE as favorites.
We all know that when we mark as any URL as favorite using UI in IE then it gets saved in the favorites folder of user. to take a look , I opened favorites folder and found that all the shortcuts gets saved in the form of .url file. These .url files are nothing but the Internet Shortcuts which points to the location of actual URL.
So just to try some hands on I opened the developer’s heaven (VS) and started by creating a sample console application. And here is the code which I managed to achieve what I was thinking.
there is option to export the all bookmarked URL either to XML or HTML format in Firefox (at least in latest version) also google chrome has this option to export all bookmarks to HTML but when came to IE I didn’t find any option. so I have tried creating a utility which exports all your bookmarked URLs to a HTML file.
HTML file gets created in same directory where you are executing the exe.
There might be different ways doing same but I pasted what I done.. so your views and suggestions are always welcome J
class Program
{
  private static string _favouritesPath = string.Empty;
  private static string _previousDirectoryName = string.Empty;
  private static string _currentDirectory = string.Empty;
  private static string _fileName = string.Empty;

  static void Main(string[] args)
  {
    try
    {
      _favouritesPath = Environment.GetFolderPath(Environment.SpecialFolder.Favorites);
      if (!string.IsNullOrEmpty(_favouritesPath))
      {
        DirectoryInfo di = new DirectoryInfo(_favouritesPath);
        _currentDirectory = Environment.CurrentDirectory;
        TextWriter _writer = new StreamWriter(_currentDirectory + "\\BookMarks.htm", false);

        if (di != null)
        {
          FileInfo[] _files = di.GetFiles("*.url", SearchOption.AllDirectories);
          if (_files != null && _files.Length > 0)
          {
           foreach (FileInfo _file in _files)
           {
             if (_file.Exists)
             {
               _fileName = _file.Name.Split('.').FirstOrDefault().ToString();
               StreamReader _reader = _file.OpenText();
               string _allContents = _reader.ReadToEnd();
               string[] _splits = _allContents.Split(new char[] { '=', '[' }, StringSplitOptions.RemoveEmptyEntries);
               if (_splits.Length > 0 && !string.IsNullOrEmpty(_splits[1]))
               {
                 if (!string.Equals(_file.Directory.Name, _previousDirectoryName))
                 {
                   _writer.Write("</br>");
                   //<b style="color: Green;"></b>
                   _writer.Write("<b style=\"color: Green;\">" + _file.Directory.Name + "</b>");
                   _writer.Write("</br>");
                    _writer.Write(string.Format("{0}<a href=\"{1}\">{2}</a>", " ------ ", _splits[1], _fileName));
                 }
                else
                {
                  _writer.Write("</br>");
                  _writer.Write(string.Format("{0}<a href=\"{1}\">{2}</a>", " ------ ", _splits[1], _fileName));

                }

              }
             _previousDirectoryName = _file.Directory.Name;
            }
           }
          }
         }

         _writer.Close();

       }
      }
      catch (Exception ex)
      {
        Console.WriteLine(string.Format("{0}-{1}", "Error:", ex.Message));
      }
       Console.WriteLine("File Created..press any key to exit..");                   Console.ReadLine();
     }
    }

Tuesday, July 26, 2011

Extending SharePoint STSADM Command Line Utility


Today I tried creating extending stsadm command line utility given by SharePoint platform and followed instructions specified on MSDN site, a very good article can be found here.
Sometimes we want to perform some tasks related to SharePoint sites , but somehow we end up with facing errors when done using UI , or some settings which explicitly need to be done using code behind. so instead writing number of console applications to execute these operations on server , this time I decided to write customer stsadm command.
Example below shows how we can change the culture of the web, I have already posted about this when I was doing this using console application so code remains the same but some modifications in the functions
First of all we need to understand how stsadm works, when you go to 12 hive folder you will see folder with name “CONFIG” . All the stsadm commands are kept in this location. so when you create your own commands then you need to have a definition file which we need to place in 12\CONFIG folder with naming convention like  stsadmcommands.sample.xml (note : word sample could be anything as you want).
then we need to have a class file which will act as code behind for the command. class should be inheriting from the OOB interface ISPStsadmCommand. Once this is done then we need to implement two methods of this interface in custom class
#region ISPStsadmCommand Members

string ISPStsadmCommand.GetHelpMessage(string command)
{
   throw new NotImplementedException();
}

int ISPStsadmCommand.Run(string command, StringDictionary keyValues, out string output)
{
    throw new NotImplementedException();
}

#endregion
Ok so far so good, before diving into the code, people might have question like, why one should create these for? And answer is,
There are some times when we want to perform certain operations on SP platform and we end up with writing number of customer console applications for each of those operations , this can simplify the approach as we can write bunch of commands in single file and use them.
Some good operation using stsadm (not available with OOB SP STSADM) are done by Gary lapointe, and you can take a look at those here.

Here is the definition file with syntax
<?xml version="1.0" encoding="utf-8" ?>
<commands>
<command name="setwebculture" class="MyCustomStsadmCommand.ChangeWebLocale,   MyCustomStsadmCommand,
  Version=1.0.0.0,
  Culture=neutral,
  PublicKeyToken=64622bec6a4399fa"/>
</commands>
and here is the code behind

namespace MyCustomStsadmCommand
{
 public class ChangeWebLocale : ISPStsadmCommand
 {
  #region ISPStsadmCommand Members

  public string GetHelpMessage(string command)
  {
     return "-url <full url to a root web in SharePoint Site Collection> -culturename -recursive";
  }

  public int Run(string command, StringDictionary keyValues, out string output)
  {
     command = command.ToLowerInvariant();

     switch (command)
     {
       case "setwebculture":
        return this.ChangeCulture(keyValues, out output);

       default:
         throw new InvalidOperationException();
      }

   }

   private int ChangeCulture(StringDictionary keyValues, out string output)
   {
     if (!keyValues.ContainsKey("url"))
     {
      throw new InvalidOperationException("The url parameter was not specified.");
     }
     if (!keyValues.ContainsKey("culturename"))
     {
      throw new InvalidOperationException("The CultureName parameter was not specified.");
     }

     String url = keyValues["url"];
     String cultureName = keyValues["culturename"];
     String recursive = keyValues["recursive"];
     bool _isRecursive = false;
     if (string.IsNullOrEmpty(recursive))
     {
       recursive = "False";
     }
     bool _IsRecursive = bool.TryParse(recursive, out _isRecursive);

     SPWeb web = null;
     StringBuilder sb = null;

     try
     {
       CultureInfo _cultureInfo = new CultureInfo(cultureName);
       sb = new StringBuilder();
       using (SPSite site = new SPSite(url))
        {
         using (web = site.OpenWeb())
         {
           if (_isRecursive)
           {
             RecursiveChangeCulture(web, _cultureInfo, sb);
           }
           else
           {
             web.AllowUnsafeUpdates = true;
             web.Locale = _cultureInfo;
             web.Update();
             web.AllowUnsafeUpdates = false;
             sb.AppendLine("culture changed for " + web.Title + " to " + _cultureInfo.EnglishName);
            }
          }
         }
      }
      catch (Exception ex)
      {
       throw new InvalidOperationException("Error Details: " + ex.Message);
      }

     output = sb.ToString();
     sb.Remove(0, sb.Length);
     return 0;
   }

 private void RecursiveChangeCulture(SPWeb web, CultureInfo _c, StringBuilder _sb)
 {
    if (web != null)
    {
     web.AllowUnsafeUpdates = true;
     CultureInfo _previousLocale = web.Locale;
     web.Locale = _c;
     _sb.AppendLine("culture changed for " + web.Title + " from " + _previousLocale.EnglishName + " to " + _c.EnglishName);
     web.Update();
     web.AllowUnsafeUpdates = false;

     foreach (SPWeb _web in web.Webs)
     {
         RecursiveChangeCulture(_web, _c, _sb);
     }
  }
 }

 #endregion
}
}