Open with Explorer Intermittent Failures

Applies To: SharePoint

Background:

I recently created a new web application that will eventually be used quite a bit, but for now we were only moving one site over. Fortunately, the site collection we were moving was the only thing in the Content Database so I just performed a simple Dismount and then Mount and everything was up and running except for the search results. A quick change of the scopes and a Full Crawl takes care of that. I turned it over to the main user and he immediately called me back and said the Explorer View was not working for him.

Then there was much weeping.

Symptoms:

I immediately confirmed that it worked on my machine (Windows 7) and assumed he was doing it wrong (Cause I’m a bit of a Jerk). A quick visit to his machine proved I didn’t know what I was talking about. He was running XP and everything was working fine in our other main Web Application on his machine for Explorer View, but not in the new Web App.

He would receive an access denied message stating he didn’t have enough permissions but also that the Network Path was not found. I decided to investigate further at my machine only to find that mine only worked intermittently. Sometimes it would open up just fine, but other times I would receive the message “Your client does not support opening this list with windows explorer.” Something had made my machine a liar.

Disclaimer

After a bunch of searching and cross comparing my Web Apps to see what setting I missed, I came across this article on The prostructure blog. Amber Pham lays out the full solution there which I am reproducing here. She got it right but it was so hard to find that I thought rephrasing some things might help the next poor victim find the solution quicker. So it’s below, but it is her solution and I’m very grateful for her help.

Solution:

Turns out, for whatever reason, a missing root site for the Web Application will cause this issue. Since I was only moving the one site for now, I hadn’t yet created a Site Collection at / (Root Site Collection). I didn’t think this was a big deal – and if you’re not using Explorer View, it’s not. But to correct this issue, go into Central Admin and create a new Site Collection at /. Pick any template you want since you can always change it later. I just ensured that I was the only one who had access to it for now and voila, Open with Explorer suddenly works for my XP clients and consistently works for our Windows 7 clients. Sheesh.

Renaming a Web Application in SharePoint 2010

Applies To: SharePoint 2010

In getting ready to create a new web application for our SharePoint farm I realized the default web application name of “SharePoint – 80” wasn’t very descriptive and I’d like to change it. If you’re reading this, then you probably already went through all the possible settings in Central Admin just like I did only to find this isn’t an option.

Fortunately, this can all be done through Powershell very quickly:

$wapp = Get-SPWebApplication "SharePoint - 80"
$wapp.Name = "Magical Web App"
$wapp.Update()

This can be written up in a script, or you can just type the lines just like above changing the names as makes sense. To verify the update was successful just use this command:

Get-SPWebApplication "Magical Web App"

You should see your new name listed with the url of your web application:

You can also check this in Central Administration under Application Management > Manage web applications:

Everything is good to go. However, this will not change the IIS website names or application pools. This takes more work than I was willing to do and I didn’t really care about that, so you’ll have to find that information elsewhere. But if you’re like me, this should be all you need!

Deleting a Document from a Record Library

Applies To: SharePoint 2010

In setting up a Records Center I was trying out the Content Organizer and Drop Off Library. I configured a Send To location and an Organizer Rule to get my document to my new Record Library. It worked great! However, since this was just a test to make sure everything mapped over correctly, I wanted to delete the test document and I got this error:

This item cannot be deleted, moved, or renamed because it is either on hold or is a record which blocks deletion.
This item cannot be deleted, moved, or renamed because it is either on hold or is a record which blocks deletion.

Uh… so how do I undeclare it? The answer is that with record libraries, all documents are not only automatically declared records, manual declaration/undeclaration is disabled by default. This all makes sense considering this is in the Record Center and it is a Record Library. But to delete your document, you will have to disable these settings (Temporarily).

1. Turn off Automatic Record Declaration

Go to your Library Settings for your Record Library. Under Permissions and Management choose Record declaration settings:

Uncheck the box in the Automatic Declaration section then press OK:

2. Enable Manual Declaration of Records

Go back into the Record declaration settings since the Manaual Record Declaration Availablity section will now be enabled. Choose Always allow the manual declaration of records:

3. Undeclare the Document as a Record

Go back to the Library and choose the document you want to delete. In the drop down menu, choose Compliance Details:

In order to remove the document, it can’t be a record nor be part of any holds. In the compliance details popup remove the document from hold (if necessary) and click the Undeclare record link. In the confirmation dialog choose OK to undeclare.

4. Delete the Document

Kill that sucker.

5. Put Everything Back in Place

Those settings were on the library for a good reason. Once you’ve finished your testing or no longer need to delete any individual records, you should go back to your library settings and reenable the default settings (Follow these steps backward).

