Tag Archives: SharePoint

SharePoint 2010: Observations and Revelations on the User Profile Sync Service and the Update-SPProfilePhotoStore cmdlet

These are my notes while trying to diagnose and better understnad some issues and oddities with the SharePoint 2010 User Profile Service Application.

If you’re wanting to populate pictures into people’s profiles, you’ll be using the Update-SPProfilePhotoStore powershell cmdlet after a normal sync (full or incremental – or your custom built one). This cmdlet is in the Microsoft.Office.Server.UserProfiles dll, specifically the Microsoft.Office.Server.UserProfiles.PowerShell.SPCmdletUserProfilePhotoStore class. Thanks to the goodness that is Redgate Reflector (a must have for any SP developer), we can get a more clear undertanding of what the cmdlet is doing. I’ve written some comments to help understand what’s going on, as well as renamed some variables for the section I was more interested in understanding. You’ll want to open the code in a new window (highlight on the top right of the code section), as some of the lines are quite long:

[Cmdlet("Update", "SPProfilePhotoStore")]
internal sealed class SPCmdletUserProfilePhotoStore : SPCmdlet
{
    // Fields
    private bool? m_createThumbnailsForImportedPhotos = null;
    private bool? m_noDelete = null;
    private SPFolder m_profilePicFolder;
    private SPSitePipeBind m_SiteMySiteHost;
    private UserProfileManager m_userProfileManager;

    // Constructor
    public SPCmdletUserProfilePhotoStore()
    {
        this.m_createThumbnailsForImportedPhotos = null;
        this.m_noDelete = null;
    }

