SharePoint Online: Fix “An error occurred while enumerating through a collection: The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested” in PowerShell
Problem: Error in SharePoint Online CSOM PowerShell script:
“An error occurred while enumerating through a collection: The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested”
Root cause: The error “An error occurred while enumerating through a collection: The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested” typically occurs when you are trying to access an object in a collection before it has been initialized or loaded. Every collection must be explicitly loaded before accessing its members.
The Problematic Script:
This PowerShell script tries to get columns of a content type.
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#parameters
$SiteURL="https://crescent.sharepoint.com/sites/marketing"
$ContentTypeID="0x01002A7A908ACAB0054880702EE263AC762B"
#Get Credentials to connect
$Cred= Get-Credential
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password)
#Get content type
$ContentType = $Ctx.web.ContentTypes.GetById($ContentTypeID)
$Ctx.Load($ContentType)
$Ctx.ExecuteQuery()
If($ContentType -ne $Null)
{
#Get columns from the content type
ForEach($Field in $ContentType.Fields)
{
Write-Host -f Green $Field.Title
}
}
else
{
Write-host "Content Type '$ContentTypeName' doesn't exist!'" -f Yellow
}
Here in the above script, we are trying to get columns from a content type without explicitly loading the fields collection, so it ends up with an error!
The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
At line:24 char:13
+ ForEach($Field in $ContentType.Fields)
+ ~~~~~~
+ CategoryInfo : OperationStopped: (:) [], CollectionNotInitializedException
+ FullyQualifiedErrorId : Microsoft.SharePoint.Client.CollectionNotInitializedException
Solution:
To solve the error, you need to make sure that the collection has been properly initialized and loaded before you try to access it. This can typically be done by calling the appropriate method to load the collection before calling the ExecuteQuery method in SharePoint Online.
Here is the corrected Script, where we loaded the $ContentType.Fields collection and resolved the issue.
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#parameters
$SiteURL="https://crescent.sharepoint.com/sites/marketing"
$ContentTypeID="0x01002A7A908ACAB0054880702EE263AC762B"
#Get Credentials to connect
$Cred= Get-Credential
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password)
#Get content type
$ContentType = $Ctx.web.ContentTypes.GetById($ContentTypeID)
$Ctx.Load($ContentType)
$Ctx.ExecuteQuery()
If($ContentType -ne $Null)
{
#Get Columns from the content type
$Ctx.Load($ContentType.Fields)
$Ctx.ExecuteQuery()
#Get columns from the content type
ForEach($Field in $ContentType.Fields)
{
Write-Host -f Green $Field.Title
}
}
else
{
Write-host "Content Type '$ContentTypeName' doesn't exist!'" -f Yellow
}
Similarly, in PnP PowerShell, we must use the Get-PnPProperty cmdlet to load a collection.
#Parameters
$SiteURL = "https://crescent.sharepoint.com/sites/PMO"
$ListName = "Projects"
$ContentTypeName ="Item"
#Connect to PnP Online
Connect-PnPOnline -Url $SiteURL -Interactive
#Get the List content type
$ContentType = Get-PnPContentType -Identity $ContentTypeName -List $ListName
#Load the "Fields" collection to retrieve All Fields from the Content Type
$ContentTypeFields = Get-PnPProperty -ClientObject $ContentType -Property Fields
#Get Field Title, Internal Name and ID
$ContentTypeFields | Select Title, InternalName, ID
By properly initializing and loading the collection before you access it, you can avoid the “An error occurred while enumerating through a collection” error and successfully retrieve the properties associated with an object in SharePoint Online using PowerShell.
Hi, I experienced the same issue with this script:
#Function to Get Permissions on a particular on List, Folder or List Item
Function Get-PnPPermissions([Microsoft.SharePoint.Client.SecurableObject]$Object)
{
#Determine the type of the object
Switch($Object.TypedObject.ToString())
{
“Microsoft.SharePoint.Client.ListItem”
{
If($Object.FileSystemObjectType -eq “Folder”)
{
$ObjectType = “Folder”
#Get the URL of the Folder
$Folder = Get-PnPProperty -ClientObject $Object -Property Folder
$ObjectTitle = $Object.Folder.Name
$ObjectURL = $(“{0}{1}” -f $Web.Url.Replace($Web.ServerRelativeUrl,”),$Object.Folder.ServerRelativeUrl)
}
Else #File or List Item
{
#Get the URL of the Object
Get-PnPProperty -ClientObject $Object -Property File, ParentList
If($Object.File.Name -ne $Null)
{
$ObjectType = “File”
$ObjectTitle = $Object.File.Name
$ObjectURL = $(“{0}{1}” -f $Web.Url.Replace($Web.ServerRelativeUrl,”),$Object.File.ServerRelativeUrl)
}
else
{
$ObjectType = “List Item”
$ObjectTitle = $Object[“Title”]
#Get the URL of the List Item
$DefaultDisplayFormUrl = Get-PnPProperty -ClientObject $Object.ParentList -Property DefaultDisplayFormUrl
$ObjectURL = $(“{0}{1}?ID={2}” -f $Web.Url.Replace($Web.ServerRelativeUrl,”), $DefaultDisplayFormUrl,$Object.ID)
}
}
}
Default
{
$ObjectType = “List or Library”
$ObjectTitle = $Object.Title
#Get the URL of the List or Library
$RootFolder = Get-PnPProperty -ClientObject $Object -Property RootFolder
$ObjectURL = $(“{0}{1}” -f $Web.Url.Replace($Web.ServerRelativeUrl,”), $RootFolder.ServerRelativeUrl)
}
}
#Get permissions assigned to the object
Get-PnPProperty -ClientObject $Object -Property HasUniqueRoleAssignments, RoleAssignments
#Check if Object has unique permissions
$HasUniquePermissions = $Object.HasUniqueRoleAssignments
#Loop through each permission assigned and extract details
$PermissionCollection = @()
Foreach($RoleAssignment in $Object.RoleAssignments)
{
#Get the Permission Levels assigned and Member
Get-PnPProperty -ClientObject $RoleAssignment -Property RoleDefinitionBindings, Member
#Get the Principal Type: User, SP Group, AD Group
$PermissionType = $RoleAssignment.Member.PrincipalType
#Get the Permission Levels assigned
$PermissionLevels = $RoleAssignment.RoleDefinitionBindings | Select -ExpandProperty Name
#Remove Limited Access
$PermissionLevels = ($PermissionLevels | Where { $_ -ne “Limited Access”}) -join “,”
#Leave Principals with no Permissions
If($PermissionLevels.Length -eq 0) {Continue}
#Get SharePoint group members
If($PermissionType -eq “SharePointGroup”)
{
#Get Group Members
$GroupMembers = Get-PnPGroupMember -Identity $RoleAssignment.Member.LoginName
#Leave Empty Groups
If($GroupMembers.count -eq 0){Continue}
$GroupUsers = ($GroupMembers | Select -ExpandProperty Title) -join “; ”
#Add the Data to Object
$Permissions = New-Object PSObject
$Permissions | Add-Member NoteProperty Object($ObjectType)
$Permissions | Add-Member NoteProperty Title($ObjectTitle)
$Permissions | Add-Member NoteProperty URL($ObjectURL)
$Permissions | Add-Member NoteProperty HasUniquePermissions($HasUniquePermissions)
$Permissions | Add-Member NoteProperty Users($GroupUsers)
$Permissions | Add-Member NoteProperty Type($PermissionType)
$Permissions | Add-Member NoteProperty Permissions($PermissionLevels)
$Permissions | Add-Member NoteProperty GrantedThrough(“SharePoint Group: $($RoleAssignment.Member.LoginName)”)
$PermissionCollection += $Permissions
}
Else
{
#Add the Data to Object
$Permissions = New-Object PSObject
$Permissions | Add-Member NoteProperty Object($ObjectType)
$Permissions | Add-Member NoteProperty Title($ObjectTitle)
$Permissions | Add-Member NoteProperty URL($ObjectURL)
$Permissions | Add-Member NoteProperty HasUniquePermissions($HasUniquePermissions)
$Permissions | Add-Member NoteProperty Users($RoleAssignment.Member.Title)
$Permissions | Add-Member NoteProperty Type($PermissionType)
$Permissions | Add-Member NoteProperty Permissions($PermissionLevels)
$Permissions | Add-Member NoteProperty GrantedThrough(“Direct Permissions”)
$PermissionCollection += $Permissions
}
}
#Export Permissions to CSV File
$PermissionCollection | Export-CSV $ReportFile -NoTypeInformation -Append
}
#Function to get sharepoint online list permissions report
Function Generate-PnPListPermissionRpt()
{
[cmdletbinding()]
Param
(
[Parameter(Mandatory=$false)] [String] $SiteURL,
[Parameter(Mandatory=$false)] [String] $ListName,
[Parameter(Mandatory=$false)] [String] $ReportFile,
[Parameter(Mandatory=$false)] [switch] $ScanItemLevel,
[Parameter(Mandatory=$false)] [switch] $IncludeInheritedPermissions
)
Try {
#Function to Get Permissions of All List Items of a given List
Function Get-PnPListItemsPermission([Microsoft.SharePoint.Client.List]$List)
{
Write-host -f Yellow “`t `t Getting Permissions of List Items in the List:”$List.Title
#Get All Items from List in batches
$ListItems = Get-PnPListItem -List $List -PageSize 500
$ItemCounter = 0
#Loop through each List item
ForEach($ListItem in $ListItems)
{
#Get Objects with Unique Permissions or Inherited Permissions based on ‘IncludeInheritedPermissions’ switch
If($IncludeInheritedPermissions)
{
Get-PnPPermissions -Object $ListItem
}
Else
{
#Check if List Item has unique permissions
$HasUniquePermissions = Get-PnPProperty -ClientObject $ListItem -Property HasUniqueRoleAssignments
If($HasUniquePermissions -eq $True)
{
#Call the function to generate Permission report
Get-PnPPermissions -Object $ListItem
}
}
$ItemCounter++
Write-Progress -PercentComplete ($ItemCounter / ($List.ItemCount) * 100) -Activity “Processing Items $ItemCounter of $($List.ItemCount)” -Status “Searching Unique Permissions in List Items of ‘$($List.Title)'”
}
}
#Get the List
$List = Get-PnpList -Identity $ListName -Includes RoleAssignments
Write-host -f Yellow “Getting Permissions of the List ‘$ListName’…”
#Get List Permissions
Get-PnPPermissions -Object $List
#Get Item Level Permissions if ‘ScanItemLevel’ switch present
If($ScanItemLevel)
{
#Get List Items Permissions
Get-PnPListItemsPermission -List $List
}
Write-host -f Green “`t List Permission Report Generated Successfully!”
}
Catch {
write-host -f Red “Error Generating List Permission Report!” $_.Exception.Message
}
}
#region ***Parameters***
$SiteURL=”https://xxx”
$ListName = “Documents”
$ReportFile=”C:\Temp\ListPermissionRpt.csv”
#endregion
#Remove the Output report if exists
If (Test-Path $ReportFile) { Remove-Item $ReportFile }
#Connect to the Site
Connect-PnPOnline -URL $SiteURL -Interactive
#Get the Web
$Web = Get-PnPWeb
#Call the function to generate list permission report
#Generate-PnPListPermissionRpt -SiteURL $SiteURL -ListName $ListName -ReportFile $ReportFile -ScanItemLevel
Generate-PnPListPermissionRpt -SiteURL $SiteURL -ListName $ListName -ReportFile $ReportFile -ScanItemLevel -IncludeInheritedPermissions
Any idea, please ?