SharePoint Detailed Permission Report using PnP PowerShell

Introduction

Microsoft 365 does not provide a built-in report to extract complete permission details across SharePoint (site, libraries, folders, files, and items) in a single view.
To achieve this, a custom PnP PowerShell script is used to generate a detailed permission report.

Purpose

This solution helps to:

  • Identify who has access to what
  • Detect unique permissions (broken inheritance)
  • Expand SharePoint group members into individual users
  • Support security audits and access reviews

When This is Required

Use this approach when:

  • Performing security or audit reviews
  • Investigating unauthorized access
  • Validating data access across files/folders
  • Preparing compliance reports

What the Report Includes

  • Site, Library, Folder, File, and Item-level permissions
  • User details (Name, UPN, Email)
  • Permission levels (Read, Contribute, Full Control)
  • Direct vs Group-based access

Prerequisites

1. Required PowerShell Modules

Install the PnP PowerShell module:

PowerShell

Install-Module -Name PnP.PowerShell -Scope CurrentUser
Show more lines

Verify installation:

PowerShell

Get-Module PnP.PowerShell -ListAvailable
Show more lines

2. Required Permissions (Very Important)

To successfully extract full permission details, the account must have:

  • Site Collection Administrator (Best option)

Minimum Required

  • Full Control on the target SharePoint site
  • Ability to:
    • Read permissions
    • Access all lists and libraries
    • View items (including restricted content)

3. Admin Role Requirements

Depending on scope:

For Single Site Reports

  • Site Collection Admin is sufficient

For Multiple Sites / Tenant-Level Execution

  • SharePoint Administrator role required

4. Authentication Method

Use modern authentication:

PowerShell

Connect-PnPOnline -Url “<SiteURL>” -Interactive
Show more lines

5. Environment Requirements

  • Windows machine or server
  • PowerShell 5.1 or PowerShell 7+
  • Internet access to Microsoft 365

6. Access Considerations

  • Script will only return data based on access level
  • If permissions are missing:
    • Some users/groups may not appear
    • Some items may be skipped

PowerShell Script

Update the $SiteURL before running

# Create Output Folder

New-Item -ItemType Directory -Force -Path “C:\Temp”

# Site URL

$SiteURL = “https://yourtenant.sharepoint.com/sites/yoursite”

# Output File

$ReportOutput = “C:\Temp\SharePoint_Permission_Report.csv”

# Connect to SharePoint

Connect-PnPOnline -Url $SiteURL -Interactive

# Report Array

$PermissionData = New-Object System.Collections.ArrayList

Function Get-PermissionDetails {

    param ($Object, $ObjectType, $ObjectTitle, $ObjectURL)

    Get-PnPProperty -ClientObject $Object -Property HasUniqueRoleAssignments, RoleAssignments

    if (-not $Object.HasUniqueRoleAssignments) { return }

    foreach ($RoleAssignment in $Object.RoleAssignments) {

        Get-PnPProperty -ClientObject $RoleAssignment -Property RoleDefinitionBindings, Member

        $PermissionLevels = (

            $RoleAssignment.RoleDefinitionBindings |

            Select-Object -ExpandProperty Name |

            Where-Object { $_ -ne “Limited Access” }

        ) -join “, “

        if ([string]::IsNullOrEmpty($PermissionLevels)) { continue }

        $Member = $RoleAssignment.Member

        if ($Member.PrincipalType -eq “SharePointGroup”) {

            $Users = Get-PnPGroupMembers -Identity $Member.Title

            foreach ($User in $Users) {

                if ($User.Title -eq “System Account”) { continue }

                $PermissionData.Add([PSCustomObject]@{

                    ObjectType  = $ObjectType

                    ObjectTitle = $ObjectTitle

                    ObjectURL   = $ObjectURL

                    GroupName   = $Member.Title

                    UserName    = $User.Title

                    UserUPN     = $User.LoginName

                    Email       = $User.Email

                    Permissions = $PermissionLevels

                }) | Out-Null

            }

        }

        else {

            if ($Member.Title -ne “System Account”) {

                $PermissionData.Add([PSCustomObject]@{

                    ObjectType  = $ObjectType

                    ObjectTitle = $ObjectTitle

                    ObjectURL   = $ObjectURL

                    GroupName   = “Direct”

                    UserName    = $Member.Title

                    UserUPN     = $Member.LoginName

                    Email       = $Member.Email

                    Permissions = $PermissionLevels

                }) | Out-Null

            }

        }

    }

}

$Web = Get-PnPWeb

# Site Level

Get-PermissionDetails $Web “Site” $Web.Title $Web.Url

# Lists & Libraries

$Lists = Get-PnPList | Where-Object { $_.Hidden -eq $false }

foreach ($List in $Lists) {

    Get-PermissionDetails $List “Library” $List.Title $List.RootFolder.ServerRelativeUrl

    $Items = Get-PnPListItem -List $List.Title -PageSize 500

    foreach ($Item in $Items) {

        if ($Item.FileSystemObjectType -eq “File”) {

            Get-PermissionDetails $Item “File” $Item.FieldValues.FileLeafRef $Item.FieldValues.FileRef

        }

        elseif ($Item.FileSystemObjectType -eq “Folder”) {

            Get-PermissionDetails $Item “Folder” $Item.FieldValues.FileLeafRef $Item.FieldValues.FileRef

        }

    }

}

# Export Report

$PermissionData |

Sort-Object ObjectURL, UserUPN -Unique |

Export-Csv -Path $ReportOutput -NoTypeInformation -Encoding UTF8

Write-Host “Report Generated: $ReportOutput”

Output

  • CSV file with full permission breakdown
  • Can be used for audit, investigation, or review

Summary

This script provides a complete permission visibility solution for SharePoint, which is not available natively in Microsoft 365, enabling better security, governance, and compliance control.

Previous Article

How to Configure Google Drive Migration to Microsoft 365 Using Migration Manager

Send this to a friend