Access denied error when adding new server to existing SharePoint 2007 Farm

I recently got an error when adding a new SharePoint 2007 (SP2) server to our existing MOSS farm.  I had run the installation fine, and was walking through the SharePoint Configuration Wizard, when I got an error on step 2: “Resource retrieved id PostSetupConfigurationFailedEventLog is Configuration of SharePoint Products and Technologies failed.”

I searched the net, but didn’t really find anything.

I then remembered that I had forgotten to run the latest SharePoint updates (for us, the latest applied was December 2009).  I installed the WSS update, and then the MOSS update and both worked fine.  I then ran the Configuration wizard again and it worked without any errors.

Integrating Windows Form Click Once Application into SharePoint 2007 – Part 2 of 4

In my last post, I explained why we decided to use a Click Once application to solve our business problem. To quickly review, we needed a way for our business users to upload documents to a SharePoint 2007 document library in mass, set the meta data, set the permissions per document, and to do so easily.

Let’s look at the pieces that make up our solution.  First, we have the Windows Form application.  This app is deployed using Click Once and calls SharePoint web services in order to upload files and then calls web services to set the meta data (SharePoint columns and permissions).  Second, we have a custom action.  The custom action is responsible for providing our users a link that will launch the Windows app, as well as passing values to it via the query string.  And lastly, we have the web services that the Windows Form application calls.  For our solution, we used both out of the box web services and a custom web service in order to set the column values in the document library as well as the permissions on the documents.

Now, let’s look at the technical details of each of these pieces.  (All of the code is downloadable from here: )

 

Windows Form application deployed via Click Once

The Windows Form application, called “Custom Upload”, has just a few classes in it:

  • Custom Upload -- the form
  • FileList.xsd -- the dataset used to track the names of the files and their meta data values
  • SharePointUpload -- this class handles uploading the file

SharePointUpload uses an HttpWebRequest to transfer the file to the web server. We had to change this code from a WebClient object to the HttpWebRequest object, because we needed to be able to set the time out value. 

        public bool UploadDocument(string localFilename, string remoteFilename)
        {
            bool result = true;

            //Need to use an HttpWebRequest object instead of a WebClient object
            //  so we can set the timeout (WebClient doesn't allow you to set the timeout!)
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(remoteFilename);

            try
            {
                req.Method = "PUT";
                req.Timeout = 60 * 1000; //convert seconds to milliseconds
                req.AllowWriteStreamBuffering = true;
                req.Credentials = System.Net.CredentialCache.DefaultCredentials;
                req.SendChunked = false;
                req.KeepAlive = true;

                Stream reqStream = req.GetRequestStream();
                FileStream rdr = new FileStream(localFilename, FileMode.Open, FileAccess.Read);
                byte[] inData = new byte[4096];
                int bytesRead = rdr.Read(inData, 0, inData.Length);

                while (bytesRead > 0)
                {
                    reqStream.Write(inData, 0, bytesRead);
                    bytesRead = rdr.Read(inData, 0, inData.Length);
                }

                reqStream.Close();
                rdr.Close();

                System.Net.HttpWebResponse response = (HttpWebResponse)req.GetResponse();
                if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Created)
                {
                    String msg = String.Format("An error occurred while uploading this file: {0}\n\nError response code: {1}",
                        System.IO.Path.GetFileName(localFilename),
                        response.StatusCode.ToString());

                    LogWarning(msg, "2ACFFCCA-59BA-40c8-A9AB-05FA3331D223");

                    result = false;
                }
            }
            catch (Exception ex)
            {
                LogException(ex, "{E9D62A93-D298-470d-A6BA-19AAB237978A}");
                result = false;
            }

            return result;
        }

The class also contains the LogException() and LogWarning() methods.

When the application is launched, it parses the query string for some initial values.  The query string looks like this:

                string queryString = "Srv=clickonce&Sec=N&Doc=DMI&SiteName=&Speed=128000&Max=50";

This Srv is the path to the server (my Virtual Machine is name “clickonce”), the Sec is short for security – meaning HTTPS or HTTP, the Doc is the shortcut for which document library to use, and SiteName is the name of the SharePoint site.  Speed is used to calculate an estimate for download speed for each file.  We added this so our users uploading documents would realize how long it might take for clients in remote locations (using slow WAN connections) to download the documents.

The last value, Max, is the maximum size that the SharePoint site will allow documents to be.  This allowed us to give users a warning that a file is too large before we even attempt to upload it.

