GetContentTypeUsages.ps1 error encountered

Jan 15, 2009 at 1:59 PM
Edited Jan 15, 2009 at 3:48 PM
Function GetContentTypeUsageById fails during the inner foreach($Web in $AllWebs) after a few iterations with the following error (line number is plus one because I added a comment line at the top of the script crediting the original author).

An exception was thrown when trying to enumerate the collection: "Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))". At :line:14 char:10 + foreach( <<<< $Web in $AllWebs)

I'm going to run this again in the PowerGUI Script Editor (version 1.5.3.593) so I can examine the value of $AllWebs to see which entry in the collection is causing the error and try to suggest a correction.

# List SharePoint sites and other corresponding information

Set-Alias -Name stsadm -Value $env:CommonProgramFiles'\Microsoft Shared\Web Server Extensions\12\BIN\STSADM.EXE'
Set-Variable -Name DEFAULT_SITE -Value 'http://workflow2/sites/main' -Option constant
$rawdata = stsadm -o enumsites -url $DEFAULT_SITE
$sitesxml
= [XML] $rawdata
$sitesxml.sites.site | Format-Table url,owner,storageusedmb -AutoSize

 

My environment:

Windows Server 2003 R2 Enterprise Edition with all available service packs and security updates (through 2009-01-14) applied.

SharePoint (MOSS) 2007 Enterprise Edition with all service packs and subsequent updates applied.

SQL Server 2005 Enterprise Edition with Service Pack 3

This is my development box for workflow development, so I have full rights to it, but I don't login as Administrator.  I have run many of my own PowerShell scripts like the following with no errors, so I hope we can find and correct the flaw in GetContentTypeUsages so others can benefit.  

 

Update:

Here is the version of function GetContentTypeUsageById that works for me.
There is a lot of "noise" output that helped me debug the issue, so feel free to remove it.

The key to resolving the issue (again, for my specific situation, which may not work for everyone) was to surround the foreach loop that was iterating through the $AllWebs SPWebCollection with an IF test to see if $AllWebs.Count is greater than zero.  Without that extra test, the permissions error will occur on my development server.

function GetContentTypeUsageById([string]$ContentTypeId)

{

          # modified 2009-01-15 by Fred Morrison, Exostar LLC, to work around "Access Denied" error in deepest nested loop.

          [int] $numApps = 0

          [Microsoft.SharePoint.Administration.SPWebApplicationCollection] $Applications = $ContentService.WebApplications

          $numApps = $Applications.Count

          [string] $appName = ''

          Write-Host "There are $numApps WebApplications to iterate."

          [Microsoft.SharePoint.Administration.SPWebApplication] $App = $null

          foreach($App in $Applications)

          {

                    [int] $numSites = $App.Sites.Count

                    [int] $numWebs = 0

                    [string] $TopUrl = ''

                    $appName = $App.Name

                    [Microsoft.SharePoint.SPSite] $TopLevel = $null

                    Write-Host "`tThere are $numSites Sites to iterate in WebApplication with Name $appName."

                    foreach($TopLevel in $App.Sites)

                    {

                              $TopUrl = $TopLevel.Url

                              Write-Host "`t`tExamining TopLevel Url $TopUrl."

                              [Microsoft.SharePoint.SPWebCollection] $AllWebs = $TopLevel.AllWebs

                              $numWebs = $AllWebs.Count

                              Write-Host "`t`tThere are $numWebs Sites to iterate."

                              [Microsoft.SharePoint.SPWeb] $Web = $null

                              if ( $AllWebs.Count -gt 0 )

                              {

                                        [string] $WebTitle = ''

                                        foreach($Web in $AllWebs)                        

                                        {                            

                                                  $WebTitle = $Web.Title

                                                  Write-Host "`t`t`tExamining SPWeb with title of $WebTitle"

                                                  $SPContentTypeId = New-Object Microsoft.SharePoint.SPContentTypeId($ContentTypeId);

                                                  $ContentType = $Web.ContentTypes[$SPContentTypeId];             

                                                  if($ContentType -ne $null)

                                                  {

                                                            ShowUsages $ContentType                                                      

                                                  }

                                                  $Web.Dispose();                                                         

                                        }

                              }

                              $TopLevel.Dispose();

                    }

          }

}

Developer
Jan 15, 2009 at 3:48 PM
Hi,

You need to use an account that have access to the entire site collection like a site collection admin for instance. If you login as local admin and according to your dev environment's configuration, the script should work.

This script is intended to be used by accounts with enough permissions. A usual option is to use SPSecurity.RunWithElevatedPrivileges but it's rather used with components that are embedded into SharePoint.

Best Regards