If for some reason, you want to delete the Record Library itself. You will need to remove every record from the library following the above steps and then run the “Hold Processing and Reporting” job in Central Admin. This let’s SharePoint know there are no records in there and the standard deletion link will appear in the Library Settings.

PDF Search Results Direct Link (Eliminating DispForm.aspx Results) Without an iFilter

Applies To: SharePoint

We are utilizing our search functionality much more in SharePoint and one of the more annoying things we found was how PDF files are treated by default. In the search results, the link goes to the DispForm.aspx for the item rather than directly to the item.

The obvious fix is to install an iFilter. Unfortunately, this isn’t always an option. For us, the performance and crawl delay issues didn’t make up for the benefit of having these documents indexed. Fortunately, I came across this answer by daver306 on SharePoint SE that didn’t get a lot of attention but worked perfectly for me.

I wanted to write it up with some added detail and share my experiences. Not only does this allow you to link directly to your PDFs within the search without the use of XSL and allows KnowledgeLake queries to open PDFs directly within the KnowledgeLake Viewer, it’s actually pretty simple to do.

1. Add PDF as a File Type

Within Central Admin, go to your Search Administration (Manage Service Applications > Search Service). From there click on the File Types link under Crawling on the left:

If pdf is not listed, click the New File Type button and type pdf (no period needed) in the File extension box and click OK:

2. Restart the Search Service

This is a very important step. I originally tried to skip it to spare myself some hassle and ended up having to repeat the crawl below. You will need to go to each server running the SharePoint Server Search service and stop it. You can do this through the command line or the Services panel under Administrative Tools:

Once off on all boxes, just go back through and start it again.

3. Reset Your Index

Back on the Search Administration page within Central Administration you will want to click on the Index Reset link under Crawling on the menu on the left:

Press the Reset Now button. Remember that this should be done at a time when your environment is not under heavy use or when search won’t be needed since search results will not be available until after a full crawl completes.

4. Perform a Full Crawl

If you have a pretty standard search setup, then you probably only have one content source. If not, then you already know how to start the full crawls for each of them. If you’ve just got the one, then from the Search Administration page within Central Administration click on the Content Sources link under Crawling on the menu on the left. Hover over your content source and choose Start Full Crawl in the dropdown menu:

After the crawl completes (This could be hours depending on the size of your farm), things should be working as expected. No more DispForm.aspx links in your search results!

 

Minimal.Master missing corev4.css

Applies To: SharePoint 2010

While testing our new master page that replaces the minimal.master I noticed that depending on your permission level, things were rendering differently. If you had full permissions then things looked great, but if you were a visitor with read-only permissions things were a little off.

Taking a look at the actual page source we found that the stylesheet links in the header section looked different. With Full permissions the link to corev4.css existed, but didn’t for anyone else. Obviously permission to the corev4.css file wasn’t the issue since this was working fine on all other sites regardless of user permissions.

Some quick searching and experimentation revealed that the corev4.css link was only added to the page when the Site Actions menu was set to render. For the standard minimal.master file this is fine, but if you are depending on any of the corev4.css styles, you’ve got a problem. Fortunately, the solution is simple.

In your custom minimal.master master page find this section in the head element:

 <SharePoint:CssLink runat="server" Alternate="true"/>
 <SharePoint:Theme runat="server"/>
 <SharePoint:CssRegistration Name="minimalv4.css" runat="server"/>
 <SharePoint:CssRegistration Name="layouts.css" runat="server"/>

And add a CssRegistration element to corev4.css above the minimalv4.css CssRegistration:

 <SharePoint:CssLink runat="server" Alternate="true"/>
 <SharePoint:Theme runat="server"/>
 <SharePoint:CssRegistration Name="corev4.css" runat="server"/>
 <SharePoint:CssRegistration Name="minimalv4.css" runat="server"/>
 <SharePoint:CssRegistration Name="layouts.css" runat="server"/>

That’ll do it. The corev4.css will load regardless of the presence of the Site Actions menu and there aren’t any conflicts since SharePoint ensures it isn’t registered twice.

Auto Publish and Approve Your Solution Files

Applies To: SharePoint 2010

By default, every file you deploy using a sandboxed solution is left checked out. This can lead to problems depending on the type of site you are deploying to and/or the permissions of your end users.

This post focuses on Branding solutions, but anytime you are deploying a sandboxed solution these techniques should help you. This is especially important for Master Pages since these often need an approved/published version in order to be visible to anyone but the site administrators.