Another critical piece is the meta data collection.  We organized our site using SharePoint content types, so when the app loads, it gets a list of the document library’s content types.  The user then select one of the content types from the drop down list, and then we query SharePoint to get a list of the fields that make up that content type.  We used both an out of the box web service, and one that we custom built, in order to get these values.

Once we have the content type fields, we then add controls to the form.  Which type of control we add depends on the data type of the field.  (DateTime pickers for date/time fields, etc)  We didn’t write code to cover every data type, since we were working with a limited set of content types and field data types.

Here’s a screen shot of the Form, before and after someone has selected the content types and our code has added the custom controls:

CustomUploadBefore  CustomUploadAfter  

The other piece of meta data we collect is the in the upper right corner of the app, “Users with access”.  This box lists the different SharePoint Groups that we have set up and by checking the boxes, the user can set the permissions on the uploaded documents.

All of this meta data is collected and submitted to our custom web service, which then sets the values on the documents on the list.  We’ll look at these web services in a future post.

In the next post, we’ll walk through the Custom Action we built.

Integrating Windows Form Click Once Application into SharePoint 2007 – Part 1 of 4

Last year, I had the opportunity to build a solution that involved integrating a Windows Form application into a SharePoint 2007 (WSS version 3.0). In this post, I’ll layout our architecture thinking and in part two, I’ll describe the technical details.

Business Case

Our challenge was this: we needed an easy way for a small group of our users to upload documents, in batches.  They also needed to quickly set the meta data values, as well as set security on individual files.

Using the out of the box uploads just didn’t fit.  The single file upload allows set the meta data, but our users would be uploading dozens of files.  The multiple upload would allow our users to upload batches of files, but it doesn’t allow them to set the meta data during upload.  Also, neither upload method allows the users to set the permissions on the file.

Our Solution

We looked into building a web control of some kind, but ruled that out due to security complexities (if I remember correctly).  Another option would have been using a technology like Silverlight (or Flash?), but our team didn’t have the skills necessary to build with these.

So, after looking at what was technically possible, and also what skills our team had, we settled on a Windows Form application.  We also decided to deliver it to the clients via Click Once, so we would have the ability to easily update the application in the future.

Lessons Learned

After deploying our solution, we’ve learned a few lessons.  First, you’ll need to have the .Net Framework installed on the client computers.  We knew this, but we still ran into issues making sure our users had the proper framework version installed.  Second, we had issues with authentication.  Our issues were due to our testing domain being a separate Active Directory domain from the domain that our end users and their workstations were members of.  (See my earlier post about Clearing Saved Passwords for the fix to our problem).

Our third issue was how we dealt with uploading files that were named the same.  Our application would replace the existing file with the new file, which is the way we expected it to work.  However, our users wanted to upload weekly reports, named the same as the previous week.  We solved this by using folders within the document library to keep the sets of reports separate from previous weeks.

One last thing to consider before implementing a solution like this, is what browsers and platforms your users will be working from.  We only needed to support IE and Windows, which works fine.  However, if you need to support Firefox, there are add-ons that allow Click Once to work with Firefox.  This is still a Windows only solution though.  In order to support Macs, you’d have to focus on either browser techniques (AJAX?) or Silverlight/Flash.

Summary

Our users are happy with the Click Once app.  It allowed them to move all of their content to our SharePoint site in under a couple hours, which they were thrilled with.  We’re happy because we can easily deploy updates, our development time was small, and we met all of our business requirements.

Corrupted Views when migrating document libraries from SharePoint 2003 to 2007

A coworker of mine ran into this error recently, while migrating a document library from SharePoint 2003 to 2007:

“A WebPartZone can only exist on a page which contains a SPWebPartManager. The SPWebPartManager must be placed before any WebPartZones on the page.”

He saw this when he tried to see the All Documents view for the library.

After looking into it, we figured out what had happened.  He was migrating documents using the Explorer View in SharePoint.  He had copied the contents of the library from one server (a remote server that we didn’t have administrative access to) to his desktop.  He then opened an Explorer View of the new library and copied the files to it.  Well, it turns out he had copied the hidden “Forms” folder, which contained the files necessary to display the different views for the library. (He had set his explorer to show hidden files, which made them visible.)

explorerview

So, he had copied the 2003 forms to the 2007 library, which are incompatible.

We fixed it, by simply deleting the new document library, recreating it, and then copied everything except that hidden Forms folder.  Another option might have been to create a new document library on 2007, and copy the Forms folder from it to the broken library.  Since we didn’t need to save anything in the broken

<UPDATE>

