
I analyzed two sites, one migrated, one newly created. Both were created from the same site template (which did not need to change for upgrade to 2010). Each URL to the Upload page was the same for the equivalent document library in both sites:
/_layouts/Upload.aspx?List={GUID}&RootFolder=&IsDlg=1
I pulled up the Upload.aspx page from the SharePoint Root (aka 14 hive) and looked for some insight, but to my surprise, there were no references to the Destination Folder input controls in either the markup. I checked the referenced javascript to see if maybe these were being built dynamically, but found nothing. Using the Page directive from the Upload.aspx, I located the assembly containing the base class: Microsoft.SharePoint.ApplicationPages.dll and loaded it up in my favorite disassembler. This assembly was not in the GAC as I expected, but rather in my web application's _app_bin directory.
A copy of the Microsoft.SharePoint.ApplicationPages.dll assembly is copied into the _app_bin folder for each web app. I haven't researched why this assembly is copied here, rather than installed to the GAC, but suspect it has something to do with CAS and running with least amount of permissions. For another day…
After looking in the obvious places and finding no references to these controls, I had one place left to look: OnPreInit(). Sure enough, I found some logic in here used the SPWeb.CustomUploadPage and does a Server.Transfer to the page if one is specified.
I put together a quick PowerShell script to help me compare my two webs:
$newWeb = Get-SPWeb http://newweb/
$migratedWeb = Get-SPWeb http://migratedweb
Write-Host "New custom upload page: " $newWeb.CustomUploadPage
Write-Host "Migrated custom upload page: " $migratedWeb.CustomUploadPage
Sure enough, the new web did not have a CustomUploadPage specified, but my migrated did. It was pointing to: /_layouts/UploadEx.aspx. Sure enough in the markup for this page were references to target folder's input controls, however, they were surrounded with some conditional logic that was checking to see if the list "HasFolders" (i.e. does the list have SubFolders?). But my migrated web's document library doesn't have any SubFolders…What gives? Time to peek at the UploadEx base class in the disassembler (Microsoft.Office.Policy.Pages.dll, again in the _app_bin folder for each web application).
After some tracing through, I found that ultimately, the decision on whether a folder has subfolders, at least in the context of this particular page, is based on an entry in the Folder's property bag: folder.Properties["vti_foldersubfolderitemcount"]
I wrote some more PowerShell and sure enough, in the case of my migrated document library, this had a value of "1". Again, my migrated library has no sub folders, so why would this value be set to "1".
Disclaimer: the rest is theory as I did not invest the time to fully research this and by this point I already had the information needed to explain the situation to the end users and get a script written to clear the SPWeb.CustomUploadPage value in all places needing it which would be sufficient to eliminate the display of the "Destination Folder" input controls since the regular Upload.aspx page doesn't make use of these controls.
I suspect, that the 2007 to 2010 migration set the ["vti_foldersubfolderitemcount"] property to be "1" and/or this property was handled differently in 2007 as compared with 2010. You see, there is actually a SubFolder, but it's the "Forms" folder, which is generally hidden from view and not available for users to upload to. Perhaps during 2007 -> 2010 migration, the upgrade process wasn't checking for the "Forms" folder if it was resetting the "vti_foldersubfolderitemcount" property? Also, the migration must have been responsible for setting the SPWeb.CustomUploadPage property on each of the migrated webs because we had not explicitly made this change. Perhaps this is a change to how document libraries are provisioned between 2007 and 2010?
To test this theory out a bit, I created a brand new document library in my migrated web. I compared the newly created library to the migrated library with some PowerShell:
$migratedWeb = Get-SPWeb http://migratedweb
$migratedDocLib = $migratedWeb.Lists["Migrated Doc Lib"]
$migratedRootFolder = $migratedDocLib.RootFolder
Write-Host "RootFolderUrl" $migratedRootFolder.Url
Write-Host "folders count" $migratedRootFolder.SubFolders.Count
Write-Host "folder[0] url" $migratedRootFolder.SubFolders[0].Url
Write-Host "Prop value" $migratedRootFolder.Properties["vti_foldersubfolderitemcount"]
write-host""
write-host""
$newDocLib = $migratedWeb.Lists["New Doc Lib"]
$newRootFolder = $newDocLib.RootFolder
Write-Host "RootFolderUrl" $newRootFolder.Url
Write-Host "folders count" $newRootFolder.SubFolders.Count
Write-Host "folder[0] url" $newRootFolder.SubFolders[0].Url
Write-Host "Prop value" $newRootFolder.Properties["vti_foldersubfolderitemcount"]
The results were as I expected: The newly created document library (in the migrated web) had a vti_foldersubfolderitemcount property value of 0, whereas my migrated document library had a value of "1" (presumably a reference to the "Forms" folder).

6 comments:
Hey Brian,
Great article! do you mind sharing the script you used to remove the Destination Folder field?
foreach($webapp in get-spwebapplication)
{
foreach($site in $webapp.Sites)
{
foreach($web in $site.AllWebs)
{
if ($web.CustomUploadPage -ne "")
{
Out-File Clear-CustomUploadPage_Log.txt -Append -InputObject $web.Url
Write-Host "Updating " $web.Url -ForeGroundColor Yellow
$web.CustomUploadPage = ""
$web.Update()
}
}
}
}
Warning: this fix will ensure you will never have the destination path field.
It can be useful for some cases though.
There is also a bug with the STS#0 (Blank site) template: the field is never shown. Maybe some event handler is not provisioned with this template...
Nice detective work. Your theory about migration sounds likely.
This is a great article. Thanks for posting and great detective work. I have the same issue with my 2010 SP server (Enterprise). Two things that set this apart is that this was a clean install of SP 2010 (not an upgrade), and I have at least one other site collection on this farm that works exactly the way I want where the destination folder part of the dialog does NOT show up. I started a new project in a new site collection (same farm) and this little issue cropped up on a new doc library. I don't want to allow users to interact with the location of the document. I want them to upload docs in to a folder that I had a workflow create.
The script you posted in Feb, how would I run this? Can you please provide some guidance on how to set this script up to run?
I do like this, and it works fine. $(document).ready(function(){
$("#ctl00_PlaceHolderMain_ctl04").remove();
$("a:contains('Multiple Files')").hide();
});
Post a Comment