I found an interesting approach by Waldek Mastykarz where he suggests using a “Stamp” (Feature ID property) on each file and using that to find and check in each file. This was very cool, but requires you to modify the Elements.xml entry for each file to ensure that property is added and he also never addressed Master Pages which can be a bit of a special case.

For my needs, I generally take a simpler approach of just deploying my resources to one root folder and creating sub folders as needed. This makes it easier to find stuff, but it also means I don’t need to track each file individually. Obviously if you are doing something a little more extensive then you may need to take a hybrid approach of using the featureid property and/or just tracking the various folders you are deploying too. But for a simple branding solution you really just need to:

  1. Apply your branding to each site
  2. Publish and Approve each resource file
  3. Publish and Approve each Master Page

All of this can be done in the FeatureActivating event with a simpler helper method:

    Public Overrides Sub FeatureActivated(ByVal properties As SPFeatureReceiverProperties)
        Dim siteCollection As SPSite = CType(properties.Feature.Parent, SPSite)
        If siteCollection IsNot Nothing Then
            Dim topSite As SPWeb = siteCollection.RootWeb

            'Calculate relative path to site from Web Application root
            Dim WebAppRelativePath As String = topSite.ServerRelativeUrl
            If Not WebAppRelativePath.EndsWith("/") Then WebAppRelativePath &= "/"

            'Enumerate through each site and apply branding
            For Each site As SPWeb In siteCollection.AllWebs
                If Not site.MasterUrl.EndsWith("minimal.master") Then
                    site.MasterUrl = WebAppRelativePath & "_catalogs/masterpage/BSmain.master"
                Else
                    site.MasterUrl = WebAppRelativePath & "_catalogs/masterpage/BSminimal.master"
                End If
                If Not site.CustomMasterUrl.EndsWith("minimal.master") Then
                    site.CustomMasterUrl = WebAppRelativePath & "_catalogs/masterpage/BSmain.master"
                Else
                    site.CustomMasterUrl = WebAppRelativePath & "_catalogs/masterpage/BSminimal.master"
                End If
                site.AlternateCssUrl = WebAppRelativePath & "Style%20Library/BSResources/BS.css"
                site.SiteLogoUrl = WebAppRelativePath & "Style%20Library/BSResources/Images/BSlogo.png"
                site.UIVersion = 4
                site.Update()
            Next

            'Publish and Approve each file
            Dim styleLibrary As SPList = topSite.Lists.TryGetList("Style Library")
            If styleLibrary IsNot Nothing Then
                Dim folders As SPListItemCollection = styleLibrary.Folders
                Dim item As SPListItem = DirectCast((From i In folders Where DirectCast(i, SPListItem).Url = "Style Library/BSResources" Select i).FirstOrDefault(), SPListItem)
                ApproveAndPublish(item.Folder, styleLibrary.EnableModeration)
            End If

            'Publish and Approve the Master Pages
            Dim mpGallery As SPList = siteCollection.GetCatalog(SPListTemplateType.MasterPageCatalog)
            If mpGallery IsNot Nothing Then
                Dim mpages As SPListItemCollection = mpGallery.GetItems(New SPQuery With {.Query = "<Where><Or><Eq><FieldRef Name='FileLeafRef' /><Value Type='Text'>RegalIC.master</Value></Eq><Eq><FieldRef Name='FileLeafRef' /><Value Type='Text'>RegalICminimal.master</Value></Eq></Or></Where>"})
                If mpages IsNot Nothing Then
                    For Each i As SPListItem In mpages
                        If Not i.File.CheckOutType = SPFile.SPCheckOutType.None Then
                            i.File.CheckIn("Feature Activation", SPCheckinType.MajorCheckIn)
                            If mpGallery.EnableModeration Then
                                i.File.Approve("Feature Activation")
                            End If
                        End If
                    Next
                End If
            End If

        End If
    End Sub

    Private Sub ApproveAndPublish(folder As SPFolder, Approve As Boolean)
        If folder Is Nothing Then Return
        For Each subfolder As SPFolder In folder.SubFolders
            ApproveAndPublish(subfolder, Approve)
        Next
        For Each file As SPFile In folder.Files
            If Not file.CheckOutType = SPFile.SPCheckOutType.None Then
                file.CheckIn("Feature Activation", SPCheckinType.MajorCheckIn)
                If Approve Then
                    file.Approve("Feature Activation")
                End If
            End If
        Next
    End Sub

1. Apply your branding to each site

After gathering basic information about where the feature is being deployed and getting the correct reference URLs, we begin looping through every site in the sitecollection and setting the master page, sitelogo, and CSS settings to use our custom branding beginning in line 11.