Based on the feedback I received, we've confirmed that just moving the Forms folder from a newly created library to the broken one fixes it.  Just keep in mind, that any custom forms will need to be recreated (using a tool like SharePoint Designer).  If your broken library is just an out of the box library, you'll be fine.

</UPDATE>

BTW, I confirmed my suspicion with this blog post: http://palmettotq.com/blog/?p=54

SharePoint 2007 Parser Error after updating master page

A few weeks ago I was updating the master page for a SharePoint 2007 (WSS) site.  The client wanted the site updated to reflect the new look and feel that is being applied to another set of sites in the organization.

I created a new theme and master page, which I already wrote about here and here.  It worked well, except for a few pages on a subsite.  On those pages, I got the following error:

Server Error in '/' Application.

Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.

Parser Error Message: Code blocks are not allowed in this file.

 

I decided to go comb through my new master page and compare it to the existing master page that was already working.  After going through them line by line several times, I had no clue what would be causing the error because they were basically the same!

It turns out, it was a combination of two things.  First, on a few of the pages in the site, there was some include code (basically an <% EVAL()%> snippet).  This was the code that was triggering my error “Code blocks are not allowed in this file”. However, this code was working fine with the previous master page.

I decided to then try doing a full deployment of the site with the new master page, and it worked fine!  Apparently, if the master page is deployed using a Feature, then it is granted permission to allow code blocks, but if you upload pages either using web UI or SharePoint Designer, then the pages won’t be able to use code blocks.

I haven’t been able to pin down the rules or official info about this, but I thought others might find it useful anyway.

<UPDATE>

I recently read the Inside WSS 3.0 book which explains the reason for this issue. Pages deployed through the UI or SharePoint Designer are considered customized/unghosted/whatever you want to call it. As such they are not allowed to have script blocks outside of web part zones. This is intentional design by Microsoft so that potentially untrusted users aren't able to run malicious code on your server. Pages deployed through features and WSPs are non-customized/ghosted/etc and are allowed to have script blocks anywhere on the page.

-from the comments - Thanks Brian!

</UPDATE>

Updating a SharePoint master page via a solution (WSP)

In my last blog post, I wrote how to deploy a SharePoint theme using Features and a solution package.  As promised in that post, here is how to update an already deployed master page.

There are several ways to update a master page in SharePoint.  You could upload a new version to the master page gallery, or you could upload a new master page to the gallery, and then set the site to use this new page.  Manually uploading your master page to the master page gallery might be the best option, depending on your environment.  For my client, I did these steps in code, which is what they preferred.

