SharePoint Online: Site Collection Permissions Report using PowerShell
Requirement: Generate permissions report for a SharePoint Online site collection.
SharePoint Online: Site Collection Permissions Report using PowerShell
Output Report of the script:
The above script generates a CSV file in the provided ReportFile parameter. Here is a sample report generated.
If you are looking for permission report for a specific user, use my another script: SharePoint Online: User Permissions Report using PowerShell
Update: SharePoint Online Site Permission Report V2
How about extending the script to expand SharePoint Groups (instead of just group name, have all members of the group) and introduce switches for Recursively process all sub-sites, Scan up to Item level permissions and export all permissions including the one with inheriting permissions from its parent? Here is the SharePoint Online PowerShell to get all user permissions:
SharePoint Online: Site Collection Permissions Report using PowerShell
Have you ever wanted to get SharePoint Online Site and subsites permissions using PowerShell? Well, This PowerShell script generates permission report on all objects which has unique permissions on the given site collection. It scans through following securables:
- Site collection administrators group
- Given site collection and sub-sites with unique permissions
- All lists and libraries with unique permissions
- All list items (and folders) with unique permissions.
#sharepoint online powershell permissions report 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" #To call a non-generic method Load Function Invoke-LoadMethod() { param( [Microsoft.SharePoint.Client.ClientObject]$Object = $(throw "Please provide a Client Object"), [string]$PropertyName ) $ctx = $Object.Context $load = [Microsoft.SharePoint.Client.ClientContext].GetMethod("Load") $type = $Object.GetType() $clientLoad = $load.MakeGenericMethod($type) $Parameter = [System.Linq.Expressions.Expression]::Parameter(($type), $type.Name) $Expression = [System.Linq.Expressions.Expression]::Lambda([System.Linq.Expressions.Expression]::Convert([System.Linq.Expressions.Expression]::PropertyOrField($Parameter,$PropertyName),[System.Object] ), $($Parameter)) $ExpressionArray = [System.Array]::CreateInstance($Expression.GetType(), 1) $ExpressionArray.SetValue($Expression, 0) $clientLoad.Invoke($ctx,@($Object,$ExpressionArray)) } #Function to Get Permissions Applied on a particular Object, such as: Web, List or Item Function Get-Permissions([Microsoft.SharePoint.Client.SecurableObject]$Object) { #Determine the type of the object Switch($Object.TypedObject.ToString()) { "Microsoft.SharePoint.Client.Web" { $ObjectType = "Site" ; $ObjectURL = $Object.URL } "Microsoft.SharePoint.Client.ListItem" { $ObjectType = "List Item" #Get the URL of the List Item Invoke-LoadMethod -Object $Object.ParentList -PropertyName "DefaultDisplayFormUrl" $Ctx.ExecuteQuery() $DefaultDisplayFormUrl = $Object.ParentList.DefaultDisplayFormUrl $ObjectURL = $("{0}{1}?ID={2}" -f $Ctx.Web.Url.Replace($Ctx.Web.ServerRelativeUrl,''), $DefaultDisplayFormUrl,$Object.ID) } Default { $ObjectType = "List/Library" #Get the URL of the List or Library $Ctx.Load($Object.RootFolder) $Ctx.ExecuteQuery() $ObjectURL = $("{0}{1}" -f $Ctx.Web.Url.Replace($Ctx.Web.ServerRelativeUrl,''), $Object.RootFolder.ServerRelativeUrl) } } #Get permissions assigned to the object $Ctx.Load($Object.RoleAssignments) $Ctx.ExecuteQuery() Foreach($RoleAssignment in $Object.RoleAssignments) { $Ctx.Load($RoleAssignment.Member) $Ctx.executeQuery() #Get the Permissions on the given object [email protected]() $Ctx.Load($RoleAssignment.RoleDefinitionBindings) $Ctx.ExecuteQuery() Foreach ($RoleDefinition in $RoleAssignment.RoleDefinitionBindings) { $Permissions += $RoleDefinition.Name +";" } #Check direct permissions if($RoleAssignment.Member.PrincipalType -eq "User") { #Send the Data to Report file "$($ObjectURL) `t $($ObjectType) `t $($Object.Title)`t $($RoleAssignment.Member.LoginName) `t User `t $($Permissions)" | Out-File $ReportFile -Append } ElseIf($RoleAssignment.Member.PrincipalType -eq "SharePointGroup") { #Send the Data to Report file "$($ObjectURL) `t $($ObjectType) `t $($Object.Title)`t $($RoleAssignment.Member.LoginName) `t SharePoint Group `t $($Permissions)" | Out-File $ReportFile -Append } ElseIf($RoleAssignment.Member.PrincipalType -eq "SecurityGroup") { #Send the Data to Report file "$($ObjectURL) `t $($ObjectType) `t $($Object.Title)`t $($RoleAssignment.Member.Title)`t $($Permissions) `t Security Group" | Out-File $ReportFile -Append } } } #powershell to get sharepoint online site permissions Function Generate-SPOSitePermissionRpt($SiteURL,$ReportFile) { Try { #Get Credentials to connect $Cred= Get-Credential $Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password) #Setup the context $Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL) $Ctx.Credentials = $Credentials #Get the Web $Web = $Ctx.Web $Ctx.Load($Web) $Ctx.ExecuteQuery() #Write CSV- TAB Separated File) Header "URL `t Object `t Title `t Account `t PermissionType `t Permissions" | out-file $ReportFile Write-host -f Yellow "Getting Site Collection Administrators..." #Get Site Collection Administrators $SiteUsers= $Ctx.Web.SiteUsers $Ctx.Load($SiteUsers) $Ctx.ExecuteQuery() $SiteAdmins = $SiteUsers | Where { $_.IsSiteAdmin -eq $true} ForEach($Admin in $SiteAdmins) { #Send the Data to report file "$($Web.URL) `t Site Collection `t $($Web.Title)`t $($Admin.Title) `t Site Collection Administrator `t Site Collection Administrator" | Out-File $ReportFile -Append } #Function to Get Permissions of All List Items of a given List Function Get-SPOListItemsPermission([Microsoft.SharePoint.Client.List]$List) { Write-host -f Yellow "`t `t Getting Permissions of List Items in the List:"$List.Title $Query = New-Object Microsoft.SharePoint.Client.CamlQuery $Query.ViewXml = "<View Scope='RecursiveAll'><Query><OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy></Query><RowLimit Paged='TRUE'>$BatchSize</RowLimit></View>" $Counter = 0 #Batch process list items - to mitigate list threshold issue on larger lists Do { #Get items from the list $ListItems = $List.GetItems($Query) $Ctx.Load($ListItems) $Ctx.ExecuteQuery() $Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition #Loop through each List item ForEach($ListItem in $ListItems) { Invoke-LoadMethod -Object $ListItem -PropertyName "HasUniqueRoleAssignments" $Ctx.ExecuteQuery() If($ListItem.HasUniqueRoleAssignments -eq $True) { #Call the function to generate Permission report Get-Permissions -Object $ListItem } $Counter++ Write-Progress -PercentComplete ($Counter / ($List.ItemCount) * 100) -Activity "Processing Items $Counter of $($List.ItemCount)" -Status "Searching Unique Permissions in List Items of '$($List.Title)'" } } While ($Query.ListItemCollectionPosition -ne $null) } #Function to Get Permissions of all lists from the web Function Get-SPOListPermission([Microsoft.SharePoint.Client.Web]$Web) { #Get All Lists from the web $Lists = $Web.Lists $Ctx.Load($Lists) $Ctx.ExecuteQuery() #Get all lists from the web ForEach($List in $Lists) { #Exclude System Lists If($List.Hidden -eq $False) { #Get List Items Permissions Get-SPOListItemsPermission $List #Get the Lists with Unique permission Invoke-LoadMethod -Object $List -PropertyName "HasUniqueRoleAssignments" $Ctx.ExecuteQuery() If( $List.HasUniqueRoleAssignments -eq $True) { #Call the function to check permissions Get-Permissions -Object $List } } } } #Function to Get Webs's Permissions from given URL Function Get-SPOWebPermission([Microsoft.SharePoint.Client.Web]$Web) { #Get all immediate subsites of the site $Ctx.Load($web.Webs) $Ctx.executeQuery() #Call the function to Get Lists of the web Write-host -f Yellow "Getting the Permissions of Web "$Web.URL"..." #Check if the Web has unique permissions Invoke-LoadMethod -Object $Web -PropertyName "HasUniqueRoleAssignments" $Ctx.ExecuteQuery() #Get the Web's Permissions If($web.HasUniqueRoleAssignments -eq $true) { Get-Permissions -Object $Web } #Scan Lists with Unique Permissions Write-host -f Yellow "`t Getting the Permissions of Lists and Libraries in "$Web.URL"..." Get-SPOListPermission($Web) #Iterate through each subsite in the current web Foreach ($Subweb in $web.Webs) { #Call the function recursively Get-SPOWebPermission($SubWeb) } } #Call the function with RootWeb to get site collection permissions Get-SPOWebPermission $Web Write-host -f Green "Site Permission Report Generated Successfully!" } Catch { write-host -f Red "Error Generating Site Permission Report!" $_.Exception.Message } } #Set parameter values $SiteURL="https://crescent.sharepoint.com" $ReportFile="C:\Temp\SitePermissionRpt.csv" $BatchSize = 500 #Call the function Generate-SPOSitePermissionRpt -SiteURL $SiteURL -ReportFile $ReportFile
Output Report of the script:
The above script generates a CSV file in the provided ReportFile parameter. Here is a sample report generated.
If you are looking for permission report for a specific user, use my another script: SharePoint Online: User Permissions Report using PowerShell
Update: SharePoint Online Site Permission Report V2
How about extending the script to expand SharePoint Groups (instead of just group name, have all members of the group) and introduce switches for Recursively process all sub-sites, Scan up to Item level permissions and export all permissions including the one with inheriting permissions from its parent? Here is the SharePoint Online PowerShell to get all user permissions:
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" #Function to call a non-generic method Load Function Invoke-LoadMethod([Microsoft.SharePoint.Client.ClientObject]$Object = $(throw "Please provide a Client Object"),[string]$PropertyName) { $Ctx = $Object.Context $Load = [Microsoft.SharePoint.Client.ClientContext].GetMethod("Load") $Type = $Object.GetType() $ClientLoad = $load.MakeGenericMethod($type) $Parameter = [System.Linq.Expressions.Expression]::Parameter(($type), $type.Name) $Expression = [System.Linq.Expressions.Expression]::Lambda([System.Linq.Expressions.Expression]::Convert([System.Linq.Expressions.Expression]::PropertyOrField($Parameter,$PropertyName),[System.Object] ), $($Parameter)) $ExpressionArray = [System.Array]::CreateInstance($Expression.GetType(), 1) $ExpressionArray.SetValue($Expression, 0) $ClientLoad.Invoke($ctx,@($Object,$ExpressionArray)) } #Function to Get Permissions Applied on a particular Object, such as: Web or List Function Get-Permissions([Microsoft.SharePoint.Client.SecurableObject]$Object) { #Determine the type of the object Switch($Object.TypedObject.ToString()) { "Microsoft.SharePoint.Client.Web" { $ObjectType = "Site" ; $ObjectURL = $Object.URL; $ObjectTitle = $Object.Title } "Microsoft.SharePoint.Client.ListItem" { If($Object.FileSystemObjectType -eq "Folder") { $ObjectType = "Folder" #Get the URL of the Folder Invoke-LoadMethod -Object $Object -PropertyName "Folder" $Ctx.ExecuteQuery() $ObjectTitle = $Object.Folder.Name $ObjectURL = $("{0}{1}" -f $Ctx.Web.Url.Replace($Ctx.Web.ServerRelativeUrl,''),$Object.Folder.ServerRelativeUrl) } Else #File or List Item { #Get the URL of the Object Invoke-LoadMethod -Object $Object -PropertyName "File" $Ctx.ExecuteQuery() If($Object.File.Name -ne $Null) { $ObjectType = "File" $ObjectTitle = $Object.File.Name $ObjectURL = $("{0}{1}" -f $Ctx.Web.Url.Replace($Ctx.Web.ServerRelativeUrl,''),$Object.File.ServerRelativeUrl) } else { $ObjectType = "List Item" $ObjectTitle = $Object["Title"] #Get the URL of the List Item Invoke-LoadMethod -Object $Object.ParentList -PropertyName "DefaultDisplayFormUrl" $Ctx.ExecuteQuery() $DefaultDisplayFormUrl = $Object.ParentList.DefaultDisplayFormUrl $ObjectURL = $("{0}{1}?ID={2}" -f $Ctx.Web.Url.Replace($Ctx.Web.ServerRelativeUrl,''), $DefaultDisplayFormUrl,$Object.ID) } } } Default { $ObjectType = "List or Library" $ObjectTitle = $Object.Title #Get the URL of the List or Library $Ctx.Load($Object.RootFolder) $Ctx.ExecuteQuery() $ObjectURL = $("{0}{1}" -f $Ctx.Web.Url.Replace($Ctx.Web.ServerRelativeUrl,''), $Object.RootFolder.ServerRelativeUrl) } } #Check if Object has unique permissions Invoke-LoadMethod -Object $Object -PropertyName "HasUniqueRoleAssignments" $Ctx.ExecuteQuery() $HasUniquePermissions = $Object.HasUniqueRoleAssignments #Get permissions assigned to the object $RoleAssignments = $Object.RoleAssignments $Ctx.Load($RoleAssignments) $Ctx.ExecuteQuery() #Loop through each permission assigned and extract details $PermissionCollection = @() Foreach($RoleAssignment in $RoleAssignments) { $Ctx.Load($RoleAssignment.Member) $Ctx.executeQuery() #Get the Principal Type: User, SP Group, AD Group $PermissionType = $RoleAssignment.Member.PrincipalType #Get the Permission Levels assigned $Ctx.Load($RoleAssignment.RoleDefinitionBindings) $Ctx.ExecuteQuery() $PermissionLevels = $RoleAssignment.RoleDefinitionBindings | Select -ExpandProperty Name #Remove Limited Access $PermissionLevels = ($PermissionLevels | Where { $_ –ne "Limited Access"}) -join "," If($PermissionLevels.Length -eq 0) {Continue} #Get SharePoint group members If($PermissionType -eq "SharePointGroup") { #Get Group Members $Group = $Ctx.web.SiteGroups.GetByName($RoleAssignment.Member.LoginName) $Ctx.Load($Group) $GroupMembers= $Group.Users $Ctx.Load($GroupMembers) $Ctx.ExecuteQuery() 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 site permissions report Function Generate-SPOSitePermissionRpt() { [cmdletbinding()] Param ( [Parameter(Mandatory=$false)] [String] $SiteURL, [Parameter(Mandatory=$false)] [String] $ReportFile, [Parameter(Mandatory=$false)] [switch] $Recursive, [Parameter(Mandatory=$false)] [switch] $ScanItemLevel, [Parameter(Mandatory=$false)] [switch] $IncludeInheritedPermissions ) Try { #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 the Web & Root Web $Web = $Ctx.Web $RootWeb = $Ctx.Site.RootWeb $Ctx.Load($Web) $Ctx.Load($RootWeb) $Ctx.ExecuteQuery() Write-host -f Yellow "Getting Site Collection Administrators..." #Get Site Collection Administrators $SiteUsers= $RootWeb.SiteUsers $Ctx.Load($SiteUsers) $Ctx.ExecuteQuery() $SiteAdmins = $SiteUsers | Where { $_.IsSiteAdmin -eq $true} $SiteCollectionAdmins = ($SiteAdmins | Select -ExpandProperty Title) -join "," #Add the Data to Object $Permissions = New-Object PSObject $Permissions | Add-Member NoteProperty Object("Site Collection") $Permissions | Add-Member NoteProperty Title($RootWeb.Title) $Permissions | Add-Member NoteProperty URL($RootWeb.URL) $Permissions | Add-Member NoteProperty HasUniquePermissions("TRUE") $Permissions | Add-Member NoteProperty Users($SiteCollectionAdmins) $Permissions | Add-Member NoteProperty Type("Site Collection Administrators") $Permissions | Add-Member NoteProperty Permissions("Site Owner") $Permissions | Add-Member NoteProperty GrantedThrough("Direct Permissions") #Export Permissions to CSV File $Permissions | Export-CSV $ReportFile -NoTypeInformation #Function to Get Permissions of All List Items of a given List Function Get-SPOListItemsPermission([Microsoft.SharePoint.Client.List]$List) { Write-host -f Yellow "`t `t Getting Permissions of List Items in the List:"$List.Title $Query = New-Object Microsoft.SharePoint.Client.CamlQuery $Query.ViewXml = "<View Scope='RecursiveAll'><Query><OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy></Query><RowLimit Paged='TRUE'>$BatchSize</RowLimit></View>" $ItemCounter = 0 #Batch process list items - to mitigate list threshold issue on larger lists Do { #Get items from the list $ListItems = $List.GetItems($Query) $Ctx.Load($ListItems) $Ctx.ExecuteQuery() $Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition #Loop through each List item ForEach($ListItem in $ListItems) { #Get Objects with Unique Permissions or Inherited Permissions based on 'IncludeInheritedPermissions' switch If($IncludeInheritedPermissions) { Get-Permissions -Object $ListItem } Else { Invoke-LoadMethod -Object $ListItem -PropertyName "HasUniqueRoleAssignments" $Ctx.ExecuteQuery() If($ListItem.HasUniqueRoleAssignments -eq $True) { #Call the function to generate Permission report Get-Permissions -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)'" } } While ($Query.ListItemCollectionPosition -ne $null) } #Function to Get Permissions of all lists from the web Function Get-SPOListPermission([Microsoft.SharePoint.Client.Web]$Web) { #Get All Lists from the web $Lists = $Web.Lists $Ctx.Load($Lists) $Ctx.ExecuteQuery() #Exclude system lists $ExcludedLists = @("Access Requests","App Packages","appdata","appfiles","Apps in Testing","Cache Profiles","Composed Looks","Content and Structure Reports","Content type publishing error log","Converted Forms", "Device Channels","Form Templates","fpdatasources","Get started with Apps for Office and SharePoint","List Template Gallery", "Long Running Operation Status","Maintenance Log Library", "Images", "site collection images" ,"Master Docs","Master Page Gallery","MicroFeed","NintexFormXml","Quick Deploy Items","Relationships List","Reusable Content","Reporting Metadata", "Reporting Templates", "Search Config List","Site Assets","Preservation Hold Library" "Site Pages", "Solution Gallery","Style Library","Suggested Content Browser Locations","Theme Gallery", "TaxonomyHiddenList","User Information List","Web Part Gallery","wfpub","wfsvc","Workflow History","Workflow Tasks", "Pages") $Counter = 0 #Get all lists from the web ForEach($List in $Lists) { #Exclude System Lists If($List.Hidden -eq $False -and $ExcludedLists -notcontains $List.Title) { $Counter++ Write-Progress -PercentComplete ($Counter / ($Lists.Count) * 100) -Activity "Processing Lists $Counter of $($Lists.Count) in $($Web.URL)" -Status "Exporting Permissions from List '$($List.Title)'" #Get Item Level Permissions if 'ScanItemLevel' switch present If($ScanItemLevel) { #Get List Items Permissions Get-SPOListItemsPermission -List $List } #Get Lists with Unique Permissions or Inherited Permissions based on 'IncludeInheritedPermissions' switch If($IncludeInheritedPermissions) { Get-Permissions -Object $List } Else { #Check if List has unique permissions Invoke-LoadMethod -Object $List -PropertyName "HasUniqueRoleAssignments" $Ctx.ExecuteQuery() If($List.HasUniqueRoleAssignments -eq $True) { #Call the function to check permissions Get-Permissions -Object $List } } } } } #Function to Get Webs's Permissions from given URL Function Get-SPOWebPermission([Microsoft.SharePoint.Client.Web]$Web) { #Get all immediate subsites of the site $Ctx.Load($web.Webs) $Ctx.executeQuery() #Call the function to Get permissions of the web Write-host -f Yellow "Getting Permissions of the Web: $($Web.URL)..." Get-Permissions -Object $Web #Get List Permissions Write-host -f Yellow "`t Getting Permissions of Lists and Libraries..." Get-SPOListPermission($Web) #Recursively get permissions from all sub-webs based on the "Recursive" Switch If($Recursive) { #Iterate through each subsite in the current web Foreach ($Subweb in $web.Webs) { #Get Webs with Unique Permissions or Inherited Permissions based on 'IncludeInheritedPermissions' switch If($IncludeInheritedPermissions) { Get-SPOWebPermission($Subweb) } Else { #Check if the Web has unique permissions Invoke-LoadMethod -Object $Subweb -PropertyName "HasUniqueRoleAssignments" $Ctx.ExecuteQuery() #Get the Web's Permissions If($Subweb.HasUniqueRoleAssignments -eq $true) { #Call the function recursively Get-SPOWebPermission($Subweb) } } } } } #Call the function with RootWeb to get site collection permissions Get-SPOWebPermission $Web Write-host -f Green "`n*** Site Permission Report Generated Successfully!***" } Catch { write-host -f Red "Error Generating Site Permission Report!" $_.Exception.Message } } #region ***Parameters*** $SiteURL="https://crescent.sharepoint.com/sites/marketing" $ReportFile="C:\Temp\SitePermissionRpt.csv" $BatchSize = 500 #endregion #Call the function to generate permission report Generate-SPOSitePermissionRpt -SiteURL $SiteURL -ReportFile $ReportFile #Generate-SPOSitePermissionRpt -SiteURL $SiteURL -ReportFile $ReportFile -Recursive -ScanItemLevel -IncludeInheritedPermissionsThis script produces output as below! It gets SharePoint Online site and subsites along with its child object permission using PowerShell
I tried your script and it worked like a charm!! Thanks a Million Salaudeen!
ReplyDeleteGetting below error: Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The specified user could not be found."
ReplyDeleteAny thought?
Guess it happens when the user doesn't exist (Orphan Users!).. Let me check if this can be avoided.
Deletehi i have the same error
ReplyDeleteGetting below error: Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The specified user could not be found."
#Read more: http://www.sharepointdiary.com/2018/09/sharepoint-online-site-collection-permission-report-using-powershell.html#ixzz5SlTVyKNr
Script has been updated! Try now.
DeleteThis comment has been removed by the author.
ReplyDeleteThe script does not show a title for the list item
ReplyDeleteHi I am getting below list view threshold error, any ideas please because we have more list in our sites.
ReplyDeleteError Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator."
This is because: You have larger lists with > 5000 List items. The script has been updated to handle larger lists. Try now!
DeleteHi Salaudeen,
ReplyDeleteDid you modify this script?
I'm getting error like,
"Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The sign-in name or password does not match one in the Microsoft account system."
I have entered the correct credentials and I'm a tenant admin for SharePoint online.
Thanks.
I am having the same error and I am using MFA. Where do you "Leave the -Credentials parameter" at?
DeleteYou will need to use your app password for MFA instead of the regular password you use. When you enable the MFA it displays a special app password string you will use for static apps or scripts to use.
DeleteYes, When you have MFA enabled, You have to use App Passwords to authenticate through scripts! Here is how to create an App Password: Manage app passwords for two-step verification
DeleteThank you! This is a great script.
ReplyDeleteThe output for folders and subfolders are written as ../Forms/DispForm.aspx?ID=nnn. Can you include the actual name of the folders and subfolders?
Thank you!
CAn i use this to get permissions for a specifi library?
ReplyDeleteSure.. Here you go: SharePoint Online: PowerShell to Get List Permissions
DeleteSalaudeen, this is great! But I'm still getting issues with lists over 5000 items -- actually, lists over 2000 items. The script seems to stall. Are you sure the list threshold issue is resolved? Do you need to paginate the query?
ReplyDeleteSeeing this error on running. Is there a problem with the function?
ReplyDeletePS C:\users\Victor\Desktop> .\SPO-SiteCollectionPermissionsReport.ps1
At C:\users\Victor\Desktop\SPO-SiteCollectionPermissionsReport.ps1:127 char:48
+ ... ewXml = "2000"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected token 'RecursiveAll">2000"' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
Wrap "RecursiveAll" with 'RecursiveAll' (Replace "" with ')
DeleteThanks for the update. Any idea how to update this further? We have some pretty beefy lists/document library upwards of 5000 items. It seems to stall on bigger ones still.
DeleteThanks but I noticed that this isn't iterating through the sharepoint groups and exporting out the members... can you add that?
ReplyDeleteHey Salaudeen, it seems like this is the only script for that purpose, so thanks for writing it!
ReplyDeleteI tried to run it and was able to successfully output some info like SC admins and permissions of the web, but when it gets to the function for the lists items, it fails with the following error:
Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "Cannot complete this action.
Please try again."
Any ideas where to look?
Could happen in slow connections. Try setting RowLimit from 500 to 100
Deletethanks works really well,
ReplyDeletei seem to get the below error on my larger document libraries, any idea why?
"ExecuteQuery" with "0" argument(s): "The remote server returned an error: (429)
thanks!
Same error as just above for me too.
ReplyDeletei think it has something to do with the list view setting in SP Online, I've ran successfully on a doc library with 4000 files but it failed on one with 9000
DeleteScript has been updated with batch processing and progress bars. Try now!
DeleteThis has helped and working well as is. Thank you!
ReplyDeletethanks for the script! I am running it over one document library where sub-folders have different permissions. is there a way to change column A so that it includes the true path for example it's currently showing
ReplyDeletehttps://hereismy.sharepoint.com/sites/hereismysitename/Documents/Forms/DispForm.aspx?ID=8280
but I would like to show the folder structure instead of the ID:
https://hereismy.sharepoint.com/sites/hereismysitename/Documents/name_of_folder/name_of_subfolder
Also can you please confirm (I think I saw it in your screen shot) that if a user is added direct to the Document Library (not to a sharepoint permission group) that there name will appear on the output. Thank you :)
Thank you for this great script. I'm getting this error if you could help :
ReplyDeleteError Generating User Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The remote server returned an error: (500) Internal Server Error."
I ran a search and found many "ExecuteQuery()". Do i need to put a value in everyone? and what value should they be?
Thank you
Hi, I'm having this error while running the script. Any clues of what might be wrong or where I could look for the problem? Thanks in advance!
ReplyDeleteError Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "Entity (External Content Type) cannot be found with Namespace = 'namespace', Name = 'Role'."
Hi,
ReplyDeleteI have followed the script where we can find SharePoint Groups and their members along with the permissions, but it doesn't give unique users list and their permissions and second , it gives GUIDs instead of names . Can you look into this ?
Thanks
And this doesn't include AD groups too. We are looking for a script where we can find permissions of all groups ( AD and SharePoint both ) and users ( permissions given directly ) for a SharePoint Online site collection . How can this be achieved ?
DeleteError Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The remote server retur
ReplyDeletened an error: (401) Unauthorized."
Add the account that you are using as a owner to the site.
DeleteThanks for a great script!
ReplyDeleteQuestion - is it possible to run this on a specific folder/subfolder in the document library?
You can get permissions of a SharePoint Folder with my another script: SharePoint Online: Get Folder Permissions using PowerShell
DeleteHi, Is it possible to have it show the AzureAD displayName instead of the ObjectID on the Users?
ReplyDeleteHi, thanks for the script. I got below, can you give me some suggestions please?
ReplyDelete---------------------
Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The remote server returned an error: (500) Internal Server Error."
Version 1 Script is taking an exceptionally long time to run. Is this typical? I am analyzing a fairly large site collection. It has been running for over 2 hours now and not sure how close it is to completion. Can PowerShell handle two Progress Meters, The first to show progress over the entire collection and the second show progress as it currently does?
ReplyDeleteThis is excellent stuff. I am concerned however about the execution time. I am analyzing a fairly large site collection and the script has been running for over 2 hours now. Is this typical?
ReplyDeleteAlso, can PowerShell handle 2 Progress Meters, where the first can show progress over the entire collection and the second as you currently have it?
I've tried running this script (the v2 version) on an office 365 site, but it doesn't seem to be working recursively. It lists the permissions of the objects on the site, but not for any folders or files in a document library. Any ideas on what I'm doing wrong?
ReplyDeleteI've tried to do some debugging on this and when i put a break at "foreach ($Subweb in $Web.Webs)" and then look for at $web.webs.count it comes up as 0. The site I'm looking at has a few lists and a document library with some folders with unique permissions, but these are not being interrogated. Also the "If($recursive)" line is only being reached after the permissions of the immediate sites contents are noted. Is this normal?
DeleteAwesome script, thanks a bunch! Saved me sooo much time.
ReplyDeletewill the same script work for 2010?I need to compare source and target
ReplyDeleteThis is written for SharePoint Online! For SharePoint On-premises, use: SharePoint Site Permission Report using PowerShell
DeleteHi Salaudeen, are we able to iterate through subsites and subsites of subsites?
ReplyDeleteHi Tony, Yes! This PowerShell script iterates through all subsites of all levels recursively.
DeleteThanks for writing this script. I am hitting an issue when the script hits an item with unique permissions that appears to be locked down ( even for the SPO Admin)
ReplyDeleteGetting Permissions of List Items in the List: DataFeed
Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(
s): "The remote server returned an error: (401) Unauthorized."
Now 1)I could add the list to the ExludedList but 2)I would prefer to generate a "Unable to read permissions on Item id : nn" and able to gracefully get passed this item.
I have put a breakpoint on the line of code I think is the issue but any advice is welcome.
You must have "Site collection Admin" rights! Add yourself to Site collection admin prior running the script!
DeleteThat is a good question. I believe I am as a member of admins group. it is only a certain listitem ID that seems to trigger the exception. I have Added this to your script to see what is causing the issue If ($ListItem.Id -eq nnnn)
Delete{
Set-PSBreakpoint -Script Generate-SPOSitePermissionsRpt.Ps1 -Line 250
}
Hi Salaudeen, Thanks for the great script. Unfortunately, I am unable to fetch the permissions Recursively get permissions from all sub-webs. Can you please look in to this once and let me know.
ReplyDeleteThe first Script doesn't get objects with Inherited permissions. In V2, include switches -Recursive -IncludeInheritedPermissions.
DeleteHi Salaudeen,
DeleteIs there a way to make this script work with MFA? We are not allowed to use app passwords either. TIA!
Here is how to use MFA in SharePoint Online: How to Connect to SharePoint Online using PowerShell with Multi-factor Authentication (MFA)?
DeleteThank you! I am able to connect to SPO, however not sure how to use it with your above script to pull a detailed permission report. I replaced these two lines in the script:
Delete$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.UserName, $Cred.Password)
with:
$authManager = New-Object OfficeDevPnP.Core.AuthenticationManager
$Ctx = $authManager.GetWebLoginClientContext($SiteURL)
Also added the relevant packages from Nuget. Was very happy when the script ran, but clearly I am not as smart as I thought. 🤦♂️😠the script only outputs the SCAs and the root web permissions - doesn't recurse through subsites/lists/items etc.
Even After using switches in V2 of the script? -Recursive -ScanItemLevel -IncludeInheritedPermissions
DeleteHi. Script gives me this error:
ReplyDeleteError Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The remote server returned an error: (401) Unauthorized."
Any idea why? The user is a member of Sharepoint Administrators
Hi,
ReplyDeleteThanks for writing the script!
I am running v2 script but seem to not be able to report on unique folder and file permissions that sit within a document library. I am only getting reports for the top level of the site. I have tried using the recursive switch amongst others but does not appear to be working.
Do you know how i can get the script to include all files and folders that have unique permissions like it shows in the print screen.
Many Thanks,
Sean
You have to use the -ScanItemLevel switch. You can see the switches and parameters that are available at the very bottom of the script.
DeleteHello,
ReplyDeleteThis script worked great! I was wondering if you had a script that adds the users email address as well?
Use: $GroupUsersEmails = ($GroupMembers | Select -ExpandProperty Email) -join ","
DeleteIs this script supposed to report on subsites when given a site collection? It only works at whatever site is requested and not its sub sites.
ReplyDeleteThis script gets permission only for given web - When you don't use -Recursive switch or when the subsites are inheriting permissions!
DeleteI've run the script 2 times. Once with Recursive and once without. Each time it appears to hang on the same List in a subsite. It was hanging for 3 hours this morning before I cancelled it. I was Not doing ScanItemLevel permissions. Could it be because there are a lot of items in the document library? It says Exporting Permissions from List 'Site Collection Documents' and hangs there.
ReplyDeleteI am getting this error, could you please help:
ReplyDeleteAdd-Type : Cannot bind parameter 'Path' to the target. Exception setting "Path": "Cannot find path 'C:\Program
Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll' because it does
not exist."
At C:\pradeep\SPOsitepermission.ps1:1 char:16
+ ... -Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Serve ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (:) [Add-Type], ParameterBindingException
+ FullyQualifiedErrorId : ParameterBindingFailed,Microsoft.PowerShell.Commands.AddTypeCommand
Add-Type : Cannot bind parameter 'Path' to the target. Exception setting "Path": "Cannot find path 'C:\Program
Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll' because it
does not exist."
At C:\pradeep\SPOsitepermission.ps1:2 char:16
+ ... -Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Serve ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (:) [Add-Type], ParameterBindingException
+ FullyQualifiedErrorId : ParameterBindingFailed,Microsoft.PowerShell.Commands.AddTypeCommand
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
Error Generating Site Permission Report! Cannot find type [Microsoft.SharePoint.Client.ClientContext]: verify that the assembly containing this type is loaded.
Pradeep, You must install SharePoint Online CSOM Assemblies prior running this script. Download and install it from: https://www.microsoft.com/en-us/download/details.aspx?id=42038
DeleteThanks Salaudeen i was having the same problem. You're legend! this stuff is complex for some of us but vital. So thank you for sharing. very kind of you. cheers
DeleteI'm getting a lot of these errors. I'm running using Recursive and scanitemlevel: Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The operation has timed out" and Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The remote server returned an error: (503) Server Unavailable."
ReplyDeletei ended up implementing this http://fangdahai.blogspot.com/2018/02/how-to-handle-429-error-in-powershell.html to get it to run reliably for me.
ReplyDeleteHi Salaudeen, i can't seem to be able to run this for sites, subsites libraries and folders all at once. i'm having to enter each url separately. any ideas?
ReplyDeleteUse -Recursive and -IncludeInheritedPermissions switches. E.g.
DeleteGenerate-SPOSitePermissionRpt -SiteURL $SiteURL -ReportFile $ReportFile -Recursive -IncludeInheritedPermissions
We're getting the below:
ReplyDeleteGetting Site Collection Administrators...
Getting Permissions of the Web: https://XXXXXXXXXXXXXXX.sharepoint.com...
Getting Permissions of Lists and Libraries...
Getting Permissions of List Items in the List: AAAA
Getting Permissions of List Items in the List: BBBB
Getting Permissions of List Items in the List: CCCC
Getting Permissions of List Items in the List: DDDD
Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "The remote server returned an error: (429)."
Tried implementing the fix mentioned above: "i ended up implementing this http://fangdahai.blogspot.com/2018/02/how-to-handle-429-error-in-powershell.html to get it to run reliably for me." - It got further than the previous attempt but the Excel doc is only getting to around 6000 odd lines (just under 5000 odd before the fix was applied).
So I now have the following in PowerShell (where >> indicated added lines)
#Function to Get Permissions Applied on a particular Object, such as: Web or List
Function Get-Permissions([Microsoft.SharePoint.Client.SecurableObject]$Object)
{
#Determine the type of the object
>> for($retryAttempts=0; $retryAttempts -lt $Global:_retryCount; $retryAttempts++){
>> Try{
>> $ctx.ExecuteQuery()
>> break
>> }
>> Catch [system.exception]{
>> Start-Sleep -s $Global:_retryInterval
>> }
>>}
Switch($Object.TypedObject.ToString())
Any ideas? I've now trying by using the following values at the top of the script:
$Global:_retryCount = 10000 (was 1000)
$Global:_retryInterval = 15 (was 10)
As above I tried with these values:
Delete$Global:_retryCount = 10000 (was 1000)
$Global:_retryInterval = 15 (was 10)
It got slightly further, but not that much, started the next list but did not complete and produced the same error message, any ideas?
I had the 429 error. The script would crash out with this error due to what seems to be the number of request for the SharePoint server to handle. I tried above fix, the script went a little bit further but crashed out again. I then added a sleep snippet in the code which seemed to fix the issue. The script took longer to run though:
DeleteCode; (> added new code):
Function Get-Permissions([Microsoft.SharePoint.Client.SecurableObject]$Object)
{
> Start-Sleep -Seconds 1.5
#Determine the type of the object
for($retryAttempts=0; $retryAttempts -lt $Global:_retryCount; $retryAttempts++)
----------
I'm no expert but I believe it helped the SharePoint server deal with the number of request better.
Thanks heaps for this however how do you remove documents being scanned as part of this? I just need to check permissions on folders only so it won't reach the 5000 limit if I am just checking it.
ReplyDeleteI get the following error:
ReplyDeleteGet-PnPPermissions : Cannot process argument transformation on parameter 'Object'. Cannot convert the "Microsoft.SharePoint.Client.ListItem" value of type "Microsoft.SharePoint.Client.ListItem" to
type "Microsoft.SharePoint.Client.SecurableObject".
Hi! Any solution on this?
DeleteTry:
Delete1. Remove the SharePoint CSOM assemblies from GAC (Go to: C:\Windows\Microsoft.NET\assembly\GAC_MSIL, Remove all Folders starting with name: Microsoft.SharePoint*)
2. Restart your machine, and Re-install SharePoint Online PowerShell module using "Install-Module -Name Microsoft.Online.SharePoint.PowerShell"
I keep getting this error unfortunately.
ReplyDeleteError Getting List Permissions! Exception calling "ExecuteQuery" with "0" argument(s): "'center' is an unexpected
token. The expected token is '"' or '''. Line 7, position 12."
Can you add more than one site to the script. I have a location with 60 sites that I need to run permissions for?
ReplyDeletehi, how do i run this to include folders and subfolders?
ReplyDeleteUse the PnP PowerShell script from this article with -ScanFolders switch: SharePoint Online: Permissions Report using PnP PowerShell
Deletehi,
ReplyDeleteinstead of showing the user display name, can we show the user email address?
The script was working before, but I getting the below error
ReplyDeleteGetting Site Collection Administrators...
Getting the Permissions of Web https://xxxx.sharepoint.com/sites/xxxx ...
Getting the Permissions of Lists and Libraries in https://xxxx.sharepoint.com/xxxx ...
Getting Permissions of List Items in the List: Calendar
Getting Permissions of List Items in the List: Documents
Error Generating Site Permission Report! Exception calling "ExecuteQuery" with "0" argument(s): "Exception from HRESULT: 0x80131904"
I'm getting the same.
Delete