The only thing different than the approach described in the Microsoft article, Deploying Branding Solutions for SharePoint 2010 Sites Using Sandboxed Solutions is that I am checking if the current master page is the minimal.master and if so, using my BSminimal.master file instead. This allows me to have both master pages deployed correctly, but it also allows me to restore these settings more accurately in the deactivating event (See my previous post).

2. Publish and Approve each resource file

To keep things simple, I keep all of my resource files in a single root folder within the Style Library. This makes looping through each subfolder and resource very simple to ensure that each one gets checked in and/or approved as necessary.

Lines 29-34 get a reference to the resource folder within the Style Library and pass that information over to a helper method called ApproveAndPublish. This method takes an SPFolder reference and a boolean indicating if approval is necessary or not. For the initial call, the folder is our resource folder and the approval setting comes directly from the Style Library and is found in the EnableModeration property of the SPList object.

The ApproveAndPublish method (Lines 55-68) is a recursive function that loops through every subfolder and checks in every file found. If Approval is required, it also marks them as approved.

This means you don’t have to track each file (either through stamping or keeping a list). This really cuts down on all the plumbing that is often necessary when working on a SharePoint solution.

3. Publish and Approve each Master Page

Unfortunately, Master Pages aren’t usually deployed to a sub folder and so the above technique for approval and check in has to be tweaked slightly. Lines 37-50 take care of this. Basically, we get a reference to the Master Page Catalog and use some basic CAML to isolate our master pages and then loop through them to check them in and/or activate them if required.

That’s all that’s required. You now have your files successfully deployed and ready to be used. Be sure to check out my previous post Branding Solution Cleanup. In that post I describe how to remove all of your solution files when your solution gets deactivated.

Branding Solution Cleanup

Applies To: SharePoint 2010

I followed the Microsoft article, Deploying Branding Solutions for SharePoint 2010 Sites Using Sandboxed Solutions and I was able to quickly get the bones of a Branding project put together. Unfortunately, I found that when the solution was deactivated all the files I deployed remained exactly where they were.

I found various solutions for removing your files ranging from individual file lists to marking every file with your feature ID, but for a simple Branding project all you really need to do is:

  1. Remove usage of your Master Pages from every site referencing them
  2. Remove your files from the Style Library
  3. Remove your Master Page files from the Master Page Catalog

The first two can be done in the FeatureDeactivating event handler and the third can be done in the FeatureUninstalling event handler. For those that just want the code, here it is:

    Public Overrides Sub FeatureDeactivating(ByVal properties As SPFeatureReceiverProperties)
        Dim siteCollection As SPSite = CType(properties.Feature.Parent, SPSite)
        If siteCollection IsNot Nothing Then
            Dim topSite As SPWeb = siteCollection.RootWeb

            'Calculate relative path to site from Web Application root
            Dim WebAppRelativePath As String = topSite.ServerRelativeUrl
            If Not WebAppRelativePath.EndsWith("/") Then WebAppRelativePath &= "/"

            'Enumerate through each site and remove branding
            For Each site As SPWeb In siteCollection.AllWebs
                If Not site.MasterUrl.EndsWith("minimal.master") Then
                    site.MasterUrl = WebAppRelativePath & "_catalogs/masterpage/v4.master"
                Else
                    site.MasterUrl = WebAppRelativePath & "_catalogs/masterpage/minimal.master"
                End If
                If Not site.CustomMasterUrl.EndsWith("minimal.master") Then
                    site.CustomMasterUrl = WebAppRelativePath & "_catalogs/masterpage/v4.master"
                Else
                    site.CustomMasterUrl = WebAppRelativePath & "_catalogs/masterpage/minimal.master"
                End If
                site.AlternateCssUrl = String.Empty
                site.SiteLogoUrl = String.Empty
                site.Update()
            Next

            'Kill Style Library Folder
            Dim styleLibrary As SPList = topSite.Lists.TryGetList("Style Library")
            If styleLibrary IsNot Nothing Then
                Dim folders As SPListItemCollection = styleLibrary.Folders
                Dim item As SPListItem = DirectCast((From i In folders Where DirectCast(i, SPListItem).Url = "Style Library/BSResources" Select i).FirstOrDefault(), SPListItem)
                item.Delete()
            End If

        End If
    End Sub

    Public Overrides Sub FeatureUninstalling(ByVal properties As SPFeatureReceiverProperties)
        Dim siteCollection As SPSite = properties.UserCodeSite
        If siteCollection IsNot Nothing Then

            'Kill Master Pages
            Dim mpGallery As SPList = siteCollection.GetCatalog(SPListTemplateType.MasterPageCatalog)
            If mpGallery IsNot Nothing Then
                Dim mpages As SPListItemCollection = mpGallery.GetItems(New SPQuery With {.Query = "<Where><Or><Eq><FieldRef Name='FileLeafRef' /><Value Type='Text'>BSmain.master</Value></Eq><Eq><FieldRef Name='FileLeafRef' /><Value Type='Text'>BSminimal.master</Value></Eq></Or></Where>"})
                If mpages IsNot Nothing Then
                    For i As Integer = mpages.Count - 1 To 0 Step -1
                        mpages(i).Delete()
                    Next
                End If
            End If

        End If
    End Sub