editmenu-790590(Image courtesy of: http://www.joiningdots.net/blog/2007/08/sharepoint-and-quick-launch.html )

Before you decide which method you need to use, take a look at your existing pages.  Are they using the SharePoint dynamic token or the static token for the master page reference?  The wha, huh?

SO, there are four ways to tell an .aspx page hosted in SharePoint which master page it should use:

  • ~masterurl/default.master” – tells the page to use the default.master property of the site
  • ~masterurl/custom.master” – tells the page to use the custom.master property of the site
  • ~site/default.master” – tells the page to use the file named “default.master” in the site’s master page gallery
  • ~sitecollection/default.master” – tells the page to use the file named “default.master” in the site collection’s master page gallery

For more information about these tokens, take a look at this article on MSDN.

Once you determine which token your existing pages are pointed to, then you know which file you need to update.  So, if the ~masterurl tokens are used, then you upload a new master page, either replacing the existing one or adding another one to the gallery.  If you’ve uploaded a new file with a new name, you’ll just need to set it as the master page either through the UI (MOSS only) or through code (MOSS or WSS Feature receiver code – or using SharePoint Designer).

If the ~site or ~sitecollection tokens were used, then you’re limited to either replacing the existing master page, or editing all of your existing pages to point to another master page.  In most cases, it probably makes sense to just replace the master page.

For my project, I’m working with WSS and the existing pages are set to the ~sitecollection token.  Based on this, I decided to just upload a new version of the existing master page (and not modify the dozens of existing pages).

Also, since my client prefers Features and solutions, I created a master page Feature and a corresponding Feature Receiver.  For information on creating the elements and feature files, check out this post: http://sharepointmagazine.net/technical/development/deploying-the-master-page .

This works fine, unless you are overwriting an existing master page, which was my case.  You’ll run into errors because the master page file needs to be checked out, replaced, and then checked in.  I wrote code in my Feature Activated event handler to accomplish these steps.

Here are the steps necessary in code:

  1. Get the file name from the elements file of the Feature
  2. Check out the file from the master page gallery
  3. Upload the file to the master page gallery
  4. Check in the file to the master page gallery

Here’s the code in my Feature Receiver:

   1:          public override void FeatureActivated(SPFeatureReceiverProperties properties)
   2:          {
   3:              try
   4:              {
   5:   
   6:                  SPElementDefinitionCollection col = properties.Definition.GetElementDefinitions(System.Globalization.CultureInfo.CurrentCulture);
   7:   
   8:                  using (SPWeb curweb = GetCurWeb(properties))
   9:                  {
  10:                      foreach (SPElementDefinition ele in col)
  11:                      {
  12:                          if (string.Compare(ele.ElementType, "Module", true) == 0)
  13:                          {
  14:                              //  <Module Name="DefaultMasterPage" List="116" Url="_catalogs/masterpage" RootWebOnly="FALSE">
  15:                              //    <File Url="myMaster.master" Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE" 
  16:                              //      Path="MasterPages/myMaster.master" />
  17:                              //  </Module>
  18:                              string Url = ele.XmlDefinition.Attributes["Url"].Value;
  19:                              foreach (System.Xml.XmlNode file in ele.XmlDefinition.ChildNodes)
  20:                              {
  21:                                  string Url2 = file.Attributes["Url"].Value;
  22:                                  string Path = file.Attributes["Path"].Value;
  23:                                  string fileType = file.Attributes["Type"].Value;
  24:   
  25:                                  if (string.Compare(fileType, "GhostableInLibrary", true) == 0)
  26:                                  {
  27:                                      //Check out file in document library
  28:                                      SPFile existingFile = curweb.GetFile(Url + "/" + Url2);
  29:   
  30:                                      if (existingFile != null)
  31:                                      {
  32:                                          if (existingFile.CheckOutStatus != SPFile.SPCheckOutStatus.None)
  33:                                          {
  34:                                              throw new Exception("The master page file is already checked out.  Please make sure the master page file is checked in, before activating this feature.");
  35:                                          }
  36:                                          else
  37:                                          {
  38:                                              existingFile.CheckOut();
  39:                                              existingFile.Update();
  40:                                          }
  41:                                      }
  42:   
  43:                                      //Upload file to document library
  44:                                      string filePath = System.IO.Path.Combine(properties.Definition.RootDirectory, Path);
  45:                                      string fileName = System.IO.Path.GetFileName(filePath);
  46:                                      char slash = Convert.ToChar("/");
  47:                                      string[] folders = existingFile.ParentFolder.Url.Split(slash);
  48:   
  49:                                      if (folders.Length > 2)
  50:                                      {
  51:                                          Logger.logMessage("More than two folders were detected in the library path for the master page.  Only two are supported.",
  52:                                               Logger.LogEntryType.Information); //custom logging component
  53:                                      }
  54:   
  55:                                      SPFolder myLibrary = curweb.Folders[folders[0]].SubFolders[folders[1]];
  56:   
  57:                                      FileStream fs = File.OpenRead(filePath);
  58:   
  59:                                      SPFile newFile = myLibrary.Files.Add(fileName, fs, true);
  60:   
  61:                                      myLibrary.Update();
  62:                                      newFile.CheckIn("Updated by Feature", SPCheckinType.MajorCheckIn);
  63:                                      newFile.Update();
  64:                                  }
  65:                              }
  66:                          }
  67:                      }
  68:                  }
  69:              }
  70:              catch (Exception ex)
  71:              {
  72:                  string msg = "Error occurred during feature activation";
  73:                  Logger.logException(ex, msg, "");
  74:              }
  75:   
  76:          }
  77:   
  78:          /// <summary>
  79:          /// Using a Feature's properties, get a reference to the Current Web
  80:          /// </summary>
  81:          /// <param name="properties"></param>
  82:          public SPWeb GetCurWeb(SPFeatureReceiverProperties properties)
  83:          {
  84:              SPWeb curweb;
  85:   
  86:              //Check if the parent of the web is a site or a web
  87:              if (properties != null && properties.Feature.Parent.GetType().ToString() == "Microsoft.SharePoint.SPWeb")
  88:              {
  89:   
  90:                  //Get web from parent
  91:                  curweb = (SPWeb)properties.Feature.Parent;
  92:                  
  93:              }
  94:              else
  95:              {
  96:                  //Get web from Site
  97:                  using (SPSite cursite = (SPSite)properties.Feature.Parent)
  98:                  {
  99:                      curweb = (SPWeb)cursite.OpenWeb();
 100:                  }
 101:              }
 102:   
 103:              return curweb;
 104:          }

This did the trick.  It allowed me to update my existing master page, through an easily repeatable process (which is great when you are working with more than one environment and what to do things like TEST it!).  I did run into what I would classify as a strange issue with one of my subsites, but that’s the topic for another blog post.

Deploying a SharePoint 2007 theme using Features

I recently had a requirement to update the branding on an existing Windows SharePoint Services (WSS version 3.0) site.  I needed to update the theme, along with the master page.  An additional requirement is that my client likes to have all changes bundled up in SharePoint solutions.  This makes it much easier to move code from dev to test to prod and more importantly, makes it easier to undo code migrations if any issues would arise (I agree with this approach).

Updating the theme was easy enough.  I created a new theme, along with a two new features.  The first feature, scoped at the farm level, deploys the theme, adding it to the spthemes.xml file (in the 12 hive –> \Template\layouts\1033 folder).  Here’s the method that I call from the feature activated event:

       private static void AddThemeToSpThemes(string id, string name, string description, 
           string thumbnail, string preview, SPFeatureReceiverProperties properties)
        {
            XmlDocument spThemes = new XmlDocument();
            //use GetGenericSetupPath to find the 12 hive folder
            string spThemesPath = SPUtility.GetGenericSetupPath(@"TEMPLATE\LAYOUTS\1033\spThemes.xml");

            //load the spthemes file into our xmldocument, since it is just xml
            spThemes.Load(spThemesPath);
            XmlNode root = spThemes.DocumentElement;

            //search the themes file to see if our theme is already added
            bool found = false;
            foreach (XmlNode node in root.ChildNodes)
            {
                foreach (XmlNode prop in node.ChildNodes)
                {
                    if (prop.Name.Equals("TemplateID"))
                    {
                        if (prop.InnerText.Equals(id))
                        {
                            found = true;
                            break;
                        }
                    }
                }

                if (found)
                {
                    break;
                }
            }


            if (!found) //theme not found, so add it
            {
                //This is what we need to add:
                //  <Templates>
                //    <TemplateID>ThemeName</TemplateID>
                //    <DisplayName>Theme Display Name</DisplayName>
                //    <Description>My theme description</Description>
                //    <Thumbnail>images/mythemethumb.gif</Thumbnail>
                //    <Preview>images/mythemepreview.gif</Preview>
                //  </Templates>


                StringBuilder sb = new StringBuilder();

                sb.Append("<Templates><TemplateID>");
                sb.Append(id);
                sb.Append("</TemplateID><DisplayName>");
                sb.Append(name);
                sb.Append("</DisplayName><Description>");
                sb.Append(description);
                sb.Append("</Description><Thumbnail>");
                sb.Append(thumbnail);
                sb.Append("</Thumbnail><Preview>");
                sb.Append(preview);
                sb.Append("</Preview></Templates>");

                root.CreateNavigator().AppendChild(sb.ToString());

                spThemes.Save(spThemesPath);
            }
        }

Just as important, is the code that removes the theme when the feature is deactivated:

        private static void RemoveThemeFromSpThemes(string id)
        {
            XmlDocument spThemes = new XmlDocument();
            string spThemesPath = HostingEnvironment.MapPath("/_layouts/") + @"1033\spThemes.xml";

            spThemes.Load(spThemesPath);
            XmlNode root = spThemes.DocumentElement;

            foreach (XmlNode node in root.ChildNodes)
            {
                foreach (XmlNode prop in node.ChildNodes)
                {
                    if (prop.Name.Equals("TemplateID"))
                    {
                        if (prop.InnerText.Equals(id))
                        {
                            root.RemoveChild(node);
                            spThemes.Save(spThemesPath);
                            break;
                        }
                    }
                }
            }
        }

So, that takes care of deploying the theme.  In order to apply the theme to the web, my activate feature method looks like this:

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
                using (SPWeb curweb = (SPWeb)properties.Feature.Parent)
                {
                    curweb.ApplyTheme("myThemeName");
                    curweb.Update();
                }
        }