    // Methods
    protected override void InternalProcessRecord()
    {
        // Run the below section if -CreateThumbnailsForImportedPhotos has NOT been specified.
        if (!this.m_createThumbnailsForImportedPhotos.HasValue)
        {
            // Enumerate through all UserProfiles
            foreach (UserProfile profile in this.m_userProfileManager)
            {
                try
                {
                    // Get the PictureURL property of the user profile
                    object obj2 = profile["PictureURL"].Value;
                    if ((obj2 != null) && !string.IsNullOrEmpty((string) obj2))
                    {
                        // This user has a PictureURL property. Get the path
                        string path = profile["PictureURL"].Value.ToString();
                        string format = StringResourceManager.GetString("Powershell_MovePictures_GenericError_Text");
                        format = string.Format(CultureInfo.InvariantCulture, format, new object[] { path, (string) profile["AccountName"].Value });

                        // If the PictureURL property has a link to the medium thumbnail, don't process further.
                        if (!Path.GetFileNameWithoutExtension(path).EndsWith("_MThumb", StringComparison.Ordinal))
                        {
                            bool flag = false;
                            byte[] buffer = null;
                            try
                            {
                                using (SPSite site = new SPSite(path))
                                {
                                    using (SPWeb web = site.RootWeb)
                                    {
                                        // Try and get a reference to the file specified. This can be in SharePoint somewhere on on another webserver.
                                        SPFile file = web.GetFile(path);
                                        if (file.Exists)
                                        {
                                            try
                                            {
                                                buffer = file.OpenBinary();
                                            }
                                            catch (Exception exception)
                                            {
                                                base.WriteError(new SPException(format + exception.ToString()), ErrorCategory.WriteError, null);
                                                buffer = null;
                                            }
                                        }
                                        else
                                        {
                                            // The file doesn't exist. Write an error.
                                            string str4 = StringResourceManager.GetString("Powershell_MovePictures_FileNotFound_Text");
                                            str4 = string.Format(CultureInfo.CurrentCulture, str4, new object[] { path });
                                            base.WriteError(new FileNotFoundException(format + str4), ErrorCategory.WriteError, null);
                                        }
                                    }
                                }
                            }
                            catch (FileNotFoundException)
                            {
                                // File wasn't found using Object Model. Maybe it's on another webserver. Try and open the file using a WebClient instead of the Object Model
                                try
                                {
                                    WebClient client = new WebClient();
                                    CredentialCache cache = new CredentialCache();
                                    cache.Add(new Uri(path), "Ntlm", CredentialCache.DefaultNetworkCredentials);
                                    client.Credentials = cache;
                                    buffer = client.DownloadData(new Uri(path));
                                }
                                catch (Exception exception2)
                                {
                                    base.WriteError(new SPException(format + exception2.ToString()), ErrorCategory.WriteError, null);
                                    buffer = null;
                                }
                            }
                            string str5 = null;
                            // Did we read the file into memory?
                            if (buffer != null)
                            {
                                string str7 = UrlUtility.ConvertToLegalFileName(profile["AccountName"].Value.ToString(), '_');
                                string str8 = ".jpg";
                                try
                                {
                                    using (MemoryStream stream = new MemoryStream(buffer))
                                    {
                                        using (Bitmap bitmap = new Bitmap(stream, true))
                                        {
                                            // Create a large thumbnail
                                            UserProfilePhotos.CreateThumbnail(bitmap, UserProfilePhotos.LargeThumbnailSize, UserProfilePhotos.LargeThumbnailSize, this.m_profilePicFolder, str7 + "_LThumb" + str8);
                                            // Create a medium thumbnail
                                            SPFile file2 = UserProfilePhotos.CreateThumbnail(bitmap, UserProfilePhotos.MediumThumbnailSize, UserProfilePhotos.MediumThumbnailSize, this.m_profilePicFolder, str7 + "_MThumb" + str8);
                                            // Create a small thumbnail
                                            UserProfilePhotos.CreateThumbnail(bitmap, UserProfilePhotos.SmallThumbnailSize, UserProfilePhotos.SmallThumbnailSize, this.m_profilePicFolder, str7 + "_SThumb" + str8);
                                            // Get a URL to the Medium Size Thumbnail
                                            str5 = UrlUtility.EnsureTrailingSlash(this.m_userProfileManager.MySiteHostUrl) + file2.Url;
                                        }
                                    }
                                }
                                catch (Exception exception3)
                                {
                                    base.WriteError(new SPException(format + exception3.ToString()), ErrorCategory.WriteError, null);
                                    flag = true;
                                }
                            }
                            // If the URL to the medium thumbnail isn't null and we successfully created the thumbnails...
                            if ((str5 != null) && !flag)
                            {
                                // Set the PictureURL value
                                profile["PictureURL"].Value = str5;
                                profile.Commit();
                                // Write to the log (verbose) that we set the Picture up.
                                string str9 = StringResourceManager.GetString("Powershell_MovePictures_PhotoMoved_Text");
                                str9 = string.Format(CultureInfo.InvariantCulture, str9, new object[] { profile["AccountName"].ToString(), DateTime.Now.ToLongTimeString() });
                                base.WriteVerbose(str9);
                            }
                        }
                    }
                }
                catch (Exception exception4)
                {
                    string str10 = StringResourceManager.GetString("Powershell_MovePictures_GenericError_Text");
                    str10 = string.Format(CultureInfo.InvariantCulture, str10, new object[] { string.Empty, (string) profile["AccountName"].Value });
                    base.WriteError(new SPException(str10 + exception4.ToString()), ErrorCategory.WriteError, null);
                }
            }
        }
        // Run the below section if -CreateThumbnailsForImported has been specified
        else
        {
            // Get the MySiteHost Site Collection
            using (SPSite site2 = new SPSite(this.m_userProfileManager.MySiteHostUrl))
            {
                // Access the MySiteHost RootWeb
                using (SPWeb web2 = site2.RootWeb)
                {
                    // Get the PhotoListURL
                    string importPhotoListUrl = UserProfileGlobal.GetImportPhotoListUrl(ProfileType.User) + "/" + UserProfileGlobal.GetImportPhotoFolderName(web2.Locale) + "/";
                    // Enumerate through all UserProfiles
                    foreach (UserProfile profile2 in this.m_userProfileManager)
                    {
                        // Get the filename of the photo, then the url to the photo, and finally the file itself
                        // This is a combination of the UserProfileManager PartitionID (internal property) and the RecordId of the profile. This is the temporary picture file.
                        string importPhotoFilename = UserProfileGlobal.GetImportPhotoFilename(this.m_userProfileManager, profile2.RecordId);
                        string importPhotoFilenameWithListUrl = importPhotoListUrl + importPhotoFilename;
                        SPFile file3 = web2.GetFile(importPhotoFilenameWithListUrl);

                        // If the file exists, run below.
                        if ((file3 != null) && file3.Exists)
                        {
                            // Format an error message in case we need it later.
                            string str15 = StringResourceManager.GetString("Powershell_MovePictures_GenericError_Text");
                            str15 = string.Format(CultureInfo.InvariantCulture, str15, new object[] { file3.ToString(), (string) profile2["AccountName"].Value });

                            // Try opening the file and reading it into memory
                            byte[] buffer2 = null;
                            try
                            {
                                buffer2 = file3.OpenBinary();
                            }
                            catch (Exception exception5)
                            {
                                // There was an exeption reading the picture file into memory. Write this error to a log, then set the buffer to null
                                base.WriteError(new SPException(str15 + exception5.ToString()), ErrorCategory.WriteError, null);
                                buffer2 = null;
                            }

                            // Check and see if we were able to read the file into memory successfully. Run below if we could.
                            if (buffer2 != null)
                            {
                                // We've got the temporary file in memory. Determine what we should rename it
                                string str17 = profile2["AccountName"].Value.ToString().Replace(@"\", "_");
                                string str18 = ".jpg";
                                string mediumThumbnailURL = null;
                                bool createThumbnailsSuccess = true;
                                try
                                {
                                    using (MemoryStream stream2 = new MemoryStream(buffer2))
                                    {
                                        using (Bitmap bitmap2 = new Bitmap(stream2, true))
                                        {
                                            // Create a Thumbnail - large size
                                            UserProfilePhotos.CreateThumbnail(bitmap2, UserProfilePhotos.LargeThumbnailSize, UserProfilePhotos.LargeThumbnailSize, this.m_profilePicFolder, str17 + "_LThumb" + str18);
                                            // Create a Thumbanil - medium size, and get a reference to the file it creates
                                            SPFile file4 = UserProfilePhotos.CreateThumbnail(bitmap2, UserProfilePhotos.MediumThumbnailSize, UserProfilePhotos.MediumThumbnailSize, this.m_profilePicFolder, str17 + "_MThumb" + str18);
                                            // Create a Thumbnail - small size
                                            UserProfilePhotos.CreateThumbnail(bitmap2, UserProfilePhotos.SmallThumbnailSize, UserProfilePhotos.SmallThumbnailSize, this.m_profilePicFolder, str17 + "_SThumb" + str18);
                                            // Build a URL that points to the medium size thumbnail
                                            mediumThumbnailURL = this.m_userProfileManager.MySiteHostUrl + file4.Url;
                                        }
                                    }
                                }
                                catch (Exception exception6)
                                {
                                    base.WriteError(new SPException(str15 + exception6.ToString()), ErrorCategory.WriteError, null);
                                    createThumbnailsSuccess = false;
                                }
                                // Have we successfully created the thumbnails and have a path to the medium thumbnail?
                                if (createThumbnailsSuccess && (mediumThumbnailURL != null))
                                {
                                    // Set the PictureURL property
                                    profile2["PictureURL"].Value = mediumThumbnailURL;
                                    profile2.Commit();
                                    // If -NoDelete wasn't specified, then delete the image with the Guid_ID pattern for this user profile.
                                    if (!this.m_noDelete.HasValue || (this.m_noDelete == false))
                                    {
                                        file3.Delete();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    protected override void InternalValidate()
    {
        SPSite site = this.MySiteHostLocation.Read();
        if (site == null)
        {
            string message = StringResourceManager.GetString("Powershell_MovePictures_NullMySiteHost_Text");
            base.ThrowTerminatingError(new ArgumentException(message), ErrorCategory.InvalidArgument, null);
        }
        SPServiceContext serviceContext = SPServiceContext.GetContext(site);
        if (serviceContext == null)
        {
            string str2 = StringResourceManager.GetString("Powershell_MovePictures_ServerContextNotFound_Text");
            base.ThrowTerminatingError(new ArgumentException(str2), ErrorCategory.ObjectNotFound, null);
        }
        this.m_userProfileManager = new UserProfileManager(serviceContext);
        if (this.m_userProfileManager == null)
        {
            string str3 = StringResourceManager.GetString("Powershell_MovePictures_ProfManagerNotFound_Text");
            base.ThrowTerminatingError(new ArgumentException(str3), ErrorCategory.ObjectNotFound, null);
        }
        if (!this.m_userProfileManager.IsProfileAdmin)
        {
            string str4 = StringResourceManager.GetString("Powershell_MovePictures_NotProfileAdmin_Text");
            base.ThrowTerminatingError(new ArgumentException(str4), ErrorCategory.InvalidOperation, null);
        }
        try
        {
            this.m_profilePicFolder = UserProfileGlobal.GetOrCreatePictureFolder(this.m_userProfileManager);
        }
        catch (Exception exception)
        {
            base.ThrowTerminatingError(exception, ErrorCategory.ObjectNotFound, null);
        }
    }

    // Properties
    [Parameter(Mandatory=false)]
    public bool CreateThumbnailsForImportedPhotos
    {
        get
        {
            return this.m_createThumbnailsForImportedPhotos.Value;
        }
        set
        {
            this.m_createThumbnailsForImportedPhotos = new bool?(value);
        }
    }

    [ValidateNotNull, Parameter(Mandatory=true, ValueFromPipeline=true)]
    public SPSitePipeBind MySiteHostLocation
    {
        get
        {
            return this.m_SiteMySiteHost;
        }
        set
        {
            this.m_SiteMySiteHost = value;
        }
    }

    [Parameter(Mandatory=false)]
    public bool NoDelete
    {
        get
        {
            return this.m_noDelete.Value;
        }
        set
        {
            this.m_noDelete = new bool?(value);
        }
    }
}

From this we gather that the command has two modes depending on whether the -CreateThumbnailsForImportedPhotos flag is specified.

CreateThumbnailsForImportedPhotos specified

This mode appears intended for those who are importing their pictures from Active Directory (or other source) as a raw picture (Octet String for AD) in bytes.

CreateThumbnailsForImportedPhotos not specified

This mode appears intended for the use cases where the PictureURL property has been prepopulated with a URL that either points to an image in SharePoint or an image available on another web server. This mode still will create thumbnails for you, but it doesn’t look for the temporary pictures in the form {GUID}_ID to make the thumbnails from – it will try and access the picture located at the URL specified in the PictureURL property.

So – if you’re importing your pictures from Active Directory and a user removes their picture from the directory, there is no means in the powershell (or observed from the import process) to take care of removing the picture from SharePoint.

I’ll post more as more is learned. There doesn’t seem to be much information on some of these things.

SharePoint 2010: Ribbon CustomActions

Developing a CustomAction for the Ribbon and SharePoint 2010? If you’re like me – you follow some instructions online, deploy it once to verify it works, then change as needed and redeploy. One catch though – the data needed for the ribbon custom action to work is fetched by the browser and CACHED! So you won’t see your changes…until you clear your cache. Stupid but true. You’re welcome.

Hands down, the best blog post on helpful utility programs ever.

If you’re a developer, or an admistrator, or just command your home machine with extreme prejudice – you need to read Scott Hanselman’s 2011 Ultimate Developer and Power Users Tool List for Windows. Lots of good utilities to be found there. Some may even change your life…

SharePoint 2010: Setting custom User Profile properties Gotchas

The Goal

The goal is to create a custom User Profile property and then set and retrieve its value using C#.

The resources

Here’s the best resources on the net for creating, modifying, etc.

The Gotchas

Using the above resources, you can piece together how to programatically create custom user profile properties (and sections), set their value(s), and get their value(s). As a developer, you’ve probably only configured enough of your dev farm to get done what you need to do…which isn’t nearly enough to set the values on a custom user profile property.

What else do you need?

Custom User Profile Properties (and several of the Out of Box ones) depend on a Managed Metadata Service Application being setup and associated with the application you’re working with. This is fairly trivial to setup. Just remember that after you set it up via the UI, you’ll need to start it on the “Manage services on this server” page, and then perform an IIS reset. Forgetting these will keep your Managed Metadata service from working.

Jon’s General SharePoint 2010 Development Tips

In the time I’ve been doing SharePoint development, and SharePoint 2010 development in particular, I’ve tried to blog about the snags or neat stuff I’ve come across. This post is for all those little pieces of knowledge that come from working with the platform that don’t seem large enough for their own post. If you find it useful, let me know in the comments.

The Very Basics

The better understanding of the following resources you have as a SharePoint developer, the better. These are considered absolute must-knows.

Deploying .WSP solution packages

Don’t use Visual Studio 2010 to do this. ”But Jon! They built it to do that! Why shouldn’t I use it?” There are a few reasons why you shouldn’t use VS to do your deployment. Here are a few I’ve learned:

  • You as a SharePoint developer need to be 100% comfortable with using PowerShell to do your deployments. You shouldn’t be using stsadm anymore, and neither should your administrator(s). Learn the commandlets for every part of deployment through using them in your own development environment.
  • Visual Studio 2010 out of the box wants to activate all of your features on every web application in the farm. This isn’t how you’ll treat your production environment, so don’t do it in your dev environment. You can disable this behavior, but then using VS for your deployment doesn’t net you much time savings.
  • Bad things happen when developing content types and site columns. From my experience, Visual Studio keeps a connection to your application open to help you with developing content types and site columns – that’s cool, but not always the best thing. Whenever you retract your solution, make some changes to content types or site columns and redeploy - you’re very likely to end up with Visual Studio telling you that some of those content types and site columns already exist. You can either sort through getting rid of these through powershell/the UI and then continuing to use Visual Studio while trying to make it not have this behavior – or just use PowerShell for your solution/feature deployment and enablement. I chose PowerShell after 2 long days of fighting Visual Studio and haven’t looked back (and haven’t had the issue either!)

Debugging your deployed code

Deploying with PowerShell now? Good. You still need to debug your code. Here are some gotchas.

  • How to attach the Visual Studio debugger manually: If you’re new to SharePoint 2010 and don’t know how to debug without letting Visual Studio 2010 manager your deployment – here are the steps to attach the debugger manually:
    • Build and Package your latest solution package using Visual Studio (I use Ctrl + Shit + B to build, and then click Package in the Build menu).
    • Deploy the solution package using PowerShell.
    • Attach the debugger by clicking the “Debug” menu and “Attach to Process”. Next make sure the “Show processes from all users” and “Show processes in all sessions” are selected. If you’re debugging something running in a web application, select all w3wp processes. If you’re debugging feature activation, attach to your powershell process. If you are debugging a timer job, attach to the owstimer.exe process.
    • Set a breakpoint and debug as normal.
  • Debugging Feature Receivers using PowerShell: PowerShell is really slick. It’s not your normal commandline though. It acts like a .NET application. That means that the first time it loads a dll to run some code, it keeps it handy in memory and doesn’t go and load that dll again. So – if you are testing a feature, checking your results, redeploying your code, and retesting…you’re not going to get the results you want. Why? Because the first time you activated your feature and tested, PowerShell cached your code. It didn’t reload it for your second test run. The solution? Close the PowerShell window and re-open. Repeat as necessary.
  • Debugging Timer Jobs: This has the same caveat as debugging a feature receiver. OWSTimer will cache your dll the first time it runs any code from it. Need to change something in a timer job and retest? Deploy your solution and then restart the “SharePoint 2010 Timer” service in Server Manager. Reattach your debugger if necessary. Retest.

Writing Console Applications against the SharePoint Object Model

This is a really handy way of proving out some application logic, or when you need to provide a utility to your administrator(s) that would just be too complex and hairy to write using PowerShell.

  • To use the SharePoint Object Model, your Console Application needs to be compiled for x64 processors. Go to your Project Properties, and under the Build tab change the “Platform Target” to x64. This setting is specific to the chosen build configuration (most likely “Debug” for your current app). So – if you change your build configuration to Release, you’ll need to set the Platform Target to x64 again.
  • Certain actions in the Object Model require that you have an HttpContext open to the web you’re working with. I ran into this when working with the webpart manager for a web. Google should be able to help you with establishing an HttpContext from within your console application.

Provisioning the User Profile Service Application

  • The instructions on MSDN indicate that the service account running this service app should be a local administrator. In my experience, this means the account must be directly in the Administrators group. It’s not enough to have it in a security group that is then nested in the Administrators group. If you do this, it will be stuck on “starting”.

I’ll add to this as I come across little snippets of knowledge. Have a quick tip for SP2010 to share? Let me know.

SharePoint 2010: The web application at … could not be found. Verify that you have typed the URL correctly.

and so on with the error message. Do these also fit your situation?
1) The error happens when running a console application
2) Using PowerShell works to access the SPSite, SPWeb, or SPWebApplication that you’re accessing in your console application

How do you fix this?
Change your build platform target to x64 instead of x86. Also keep in mind that this is a per build configuration setting (so you have the setting for Debug and Release compile modes).

Why did I post this?
Because every few months this bites me in some way. Normally for at least an hour at a time. It’s extremely confusing at first and a ‘doh moment when you figure it out.

SharePoint 2010: Add a file to the root of your site using PowerShell

This can be useful when you need a file to be right off the root of your Internet facing site – files like robots.txt, sitemap.xml, or the verification file for Google Webmaster tools. We’ll take advantage of PowerShell’s ability to use any .NET methods along with the Files collection on each SPWeb in SharePoint.

$fileBytes = [system.io.file]::ReadAllBytes("c:\the\full\path\to\your\file.txt");
$site = Get-SPSite "http://yourdomain:portifneeded";
$site.RootWeb.Files.Add("file.txt", $fileBytes, $true);

This will result in a file.txt located at “http://yourdomain:portifneeded/file.txt”. Sweet!

SharePoint 2010: Finding the largest document library in a site collection

SharePoint 2007 came with a page (storman.aspx) dedicated to showing you how much space each of the lists in your site collection were taking up. SharePoint 2010 removed this page. Luckily, SharePoint 2010 SP1 added it back in. But what if you’re still haven’t updated to SP1 and you’re getting warnings/errors about running out of space?

Obviously – up the space so as to avoid additional noise from your users. Then – figure out which libraries are taking up the most space. This can be done by using the (now obsolete – but working) StorageManagementInformation method off of SPSite. You can write some C# to use it, or you can use PowerShell.

The required arguments for this method (listed below) can be found by looking at the above MSDN link. I’ll also include the potential values that can be found by using Reflector to look at the Microsoft.SharePoint dll:

  1. ltVar: What kind of storage management information to display
    • List = 1
    • DocumentLibrary = 2
    • Document = 3
  2. sordVar: the direction in which the items are to be sorted
    • Increasing = 0×10
    • Decreasing = 0×11
  3. soVar: whether the items are sorted by size or by date
    • Size=0
    • Date = 1
  4. nMaxResults: the number of results to return

So if you want to find the top 5 largest document libraries in a specific site collection, here’s the PowerShell:

$site = Get-SPSite "http://yoursitecollection:portifneeded";
$dataTable = $site.StorageManagementInformation(2,0x11,0,5);
$dataTable | Select *

This is very helpful if you aren’t yet on SP2010 SP1. A note though – the method is marked as obselete with this description “SPSite.StorageManagementInformation is expensive; avoid using it.”. There’s no further explanation on what is being spooled up to execute the method or why it was OK in SP2007 but not SP2010. So I’d consider this OK to use if you have to…but not in some kind of recurring scheduled script. Your mileage may vary, I’m not responsible for what happens to your farm, etc. etc.

Hope you found this useful. Let me know!

SharePoint 2010: Unable to delete site/web after SP1

While doing some testing after upgrading my dev machine to SP1, I ran into two separate issues when trying to delete a web through the UI by using the “Sites and Workspaces” link in Site Settings. Deleting through powershell worked fine.

Issue #1: Specified method is not supported

This specific error was occurring only on one of my web applications. I had just attached the database for this application to my existing SharePoint 2010 SP1 environment. The error will appear if the database for your web application needs to be updated.

To check if your database needs to be updated, open Central Administration and navigate to “Upgrade and Migration” -> “Review database status”. All of your databases should show a status of “No action required”. If the application you are experiencing the error on is running in compatibility mode, you’ll need to update it using PowerShell. To do this, first get the GUID ID of the database in question by running the following powershell and then copying the ID of the database you wish to upgrade:

Get-SPContentDatabase

Then run the following powershell to upgrade the database using the ID you just copied.

Upgrade-SPContentDatabase -Identity YourDatabaseIDGoesHere

Issue #2: There is no Web named “/YourWebName”

Once my above issue was resolved on the one misbehaving web application, I had consistent behavior across all web applications when trying to delete a web… or so I thought. Turns out – if I create a web right off of the site collection (the RootWeb), then I can successfully delete it using the “Sites and Workspaces” page. Also – I can delete the web successfully if I navigate to the web I want to delete and then use the “Delete this Site” link. This behavior was consistent in a SharePoint 2010 SP1 environment and SharePoint 2010 SP1 + June Cumulative Update. What’s going on here?

Time to open up Reflector. The offending code comes from the Microsoft.SharePoint.ApplicationPages dll located in the virtual directory/_app_bin of your web application. Specifically, the DeleteWebPage class. Here’s the code:

The offending line, using the OpenWeb function, gets passed “/DeleteMe” if your web’s name is “DeleteMe”. This will work fine if the web’s url starting from the site collection is “/DeleteMe”. But if your web is a subweb of a subweb (e.g. http://yoursite/someweb/DeleteMe) then it will fail and throw the exception. This looks to be a bug in SP1 and June CU… so we’ll have to wait for MS to fix the issue before we can go this route to delete a web. Instead – use PowerShell to delete the web or navigate to the web you wish to delete and use the “Delete this Site” link.