Wow code! Alright Scriptkitties, copy away! Everyone else, here’s what we’re doing and why:

1. Remove usage of your Master Pages from every site referencing them

After gathering basic information about where the feature was deployed and figuring out the correct reference URLs, we begin looping through every site in the sitecollection and resetting the master page to the defaults beginning in line 11.

We are just undoing what was done in the FeatureActivating event. The only thing of note is that I hate when a Branding solution replaces every MasterPage with theirs and then just blindly restores v4.master. Mostly this is fine, but if one of your subsites is an Enterprise Search site or anything else using the minimal.master you’ve just wrecked it. Obviously if you know you aren’t using minimal.master then you can simplify this section. Also, I always name my minimal.master replacement in the form [Something]minimal.master to ensure this works out.

2. Remove your files from the Style Library

To keep things simple, I keep all of my resource files in a single root folder within the Style Library. Obviously I have subfolders to organize images, fonts, etc. but all of those are within my one folder. This makes finding stuff much easier, but more than that it makes removing the files super easy – Just delete that folder.

Lines 27-33 do just that. After getting a reference to the Style Library (Every sitecollection in SharePoint 2010 has one of these), grab the folder (just replace the “Style Library/BSResources” string in line 31 with your folder path) and delete.

3. Remove your Master Page files from the Master Page Catalog

There are lots of guides for deleting deployed master pages and I didn’t find any that worked. Basically every time I tried to delete a master page from within the FeatureDeactivating event I got an error about them still being used. I’m sure there’s a good reason for this (feel free to let me know in the comments), but it doesn’t really matter because as long as you followed step 1 above, it’ll work in the FeatureUninstalling event.

We simply grab a reference to the sitecollection’s Master Page Gallery and use some simple CAML to grab references to our Master Pages. Then we walk through them and delete them.

That’s it, you now have a self-cleaning solution and you are a responsible member of the SharePoint community.

Relative Paths in SharePoint using SPUrlExpressionBuilder ($SPUrl)

Applies To: SharePoint Server (MOSS)

When you edit pages and/or master pages in SharePoint either for branding or some other project you will eventually come across the need to link to some resource file whether it’s an image, icon, CSS, etc. When this came up for me, I realized I had no idea how to do this properly.

Sure you can hardcode a link, but if this is part of a solution (especially a sandboxed solution) then this quickly becomes an unusable option. You can use the dots to do relative links, but again this can easily break on system pages or when you need to reference site collection level items from any sub site regardless of level.

Fortunately, some quick searching found the solution I needed. I came across Bugra Postaci’s blog post on the subject and that got me going. Be sure to check it out for some background, but the basic idea is to use the SPUrlExpressionBuilder class to generate relative links. Unfortunately, this class is part of the publishing namespace and so is only available in SharePoint Server (2010) and MOSS (2007).

He gives an example of linking to an image within the Style Library of the site collection using the following code directly within the master page:

<asp:Image ImageUrl="<% $SPUrl:~sitecollection/Style Library/CustomImages/BlogofBugra.jpg %>" runat="server" />

The key thing to note is the inline use of the $SPUrl command. The example shows this within an asp:Image control but this can be done in a standard tag as well (img, link, etc.).

After seeing that, I really wanted to know what other magic tokens you can use, but the Microsoft Documentaiton on the class doesn’t even show the inline $SPUrl syntax, let alone list any of the usable tokens! Doing a quick search will find you an assortment of undocumented tokens. However this can be misleading as the tokens listed in {} braces are generally only for custom actions and not for inline links (you can find examples of those lists here and here).

Here is what I’ve found by actually looking at the code using Reflector:

Token Replaced By Version
~site/ SPContext.Current.Web.ServerRelativeUrl 2007, 2010
~sitecollection/ SPContext.Current.Site.ServerRelativeUrl 2007, 2010
~language Thread.CurrentThread.CurrentUICulture.Name 2007, 2010
With the exception of the ~language token, the others are replaced using a call to Microsoft.SharePoint.Utilities.SPUtility.UrlFromPrefixedUrlCore.