Deactivating is just as simple:

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
                using (SPWeb curweb = (SPWeb)properties.Feature.Parent)
                {
                    curweb.ApplyTheme("none");
                    curweb.Update();
                }
        }

Ok, that’s the code necessary to deploy, apply, un-apply, and retract the theme.  Also, the solution (WSP file) contains the actual theme files.

SO, next is the master page, which I’ll cover in my next blog post.

Microsoft Certifications – how to prep? and why?

hdr_learning_logo

I often get asked by my colleagues, “how do you prepare for Microsoft exams?” Well, the answer for me is a little complicated, so I thought I’d write up here what I do.

The first thing I do is go to Microsoft’s website to find the exam that I need to take.  If you’re looking to get a particular certification, then their site lists the exam or exams that you’ll need to pass. 

If you’ve already taken an exam, you can log onto the MCP website and use their certification planner.  This little tool tells you what tests you need, based on the exams you’ve already passed.  It is very helpful with the certifications that are multiple tests and especially ones that have electives.

Once you’ve identified the test, you can use Microsoft’s website to see the topics that it covers.  This is a good outline to follow when you study.  I’ll keep this handy to reference back throughout my studying to make sure that I’m covering all the topics I need to know.

The next step is probably where I am a little different from others.  IF the exam outline covers material that I’ve already been working with, then I’ll skip a lot of the studying and go directly to the practice tests.  However, if I’m looking at the outline and wondering how in the world do you do that? – then it’s time to hit the books.

