SharePoint Online: User Permissions Audit Report for a Site Collection using PnP PowerShell
Requirement: Need a report to audit SharePoint Online site collection permissions.
SharePoint Online: User Permissions report in a Site Collection using PnP PowerShell
SharePoint Online PowerShell Permissions Report
Here is the PnP PowerShell script to generate user permissions report for a SharePoint Online site collection.
Here is the permission report generated by this script:
While the above script serves the purpose, What if you want to include only up to folders but not list items or files in the permission report? In other words, the above script takes a lot of time when dealing with larger lists and libraries when you use -scanitemlevel switch.
PowerShell Script to Generate Permission Report for SharePoint Online Site
How to Generate Report for All Site Collections in the Tenant?
We can just call the function for all sites in the tenant as:
SharePoint Online: User Permissions report in a Site Collection using PnP PowerShell
Auditing SharePoint Online Site permissions is critical for security as misconfigured permissions may enable users to access to data that they should not have access to. So, regular auditing of SharePoint permissions is crucial to minimizing the risk of data leaks and compliance violations. As there are no out of the box ways to generate permissions report, we can utilize PowerShell get list of effective permissions for your SharePoint site collections. This PowerShell script generates
permission report on all objects such as SharePoint Online Site collection and its subsites, lists and libraries, folders and list items 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
Here is the PnP PowerShell script to generate user permissions report for a SharePoint Online site collection.
#Function to Get Permissions Applied on a particular Object, such as: Web, 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.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 $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-PnPGroupMembers -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 site permissions report Function Generate-PnPSitePermissionRpt() { [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 { #Connect to the Site Connect-PnPOnline -URL $SiteURL -UseWebLogin #Get the Web $Web = Get-PnPWeb Write-host -f Yellow "Getting Site Collection Administrators..." #Get Site Collection Administrators $SiteAdmins = Get-PnPSiteCollectionAdmin $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($Web.Title) $Permissions | Add-Member NoteProperty URL($Web.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-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)'" } } #Function to Get Permissions of all lists from the given web Function Get-PnPListPermission([Microsoft.SharePoint.Client.Web]$Web) { #Get All Lists from the web $Lists = Get-PnPProperty -ClientObject $Web -Property Lists #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 "Exporting Permissions from List '$($List.Title)' in $($Web.URL)" -Status "Processing Lists $Counter of $($Lists.Count)" #Get Item Level Permissions if 'ScanItemLevel' switch present If($ScanItemLevel) { #Get List Items Permissions Get-PnPListItemsPermission -List $List } #Get Lists with Unique Permissions or Inherited Permissions based on 'IncludeInheritedPermissions' switch If($IncludeInheritedPermissions) { Get-PnPPermissions -Object $List } Else { #Check if List has unique permissions $HasUniquePermissions = Get-PnPProperty -ClientObject $List -Property HasUniqueRoleAssignments If($HasUniquePermissions -eq $True) { #Call the function to check permissions Get-PnPPermissions -Object $List } } } } } #Function to Get Webs's Permissions from given URL Function Get-PnPWebPermission([Microsoft.SharePoint.Client.Web]$Web) { #Call the function to Get permissions of the web Write-host -f Yellow "Getting Permissions of the Web: $($Web.URL)..." Get-PnPPermissions -Object $Web #Get List Permissions Write-host -f Yellow "`t Getting Permissions of Lists and Libraries..." Get-PnPListPermission($Web) #Recursively get permissions from all sub-webs based on the "Recursive" Switch If($Recursive) { #Get Subwebs of the Web $Subwebs = Get-PnPProperty -ClientObject $Web -Property Webs #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-PnPWebPermission($Subweb) } Else { #Check if the Web has unique permissions $HasUniquePermissions = Get-PnPProperty -ClientObject $SubWeb -Property HasUniqueRoleAssignments #Get the Web's Permissions If($HasUniquePermissions -eq $true) { #Call the function recursively Get-PnPWebPermission($Subweb) } } } } } #Call the function with RootWeb to get site collection permissions Get-PnPWebPermission $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" #endregion #Call the function to generate permission report Generate-PnPSitePermissionRpt -SiteURL $SiteURL -ReportFile $ReportFile -Recursive #Generate-PnPSitePermissionRpt -SiteURL $SiteURL -ReportFile $ReportFile -Recursive -ScanItemLevel -IncludeInheritedPermissions
Here is the permission report generated by this script:
While the above script serves the purpose, What if you want to include only up to folders but not list items or files in the permission report? In other words, the above script takes a lot of time when dealing with larger lists and libraries when you use -scanitemlevel switch.
PowerShell Script to Generate Permission Report for SharePoint Online Site
#Function to Get Permissions Applied on a particular Object, such as: Web, List or Folder Function Get-PnPPermissions([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" { $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) } Default { $ObjectType = $Object.BaseType #List, DocumentLibrary, etc $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 assigned If($PermissionLevels.Length -eq 0) {Continue} #Check if the Principal is SharePoint group If($PermissionType -eq "SharePointGroup") { #Get Group Members $GroupMembers = Get-PnPGroupMembers -Identity $RoleAssignment.Member.LoginName #Leave Empty Groups If($GroupMembers.count -eq 0){Continue} $GroupUsers = ($GroupMembers | Select -ExpandProperty Title | Where { $_ -ne "System Account"}) -join "; " If($GroupUsers.Length -eq 0) {Continue} #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 #User { #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-PnPSitePermissionRpt() { [cmdletbinding()] Param ( [Parameter(Mandatory=$false)] [String] $SiteURL, [Parameter(Mandatory=$false)] [String] $ReportFile, [Parameter(Mandatory=$false)] [switch] $Recursive, [Parameter(Mandatory=$false)] [switch] $ScanFolders, [Parameter(Mandatory=$false)] [switch] $IncludeInheritedPermissions ) Try { #Connect to the Site Connect-PnPOnline -URL $SiteURL -UseWebLogin #Get the Web $Web = Get-PnPWeb Write-host -f Yellow "Getting Site Collection Administrators..." #Get Site Collection Administrators $SiteAdmins = Get-PnPSiteCollectionAdmin $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($Web.Title) $Permissions | Add-Member NoteProperty URL($Web.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 Folders in a given List Function Get-PnPFolderPermission([Microsoft.SharePoint.Client.List]$List) { Write-host -f Yellow "`t `t Getting Permissions of Folders in the List:"$List.Title #Get All Folders from List $ListItems = Get-PnPListItem -List $List -PageSize 2000 $Folders = $ListItems | Where { ($_.FileSystemObjectType -eq "Folder") -and ($_.FieldValues.FileLeafRef -ne "Forms") -and (-Not($_.FieldValues.FileLeafRef.StartsWith("_")))} $ItemCounter = 0 #Loop through each Folder ForEach($Folder in $Folders) { #Get Objects with Unique Permissions or Inherited Permissions based on 'IncludeInheritedPermissions' switch If($IncludeInheritedPermissions) { Get-PnPPermissions -Object $Folder } Else { #Check if Folder has unique permissions $HasUniquePermissions = Get-PnPProperty -ClientObject $Folder -Property HasUniqueRoleAssignments If($HasUniquePermissions -eq $True) { #Call the function to generate Permission report Get-PnPPermissions -Object $Folder } } $ItemCounter++ Write-Progress -PercentComplete ($ItemCounter / ($Folders.Count) * 100) -Activity "Getting Permissions of Folders in List '$($List.Title)'" -Status "Processing Folder '$($Folder.FieldValues.FileLeafRef)' at '$($Folder.FieldValues.FileRef)' ($ItemCounter of $($Folders.Count))" -Id 2 -ParentId 1 } } #Function to Get Permissions of all lists from the given web Function Get-PnPListPermission([Microsoft.SharePoint.Client.Web]$Web) { #Get All Lists from the web $Lists = Get-PnPProperty -ClientObject $Web -Property Lists #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 "Exporting Permissions from List '$($List.Title)' in $($Web.URL)" -Status "Processing Lists $Counter of $($Lists.Count)" -Id 1 #Get Item Level Permissions if 'ScanFolders' switch present If($ScanFolders) { #Get Folder Permissions Get-PnPFolderPermission -List $List } #Get Lists with Unique Permissions or Inherited Permissions based on 'IncludeInheritedPermissions' switch If($IncludeInheritedPermissions) { Get-PnPPermissions -Object $List } Else { #Check if List has unique permissions $HasUniquePermissions = Get-PnPProperty -ClientObject $List -Property HasUniqueRoleAssignments If($HasUniquePermissions -eq $True) { #Call the function to check permissions Get-PnPPermissions -Object $List } } } } } #Function to Get Webs's Permissions from given URL Function Get-PnPWebPermission([Microsoft.SharePoint.Client.Web]$Web) { #Call the function to Get permissions of the web Write-host -f Yellow "Getting Permissions of the Web: $($Web.URL)..." Get-PnPPermissions -Object $Web #Get List Permissions Write-host -f Yellow "`t Getting Permissions of Lists and Libraries..." Get-PnPListPermission($Web) #Recursively get permissions from all sub-webs based on the "Recursive" Switch If($Recursive) { #Get Subwebs of the Web $Subwebs = Get-PnPProperty -ClientObject $Web -Property Webs #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-PnPWebPermission($Subweb) } Else { #Check if the Web has unique permissions $HasUniquePermissions = Get-PnPProperty -ClientObject $SubWeb -Property HasUniqueRoleAssignments #Get the Web's Permissions If($HasUniquePermissions -eq $true) { #Call the function recursively Get-PnPWebPermission($Subweb) } } } } } #Call the function with RootWeb to get site collection permissions Get-PnPWebPermission $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/legal/" $ReportFile="C:\Temp\Legal-SitePermissionRpt.csv" #endregion #Call the function to generate permission report Generate-PnPSitePermissionRpt -SiteURL $SiteURL -ReportFile $ReportFile -ScanFolders #Generate-PnPSitePermissionRpt -SiteURL $SiteURL -ReportFile $ReportFile -Recursive -ScanFolders -IncludeInheritedPermissions
How to Generate Report for All Site Collections in the Tenant?
We can just call the function for all sites in the tenant as:
#Connect to Admin Center $Cred = Get-Credential Connect-PnPOnline -Url $TenantAdminURL -Credentials $Cred #Get All Site collections - Exclude: Seach Center, Mysite Host, App Catalog, Content Type Hub, eDiscovery and Bot Sites $SitesCollections = Get-PnPTenantSite | Where -Property Template -NotIn ("SRCHCEN#0", "SPSMSITEHOST#0", "APPCATALOG#0", "POINTPUBLISHINGHUB#0", "EDISC#0", "STS#-1") #Loop through each site collection ForEach($Site in $SitesCollections) { #Connect to site collection $SiteConn = Connect-PnPOnline -Url $Site.Url -Credentials $Cred Write-host "Generating Report for Site:"$Site.Url #Call the Function for site collection $ReportFile = "C:\Temp\$($Site.URL.Replace('https://','').Replace('/','_')).CSV" Generate-PnPSitePermissionRpt -SiteURL $Site.URL -ReportFile $ReportFile -Recursive Disconnect-PnPOnline -Connection $SiteConn }
I was not able to run script and was getting error saying Get-PnPPermissions not recognized. i added Get-PnPGroupPermissions and it worked. I would like to have email address of users too. is it possible for you to modify in such way ?
ReplyDeleteGet-PnPPermissions is a custom function name defined in the top of this script! You can get user Email address with: $RoleAssignment.Member.LoginName .
Deleteit's really good,thank you!
ReplyDeleteis it possible to dump all permissions report just for the lists/folders? The code is now exporting every file permissions,and making the csv too big to open
This should help you: SharePoint Online: Export Site, List, List Item Permissions to CSV using PowerShell
DeleteSorry that after I could not see any items/folder level permission on csv file, do you know what's wrong with me?
ReplyDeleteThanks for your excellent sharing! But I encounter a problem when I add my site-url value at the end of this method and run this code with the error of ‘Error generating site permission report! Cannot process argument transformation on parameter ‘Web’. Cannot convert the ‘Microsoft.Sharepoint.Client.Web’ value of type ‘Microsoft.Sharepoint.Client.Web’ to type ‘Microsoft.Sharepoint.Client.Web’. What I have done: connect-SPOService, connect-PnPOnline, and load SharePoint CSOM Assemblies. Can you please to tell me how to figure out this error and export the whole permission report successfully? Thanks a lot.
ReplyDeleteTry removing explicit type "[Microsoft.SharePoint.Client.Web]". E.g. Instead of [Microsoft.SharePoint.Client.Web]$Web , Use just: $Web
DeleteI've tried removing [Microsoft.SharePoint.Client.Web] and it failed. Error Generating Site Permission Report! Cannot process argument transformation on parameter 'Object'. Cannot convert the "Microsoft.SharePoint.Client.Web" value of type "Microsoft.SharePoint.Client.Web" to type "Microsoft.SharePoint.Client.SecurableObject". Please help!.
DeleteLooks to me this is due version conflict from CSOM assemblies deployed in GAC! Can you try this: https://www.sharepointdiary.com/2019/02/import-module-could-not-load-type-microsoft-sharepoint-administration-designpackagetype-from-assembly.html
DeleteYou're a legend!
DeleteThank you for great work and sharing the script! I've used your script and adjusted to my needs. The only thing is the speed. If I need to generate a report on a Site Collection with few libraries, which have over 35k files/folders. To run it takes forever. As it have to go through each item/file and check if HasUniqueRoleAssignments=TRUE. Is it any way to speed up this? Any way to get List Items with HasUniqueRoleAssignments True filtered from beginning? Was looking arround on Internet and didn't find any solutions or suggestions. I'm ok to mix it with CSOM if needed, but didn't find how yet.
ReplyDeleteThanks again for your help!
I understand! But unfortunately, we don't have any mechanism to handle this issue as of today!
Deleteand SharePoint Server Object model offers: SPList.GetItemsWithUniquePermission() method which gets you all items with unique permissions from a List instantly! However, this method is not available in CSOM yet.
DeleteThis works perfectly for me needs, thank you so much for sharing your hard work!
ReplyDeleteHi,I am getting this error.
ReplyDeleteError Generating Site Permission Report! Cannot process argument transformation on parameter 'Web'. Cannot convert the
"Microsoft.SharePoint.Client.Web" value of type "Microsoft.SharePoint.Client.Web" to type "Microsoft.SharePoint.Clien
t.Web"
Update your PnP Module: Update-Module SharePointPnPPowerShellOnline
DeleteStill getting same error
DeleteCan you help Error Generating Site Permission Report! Cannot process argument transformation on parameter 'Object'. Cannot convert the "Microsoft.SharePoint.Client.Web" value of type "Microsoft.SharePoint
ReplyDelete.Client.Web" to type "Microsoft.SharePoint.Client.SecurableObject".
Do you have a similar script that work for SharePoint 2016 on-premise?
ReplyDeleteHere you go: SharePoint 2016 Permission Report using PowerShell
DeleteHi,
ReplyDeleteI only seem to be able to report on site permissions. I can not report on unique file and folder permissions which are further down the document library.
Do you know why this is?
Thanks,
Sean
This is an excellent work. Thank you very much
ReplyDeleteExcellent script, thanks very much.
ReplyDeleteI had to make one small change in the second script: $folders = @( $listItems | where... )
I think where there is one item, $folders does not have a "count" property and it fails.
Using @() forces it to be an array
Can I use this script to generate permission for sub-site?
ReplyDeleteGetting the following error: Error Generating Site Permission Report! Cannot process argument transformation on parameter 'Object'. Cannot convert the "Microsoft.SharePoint.Client.Web" value of type "Microsoft.SharePoint.Client.Web" to type "Microsoft.SharePoint.Client.SecurableObject".
ReplyDeleteHave tried updating the module but the error remains
Try restarting the PowerShell ISE or PowerShell console. Otherwise, Remove the [Microsoft.SharePoint.Client.Web] type from the parameter!
DeleteDisregard my previous comment. I followed your instructions for fixing the CSOM assemblies in the GAC and it worked perfectly. This is a superb script and a great site overall. Many thanks!!
ReplyDeleteHow do I capture the email address of the user with permissions too?
ReplyDeleteGetting "The remote server returned an error: (400) Bad Request." with both Get-PnPWeb and Get-PnpSiteCollectionAdmin commands in either script. I've got all the prerequisites installed and working and I've tried it on two different computers. 2FA is enabled. Both successfully login. One is also Azure joined. No dice.
ReplyDeleteThe script worked fine for me.
ReplyDeleteHowever, it's still not displaying the permissions for a lot of documents having unique permissions.
The library itself has unique permissions so it's showing for library level but not for file level.
Please let me know what am I missing.
Use the First script in this article with -ScanItemLevel switch:
DeleteGenerate-PnPSitePermissionRpt -SiteURL $SiteURL -ReportFile $ReportFile -Recursive -ScanItemLevel
Hi, great script. I was able to use the second script and not the first script. The first script would only evaluate sites, no subsites, no lists, or items. It returns 3 rows (1 Site Collection, and two sites of the site collection). The second script seems to work so much better and I was able to make a loop to iterate through the other sites of a Sharepoint.
ReplyDeleteIs there a way to write a function Get-PnPItemsPermissions? The item (docx, excel, etc.) could be in a folder or a list. That would help so much and avoid using the -scanitemlevel switch. Thank you so much for your hard work, I'm here to learn!
Use -ScanFolders switch in the 2nd script to limit searching permissions up to the Folders scope! Otherwise, It runs by scanning Item level permissions.
DeleteHello
ReplyDeleteIs there any way to check who provided the permission using powershell? For example I have one admin group with full permission. This admin group having 4 users, who can add/remove/change users to different group like reader and writer group. I want to track the activities which owner provide add/remove/change the user and how many time user add/removed by particular owner.
I want to do it using PowerShell for SP16 and SPO.
Regards
Avian
Audit Logs/Office 365 Security Audit reports.
DeleteNice script. thanks for sharing!
ReplyDeleteGreat work Salaudeen but I keep getting
ReplyDeleteGet-PnPWeb : The remote server returned an error: (403) Forbidden.
Despite using an account with Sharepoint Admin / Site Owner roles ?
If I run
Connect-PnPOnline -URL $SiteURL -UseWebLogin
I get no errors.
But this line
$Web = Get-PnPWeb
Produces he 403 forbidden
Generally 403 Forbidden error tells us the current user doesn't have permission to the site. SharePoint Admin/Global Admin doesn't get access to the site automatically unless they are added to the site! The Connect-PnPOnline just authorizes your account and the actual authentication occurs when you try to access objects. So, Make sure the account has permissions to sites!
DeleteThere could be other reasons as well: Fix for "The remote server returned an error: (403) Forbidden" in SharePoint Online PowerShell
Is there anyway to have this iterate through all site collections at once? Maybe by using Get-PnPTenantSite? I'm newer to using/modifying these large scripts.
ReplyDeleteArticle updated with the script to generate permissions report for all sites!
DeleteWhen using the last script that iterates through the entire tenant, I am getting the error that "Generate-PnPSitePermissionRpt : The term 'Generate-PnPSitePermissionRpt' is not recognized as the name of a cmdlet,". I have the latest module 3.25.2009.1 (that works at least, supposedly) of SharePointPnPPowerShellOnline. I have done some research looking for this cmdlet or function. Any help is welcomed
DeleteThe "Generate-PnPSitePermissionRpt" function is defined just above the script! You got to copy that as well (Till Line#260)!
DeleteThank you so much for your help. I probably need to copy the top script given the -ScanItemLevel parameter to get granular permissions for the tenant, correct? Line #260 doesn't make since to copy through in the top script, though. I will work my way through this but if you get a chance, I would not mind a second hint. :)
DeleteGreat script, thank you. I've been getting the following error when I run the first script with -Recursive -ScanItemLevel -IncludeInheritedPermissions enabled.
ReplyDeleteThe collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
It doesn't happen every time. I found restarting the PowerShell ISE or breaking it up to process a subset of results helped. There are approximately 9,000 rows in the full report for the site collection. It would appear to be an "out of memory" problem, but it's failed with 4.7 GB of memory available. Any ideas? It I'm using version 3.25.2009.1 of the SharePointPnPPowerShellOnline module.
Follow up: I had more success by putting a delay into the end of the loop in Get-PnPListItemsPermission. This may indicate that the problem is with throttling. However, it does mean the code is slower.
Delete# Pause for 10 seconds after every 20 items are processed
if($ItemCounter % 20 -eq 0)
{
Start-Sleep -Seconds 10
}
Thank you greatly for this script! Is there a way to make use of the "All sites in tenant" part of the script, but add it all to one CSV instead of one-per site collection?
ReplyDeleteYou can use the last script under section "How to Generate Report for All Site Collections in the Tenant?", Replace the $ReportFile variable with a path. E.g. "C:\Reports\PermissionRpt.csv"
DeleteThat seems to just overwrite the report with the most recent collections info. It doesn't append.
DeleteUse -Append switch in Export-CSV cmdlets.
DeleteThat did it. Thanks!
DeleteIs there a way to perform this script on a subsite, for instance: xxxxxx.sharepoint.com/Shared%20Documents/ ? Or even to specify further from there?
ReplyDelete