locked
SummaryLinkWebPart : Access Denied saving Web Part properties after migration to Moss 2010 RRS feed

  • Question

  • Hi everyone,

    i got the error below when i access pages containing a SummaryLinkWebPart. The error occured only with user having non-administrative privilege.

    The curious thing is that after an administrator access one of this pages, it starts to work for non-administrative users too.

    The site collections containing these pages has been migrated from Moss 2007 to Moss 2010.

    I'd like to find a better solution than navigate through all my pages with site collection administrator account.

    Any suggestion would be very appreciate

    Access Denied saving Web Part properties: either the Web Part is embedded directly in the page, or you do not have sufficient permissions to save properties

    Friday, July 30, 2010 10:39 AM

Answers

  • You're right, the CU I mentioned didn't fix it for our production data either.  It only worked when I did an OOTB site in our Development environment.  We ended up writing a script that found every page that had the Summary Link Web Part and then ran a javascript program to go and open each page, one by one. 

    Here is the powershell script we used to find the sites and create "sitelist.js"

     

    #http://stsadm.blogspot.com/2010/08/getting-inventory-of-all-sharepoint.html
    
    $outfile = "sitelist.js"
    if (Test-Path $outfile) { Remove-Item $outfile }
    "// started at " + (Get-Date) | Out-File $outfile
    
    $logfile = "log.txt"
    if (Test-Path $logfile) { Remove-Item $logfile }
    
    $errorfile = "error.txt"
    if (Test-Path $errorfile) { Remove-Item $errorfile }
    
    "var sites = new Array();" | Out-File $outfile -append
    $siteIdx = 0
    
    [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
    $farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
    
    foreach ($spService in $farm.Services) {
    	if (!($spService -is [Microsoft.SharePoint.Administration.SPWebService])) {
    		continue;
    	}
    
    	foreach ($webApp in $spService.WebApplications) {
    		if ($webApp -is [Microsoft.SharePoint.Administration.SPAdministrationWebApplication]) { continue }
    
    		foreach ($site in $webApp.Sites) {
    
    			foreach ($web in $site.AllWebs) {
        "Searching " + $web.Url
        foreach ($file in $web.Files) {
         if($file) {
          if($file.ServerRelativeUrl.indexof(".aspx") -lt 0) { continue }
          trap [Exception] {
           "Error on page: " + $file.ServerRelativeUrl + ": " + $_.Exception.Message | Out-File $errorfile -Append
           "sites[" + $siteIdx + "] = '" + $webApp.Url + $file.ServerRelativeUrl + "';" | Out-File $outfile -append
           $siteIdx++
           continue
          }
          $wpMgr = $file.GetLimitedWebPartManager("Shared")
          $wpIdx = -1
    						foreach($wp in $wpMgr.WebParts) {
           $wpIdx++
    							trap [Exception] { 
            "Error in web part " + $wpIdx + " on page: " + $file.ServerRelativeUrl + ": " + $_.Exception.Message | Out-File $errorfile -Append
    								$wp = ""
    								continue 
    							}
    							if($wp.WebBrowsableObject.ToString().IndexOf("SummaryLinkWebPart") -gt 1) {
    								"sites[" + $siteIdx + "] = '" + $webApp.Url + $file.ServerRelativeUrl + "';" | Out-File $outfile -append
            				$siteIdx++
    								#$wp.WebBrowsableObject.ToString() | Out-File $outfile -append
    								#$pagefile.tostring() | Out-File $outfile -append
    								#"" | Out-File $outfile -append
    								$wp = ""
    								break
    							}
    						}
         }
        }
        
    				foreach ($list in $web.Lists) {
    					if ($list.BaseType -ne "DocumentLibrary") {
    						continue
    					}
    					foreach ($item in $list.Items) {
    						trap [Exception] { 
           "Error in item: " + $item.DisplayName + ", web: " + $web.Url + ": " + $_.Exception.Message | Out-File $errorfile -Append
    							$pagefile = ""
    							$wpMgt = ""
    							$wp = ""
    							continue 
    						}
    						$pageurl = $web.url + "/" + $item.url
    						if($pageurl.indexof(".aspx") -lt 1) { continue }
    						$pagefile = $web.GetFile($pageurl)
          
    						$wpMgr = $pagefile.GetLimitedWebPartManager("Shared")
          $wpIdx = -1
    						foreach($wp in $wpMgr.WebParts) {
           $wpIdx++
    							trap [Exception] { 
            "Error in web part " + $wpIdx + " on page: " + $pageurl + ": " + $_.Exception.Message | Out-File $errorfile -Append
            "sites[" + $siteIdx + "] = '" + $pageurl + "';" | Out-File $outfile -append
            $siteIdx++
    								$wp = ""
    								continue 
    							}
    							if($wp.WebBrowsableObject.ToString().IndexOf("SummaryLinkWebPart") -gt 1) {
    								"sites[" + $siteIdx + "] = '" + $pageurl + "';" | Out-File $outfile -append
            				$siteIdx++
    								#$wp.WebBrowsableObject.ToString() | Out-File $outfile -append
    								#$pagefile.tostring() | Out-File $outfile -append
    								#"" | Out-File $outfile -append
    								$wp = ""
    								break
    							}
    						}
    					}
    				}
    				$web.Dispose();
    			}
    			$site.Dispose()
    		}
    	}
    }
    
    "// finished at " + (Get-Date) | Out-File $outfile -Append
    

     

    Then here is the HTML for the page that will load each site from your list one by one.

     

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Strict//EN">
    <html>
    <head><title>Starting sites...</title></head>
    <body>
    	<style>
    	BODY {
    		font: normal 10pt Arial, Sans-serif;
    	}
    	</style>
    	<script language="javascript" src="sitelist.js"></script>
    	<script language="javascript">
    	var INTERVAL_LENGTH = 30;
    	
    	var objTimeout = null;
    	var progress = 0;
    	
    	function startSites(sender) {
    		if(sender.value == "Start") {
    			sender.value = "Pause";
    			loadNext();
    		} else {
    			window.clearTimeout(objTimeout);
    			sender.value = "Start";
    			setStatus("Paused");
    		}
    	}
    	function loadNext(onDemand) {
    		if(progress >= sites.length) {
    			setStatus("Complete");
    			document.getElementById("btnStart").value = "Start";
    			return;
    		} 
    		
    		var url = sites[progress];
    		var idx = progress % 2;
    		
    
    			setStatus("Loading " + url);
    		
    		var div = document.getElementById('div' + idx);
    		div.innerHTML = "<a href='" + url + "'>" + url + "</a>";
    
    		var iframe = document.getElementById('frame' + idx);
    		iframe.src = "";
    		iframe.src = url;
    			
    			
    			
    			progress++;
    
    			
    
    		
    		//document.getElementById("scroller").focus();
    		
    		if(!onDemand)
    			objTimeout = window.setTimeout('loadNext()', 1000*getInterval());
    		
    	}
    	function setStatus(message) {
    		document.getElementById('lblStatus').innerHTML = message;
    	}
    	function getInterval() {
    		return parseInt(document.getElementById('interval').value);
    	}
    	</script>
    	<div style="position:fixed; top: 15px; right: 15px; background-color:#dadadd; border: solid 1px #55555; padding: 5px; ">
    		<div style="text-align:right"><input type="button" id="btnStart" value="Start" onclick="javascript:startSites(this);" />
    		<input type="button" id="btnLoadNext" value="Load Next" onclick="javascript:loadNext(true);"/></div>
    		<div>Interval: <input type="text" id="interval" value="10" style="width:35px"> sec</div>
    		<div>Status: <span id="lblStatus">Idle</span></div>
    	</div>
    	<div>
    	<table id="frames">
    	<tr><td><div id="div0"></div><iframe id="frame0" width="900" height="350" src=""></iframe></td></tr>
    	<tr><td><div id="div1"></div><iframe id="frame1" width="900" height="350" src=""></iframe></td></tr>
    	</table>
    	<input type="text" id="scroller"></div>
    	</div>
    </body>
    </html>
    

     

    Just make sure that you're logged on using an account that has admin (not just contributor) access to all of the pages. 

    Hope this helps.  Thanks to my coworker who put this together. 

    Disclaimer: Use any of this at your own risk, test it first.


    Wednesday, May 18, 2011 7:09 PM

All replies

  • I am seeing the exact same problem and the solution you found is the only one that seems to work.   I created a script to load each page in every site of my farm using my admin account after I do the migration.  So far that seems to be the only solution I have found.

    If you get your question answered, please come back and mark the reply as an answer.  
    If you are helped by an answer to someone else's question, please mark it as helpful.
    Mike Hacker | Blog: http://blog.mikehacker.net 

    Thursday, August 5, 2010 1:08 PM
  • You two aren't alone.  Did either of you find a better solution than to load each page individually? 
    Monday, October 11, 2010 10:34 PM
  • Microsoft has fixed this issue sometime before the August CU (maybe unintentionally since I don't see it listed as a fix anywhere).  I've installed the update and verified that the summary link web part issue goes away.  Note that there is a timer job that must run to complete the upgrade and it doesn't happen immediately after attaching the new database.  It runs within about an hour. 

    At this point it's probably worth applying October CU since it will have that and many other fixes. 

     

    Hope this helps someone.

    Friday, October 29, 2010 2:15 PM
  • I have the same problem in the same context :( anyone can help us?

     

     


    Un saludo Oscar
    Wednesday, May 18, 2011 2:34 PM
  • Microsoft has fixed this issue sometime before the August CU (maybe unintentionally since I don't see it listed as a fix anywhere).  I've installed the update and verified that the summary link web part issue goes away.  Note that there is a timer job that must run to complete the upgrade and it doesn't happen immediately after attaching the new database.  It runs within about an hour. 

    At this point it's probably worth applying October CU since it will have that and many other fixes. 

     

    Hope this helps someone.

    I have installed March´s CU and I reproduce the same error :( The job 1 day ago has ended


    Un saludo Oscar
    Wednesday, May 18, 2011 2:38 PM
  • Mike can you post the script???
    Un saludo Oscar
    Wednesday, May 18, 2011 2:50 PM
  • You're right, the CU I mentioned didn't fix it for our production data either.  It only worked when I did an OOTB site in our Development environment.  We ended up writing a script that found every page that had the Summary Link Web Part and then ran a javascript program to go and open each page, one by one. 

    Here is the powershell script we used to find the sites and create "sitelist.js"

     

    #http://stsadm.blogspot.com/2010/08/getting-inventory-of-all-sharepoint.html
    
    $outfile = "sitelist.js"
    if (Test-Path $outfile) { Remove-Item $outfile }
    "// started at " + (Get-Date) | Out-File $outfile
    
    $logfile = "log.txt"
    if (Test-Path $logfile) { Remove-Item $logfile }
    
    $errorfile = "error.txt"
    if (Test-Path $errorfile) { Remove-Item $errorfile }
    
    "var sites = new Array();" | Out-File $outfile -append
    $siteIdx = 0
    
    [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
    $farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
    
    foreach ($spService in $farm.Services) {
    	if (!($spService -is [Microsoft.SharePoint.Administration.SPWebService])) {
    		continue;
    	}
    
    	foreach ($webApp in $spService.WebApplications) {
    		if ($webApp -is [Microsoft.SharePoint.Administration.SPAdministrationWebApplication]) { continue }
    
    		foreach ($site in $webApp.Sites) {
    
    			foreach ($web in $site.AllWebs) {
        "Searching " + $web.Url
        foreach ($file in $web.Files) {
         if($file) {
          if($file.ServerRelativeUrl.indexof(".aspx") -lt 0) { continue }
          trap [Exception] {
           "Error on page: " + $file.ServerRelativeUrl + ": " + $_.Exception.Message | Out-File $errorfile -Append
           "sites[" + $siteIdx + "] = '" + $webApp.Url + $file.ServerRelativeUrl + "';" | Out-File $outfile -append
           $siteIdx++
           continue
          }
          $wpMgr = $file.GetLimitedWebPartManager("Shared")
          $wpIdx = -1
    						foreach($wp in $wpMgr.WebParts) {
           $wpIdx++
    							trap [Exception] { 
            "Error in web part " + $wpIdx + " on page: " + $file.ServerRelativeUrl + ": " + $_.Exception.Message | Out-File $errorfile -Append
    								$wp = ""
    								continue 
    							}
    							if($wp.WebBrowsableObject.ToString().IndexOf("SummaryLinkWebPart") -gt 1) {
    								"sites[" + $siteIdx + "] = '" + $webApp.Url + $file.ServerRelativeUrl + "';" | Out-File $outfile -append
            				$siteIdx++
    								#$wp.WebBrowsableObject.ToString() | Out-File $outfile -append
    								#$pagefile.tostring() | Out-File $outfile -append
    								#"" | Out-File $outfile -append
    								$wp = ""
    								break
    							}
    						}
         }
        }
        
    				foreach ($list in $web.Lists) {
    					if ($list.BaseType -ne "DocumentLibrary") {
    						continue
    					}
    					foreach ($item in $list.Items) {
    						trap [Exception] { 
           "Error in item: " + $item.DisplayName + ", web: " + $web.Url + ": " + $_.Exception.Message | Out-File $errorfile -Append
    							$pagefile = ""
    							$wpMgt = ""
    							$wp = ""
    							continue 
    						}
    						$pageurl = $web.url + "/" + $item.url
    						if($pageurl.indexof(".aspx") -lt 1) { continue }
    						$pagefile = $web.GetFile($pageurl)
          
    						$wpMgr = $pagefile.GetLimitedWebPartManager("Shared")
          $wpIdx = -1
    						foreach($wp in $wpMgr.WebParts) {
           $wpIdx++
    							trap [Exception] { 
            "Error in web part " + $wpIdx + " on page: " + $pageurl + ": " + $_.Exception.Message | Out-File $errorfile -Append
            "sites[" + $siteIdx + "] = '" + $pageurl + "';" | Out-File $outfile -append
            $siteIdx++
    								$wp = ""
    								continue 
    							}
    							if($wp.WebBrowsableObject.ToString().IndexOf("SummaryLinkWebPart") -gt 1) {
    								"sites[" + $siteIdx + "] = '" + $pageurl + "';" | Out-File $outfile -append
            				$siteIdx++
    								#$wp.WebBrowsableObject.ToString() | Out-File $outfile -append
    								#$pagefile.tostring() | Out-File $outfile -append
    								#"" | Out-File $outfile -append
    								$wp = ""
    								break
    							}
    						}
    					}
    				}
    				$web.Dispose();
    			}
    			$site.Dispose()
    		}
    	}
    }
    
    "// finished at " + (Get-Date) | Out-File $outfile -Append
    

     

    Then here is the HTML for the page that will load each site from your list one by one.

     

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Strict//EN">
    <html>
    <head><title>Starting sites...</title></head>
    <body>
    	<style>
    	BODY {
    		font: normal 10pt Arial, Sans-serif;
    	}
    	</style>
    	<script language="javascript" src="sitelist.js"></script>
    	<script language="javascript">
    	var INTERVAL_LENGTH = 30;
    	
    	var objTimeout = null;
    	var progress = 0;
    	
    	function startSites(sender) {
    		if(sender.value == "Start") {
    			sender.value = "Pause";
    			loadNext();
    		} else {
    			window.clearTimeout(objTimeout);
    			sender.value = "Start";
    			setStatus("Paused");
    		}
    	}
    	function loadNext(onDemand) {
    		if(progress >= sites.length) {
    			setStatus("Complete");
    			document.getElementById("btnStart").value = "Start";
    			return;
    		} 
    		
    		var url = sites[progress];
    		var idx = progress % 2;
    		
    
    			setStatus("Loading " + url);
    		
    		var div = document.getElementById('div' + idx);
    		div.innerHTML = "<a href='" + url + "'>" + url + "</a>";
    
    		var iframe = document.getElementById('frame' + idx);
    		iframe.src = "";
    		iframe.src = url;
    			
    			
    			
    			progress++;
    
    			
    
    		
    		//document.getElementById("scroller").focus();
    		
    		if(!onDemand)
    			objTimeout = window.setTimeout('loadNext()', 1000*getInterval());
    		
    	}
    	function setStatus(message) {
    		document.getElementById('lblStatus').innerHTML = message;
    	}
    	function getInterval() {
    		return parseInt(document.getElementById('interval').value);
    	}
    	</script>
    	<div style="position:fixed; top: 15px; right: 15px; background-color:#dadadd; border: solid 1px #55555; padding: 5px; ">
    		<div style="text-align:right"><input type="button" id="btnStart" value="Start" onclick="javascript:startSites(this);" />
    		<input type="button" id="btnLoadNext" value="Load Next" onclick="javascript:loadNext(true);"/></div>
    		<div>Interval: <input type="text" id="interval" value="10" style="width:35px"> sec</div>
    		<div>Status: <span id="lblStatus">Idle</span></div>
    	</div>
    	<div>
    	<table id="frames">
    	<tr><td><div id="div0"></div><iframe id="frame0" width="900" height="350" src=""></iframe></td></tr>
    	<tr><td><div id="div1"></div><iframe id="frame1" width="900" height="350" src=""></iframe></td></tr>
    	</table>
    	<input type="text" id="scroller"></div>
    	</div>
    </body>
    </html>
    

     

    Just make sure that you're logged on using an account that has admin (not just contributor) access to all of the pages. 

    Hope this helps.  Thanks to my coworker who put this together. 

    Disclaimer: Use any of this at your own risk, test it first.


    Wednesday, May 18, 2011 7:09 PM
  • Happy to confirm that this did the trick for us as well. In our case, we were migrating from a staging environment to production where the application had anonymous authentication enabled. In the event that an anonymous user hit the page before an authenticated user, the error would occur. Used this script/HTML after temporarily disabling anonymous and logging is as the farm admin and the issue was resolved.
    Wednesday, March 20, 2013 6:10 PM