So, where to find study materials?  Try typing in the exam number into any search engine.  You’ll typically find a ton of resources.  If you’re lucky, you’ll find books that others recommend based on their studying and exam experience.  As a Sogeti employee, I have access to three really good resources: an internal company list of all of the consultants who have passed particular tests (on our Connex website), Books 24x7, and Transcender practice exams.

Once my studying is done (either through books or experience), I’ll go through the practice exams.  I find them really helpful in getting my knowledge lined up to the thinking process that the exam writers use.  If I’m relying on my experience, then this really helps me to identify gaps in my knowledge that I’ll need to fill.

That’s about it.  If I’m doing ok on the practice exams, then I’ll take the real thing.  I’ve found that the practice exams are usually more difficult than then real thing.

BetaLog

Oh – one other thing I do related to Microsoft exams – I try to take any beta exams that Microsoft makes available that fall into my skill set.  Microsoft has started a blog to announce these and the seats usually fill up really quick.  The blog is at http://blogs.technet.com/betaexams/ . You don’t get your results instantly, like a normal exam, instead you have to wait for everyone to finish taking the beta exams and for Microsoft to determine which questions they are using and which they are dropping.  So, be prepared to wait six to eight weeks for your results.

Windows 7 Virtual PC - “RPC server unavailable”

WindowsVirtualPC

I use Windows 7 Virtual PC on my current project and I often bring home the files, so I can work some in the evenings.  Since my VHDs are large, I’ll only copy the undo disks, saved state, and virtual machine config files from my external drive.  I copy them to a small portable drive and once I get home, I’ll copy them to a large external drive.

I’ve done this for over a year, but recently I started getting an error when I tried to start the VPC after the copying was finished.  It would open the initial window with the progress bar, but eventually the bar would stop, turn red, and then the error “RPC server unavailable” would appear.  When I first started seeing these, I’d try again, but no luck.

After some testing, it turns out that my small portable drive is apparently going bad, so it was corrupting the files.  Lucky for me, that I never overwrote my good copies with corrupted copies, at least not at both the office and at home.

Can’t eject external USB or Firewire drive in Windows 7

As a SharePoint developer, I work a lot with Virtual Machines (presently using Windows Virtual PC, with Windows 7).  I’m using these VMs with my laptop, and in order to get better performance, I’ve moved them to external hard drives.  (These drives have faster RPMs, larger caches, and a larger capacity, than the internal drive.)  I have one large external drive at home, another similar drive at the office, and a small, slow portable drive that I carry with me.

Office Space file copy screen capture

So, at the end of each day at the office, I copy the files from the external drive to my portable drive and then once I get home, I copy them from the portable to the larger external drive I leave at home.  I do this for a couple of reasons: so I can work at home and secondly, so I have backup copies.  (Often, I feel like I’m in the movie “Office Space” when copying the files before I leave the office).

Anyway, after the files are copied, I safely eject the external drives, and then hibernate my laptop.  I’ve been doing this for over a year now, but within the last couple of months I started to have issues disconnecting the drives.  Intermittently, some application/process would have a lock on some file on the drive that would keep Windows from safely ejecting it.

After looking into it, I found that it was actually the Windows search service that was accessing the drive! Since I wasn’t using Windows search to look for stuff on these drives, I removed them as locations to index.

To do this in Windows 7, you need to go to Indexing Options (just type “Indexing” into the search box in the Start menu…).  One of the choices displayed will then be Indexing Options, so click on it and you should then see a window similar to this:Indexing Options Windows 7

 

Click on the Modify button and you’ll see this window:

Indexing Locations Windows 7Notice the different drives listed above.  My “FreeAgent XTreme (F:)” drive was checked for some reason, which was causing the indexing service to scan the drive looking for new files to make available in the search results.  Ever since I unchecked this box, I’ve been able to safely eject the drive.

9 years of having a cell phone…

…or an excuse to write about my cool new phone.

I got a new phone this past week.  One which I think is really cool, but before I talk about it, I want stroll through the previous cell phones I’ve owned.

Almost nine years ago, my wife and I bought a pair of cell phones.  These were our first phones, and the excuse to get them was that my wife was pregnant with our first child at the time.  We thought it might be useful to have cell phones so she could get a hold of me if or when something was up.

The phones were pretty minimal – some Motorola cheap phone from Verizon that I can’t even find a photo of on the net now.  They were really reliable and Verizon’s network is really good here in central Ohio, except for one area – our house.  We hardly get a signal and if we do get a call started, it usually drops out.

A few years later, after I had gotten into .Net development, it was time to get new phones.  My wife wanted something smaller and I wanted something I could write .Net apps for.  After some searching, I got an Audiovox Thera on closeout from Tiger Direct.advxthera

The Thera was a Windows PocketPC phone, running PocketPC 2002.  I could load the .Net Compact Framework v1.0 on it and build apps.  I could also sync the calendar/contacts to 1194937my Mac using Missing Sync.  It didn’t have a data plan, but that was alright.

It was a good PocketPC, but a horrible phone.  It was hard to dial without looking at the screen, because there were no buttons to feel – just the flat screen.  Talking on the phone was difficult without the wired ear plug, because it would act like a speaker phone.

I built an app that I used to track my gas mileage, but that was about it.  I lived with it for about three years before upgrading to my next phone.

  Samsung_i730

My next phone was a used Samsung i730.  A couple of the guys at work at these phones and I thought they were pretty good.  It had built in WiFi, blue tooth, a slide out keyboard, and most importantly, ran Windows Mobile 5, so I was able to build apps for it.  Again, the only one I built was an upgraded version of my gas mileage tracker.

These phones are now considered pretty thick and they have an antique looking antenna that can slide out even further.  The keyboard is pretty small and so is the screen.

So, fast forward another three years and I get a promotion at work.  More importantly, I get a promotion at work and now work is going to pay my cell phone bill! So, now I am the proud new owner of an HTC Touch Pro 2 on T-Mobile.

touchpro2-htc-per02It arrived last week and I am really impressed. It is running Windows Mobile 6.5 with a touch interface.  It has 3G and WiFi and most importantly – I have a good cell signal at my house!  It don’t have 3G coverage, but it does have edge at my house, which doesn’t matter too much since I can use my wifi connection instead.

It’s got a camera which can take both still and videos.  It has GPS and Google maps.  It has the weather.  It has a Bing app, with maps, gas prices, search.  All very cool stuff.

Having the data plan has really opened up what I can do with the phone.  I’ve got it configured to connect to my work email and Gmail, as well as Facebook and Twitter.

I’m looking forward to using it when I travel too.  At some point, I’ll also get to write another gas mileage app….

HTC-Touch-Pro2-from-T-Mobile-USA-3

What’s up with these ads?

I’ve started to notice particular ads on Facebook and MSNBC.  It’s just some random mug shot photo with text around it, but I started to notice the same weird faces showing up on different sites for different topics.  Here’s a couple of examples:

 

FacebookAd1 FacebookAd2facebookad3facebookad4

After Googling about these ads, I found that apparently ClassesUSA is ripping off the ads from LowerMyBills.  I find that really funny, since I think the ads are awful. 

Apparently, I’m not the first to notice how bad these ads are: http://kidicarus222.blogspot.com/2009/12/refinance-your-home-or-rot-in-street.html

SharePoint 2007: “Failed to extract the cab file in the solution.” when trying to perform addsolution

I ran into an error today, while trying to execute the following: stsadm –o addsolution mySolution.wsp .  The error was “Failed to extract the cab file in the solution.”

A quick search found blog entries stating that either a file in the WSP contained an illegal character or two files were named the same.  I looked through my files and found a couple of graphics files with names containing a parenthesis.  Since all of my file names were unique, which ruled out the one suggestion, I decided to try renaming the files, leaving out the parentheses.

After renaming them, I retried my stsadm command and it worked fine. (“Operation completed successfully.”)

One thing to note: I had manually deployed these same graphic files to a SharePoint library using Designer without any issues.  I guess the solution deployment must be more particular (or maybe Designer handles the name differently).

Apple iPad: Out of this world hit or colossal failure?

apple-ipad-6

As someone who loves technology, I was very interested in the Apple announcement this past week.  I read some of the live blogging during Steve’s presentation and have read some of the pundit blogs in the last few days.  Most of the reactions I’ve seen are either: Apple hit it out of the ballpark (see Apple ][, Mac Plus, original iMac, iPod, iPhone) or Apple just delivered another dud (see Apple Lisa, first Mac laptop, 20th Anniversary Mac, Mac Cube, Apple TV). So which is it?

I think the iPad will be successful in certain scenarios, but first let’s rule out where the iPad doesn’t make sense. iPads won’t be used in the enterprise.  The form factor doesn’t make sense for typical office functions for extended periods of time (the occasional document editing on weekends might happen).  Plus, enterprise IT only likes devices that can be centrally managed and Apple has a history of not playing well in this space.

I also don’t think it’ll be a laptop replacement.  As the laptop has replaced the desktop, it is now the main computing device.  It’s the thing that we attach our devices to (printers, scanners, extra storage, etc), the thing that we use at the office and the home to get work done.  The iPad won’t replace the laptop for any of these scenarios.ipad-apple-large

The iPad can serve the casual computing niche extremely well.  What do I mean by casual computing?  For me, it’s the time that I spend with the laptop surfing and reading my RSS feeds in my family room with the tv on in the background.  It’s for the times when I need a trivia question answered (like when we need to find out where we’ve seen that actor before via IMDB.com).  Or during the sixteen hour drive to Disney World, when the kids want to watch a movie.

One thing I would need for vacations, would be the ability to get photos off the camera and onto the iPad, so I could then post them to the net.  (I like to get copies of my photos onto Google photos just in case something would happen to my camera before I got home.)Lenovo-IdeaPad-U1-Hybrid-Notebook-Slate-Tablet-Combo-screen

So when am I going to get one? Eh, I’m not.  The price is just too high for me to drop on a casual device. I’ll continue to use my laptop for both work and some casual.  Our desktop (a Mac Mini) will still be the main computer in the house, with our finance, photos, and music.

If I was going to spend money on a new device, I think a better fit would be something like the Lenovo IdeaPad.  It was announced at CES this year.  It’s a small laptop, with a detachable screen.  When the screen detaches, it changes from a Windows based machine to a custom Linux machine, with functionality like that of the iPad. For just under $1,000 you get two computers in one.

Only time will tell if the iPad is deemed a success. I’ll be looking back at this post in a couple of years to see how things actually turned out compared with how I think today….

SharePoint Site tab appears when user doesn’t have permission to the site

We have a rather simple WSS portal that has about six sites, shown using the standard navbar (“tabs”) across the top of the page.  This navbar is shared among all of the sites.  Each subsite has different permissions, mostly giving certain users some level of edit permission on those subsites.

Well, one of the sites has some out of the box Content Editor webparts and we wanted to allow a group of users to edit the content using these web parts.  They already had contribute permission, so they could upload documents into libraries.  However, they couldn’t edit the content because they didn’t have the edit page permission.

So, I created a new role with the “Add and Edit Pages…” permission (one of the SharePoint granular permissions you can grant) and then I granted our Editors group this role/permission.  When I logged in as an editor, I was surprised to see a tab appear in the navbar that should only be accessible by IT Administrators (it’s an “Admin” site that has some pages that IT can use to manage the portal).  When I clicked on it, I got the standard SharePoint access denied page.  However, we didn’t even want our users to see this tab.1_1

After some research, I found that the edit page permission grants users the ability to see all links, so they can edit them, even if they don’t have access to the pages that those links point to.  This makes sense, but it’s not the behavior that we were looking for!

SO, I went back to the drawing board and created a new web part that could be edited without relying on the edit page permission.  I showed it to our main editor today for the first time and she was thrilled.  She thinks the new part is much easier to use, because there is a simple edit button (that only editors can see) that then toggles the web part into edit mode. When she’s done, she just clicks a save (or cancel) button, which saves the changes and puts the web part back into display mode. 1

 2

Using the out of the box content editor webpart, she would have to put the page into edit mode, select edit from the web part’s menu, find the edit HTML button on the web part properties panel, make the changes, click save in the web part, click ok in the properties panel, and exit edit page mode.  Whew. (Here’s the screens:)

4 

35

In the end, this redesign worked out.